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.
3759 lines
122 KiB
3759 lines
122 KiB
// Copyright (c) 1996-1999 Microsoft Corporation
|
|
/* helper1.c - helper functions */
|
|
|
|
|
|
|
|
#include "gpdparse.h"
|
|
|
|
|
|
|
|
|
|
|
|
// ---- functions defined in helper1.c ---- //
|
|
|
|
|
|
|
|
PTSTR pwstrGenerateGPDfilename(
|
|
PTSTR ptstrSrcFilename
|
|
) ;
|
|
|
|
#ifndef PARSERDLL
|
|
|
|
PCOMMAND
|
|
CommandPtr(
|
|
IN PGPDDRIVERINFO pGPDDrvInfo,
|
|
IN DWORD UniCmdID
|
|
) ;
|
|
|
|
BOOL
|
|
InitDefaultOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
OUT POPTSELECT poptsel,
|
|
IN INT iMaxOptions,
|
|
IN INT iMode
|
|
) ;
|
|
|
|
BOOL
|
|
SeparateOptionArray(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pCombinedOptions,
|
|
OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN INT iMode
|
|
) ;
|
|
|
|
BOOL
|
|
CombineOptionArray(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
OUT POPTSELECT pCombinedOptions,
|
|
IN INT iMaxOptions,
|
|
IN POPTSELECT pDocOptions,
|
|
IN POPTSELECT pPrinterOptions
|
|
) ;
|
|
|
|
PINFOHEADER
|
|
UpdateBinaryData(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN PINFOHEADER pInfoHdr,
|
|
IN POPTSELECT poptsel
|
|
) ;
|
|
|
|
BOOL
|
|
ReconstructOptionArray(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN PBOOL pbSelectedOptions
|
|
) ;
|
|
|
|
BOOL
|
|
ChangeOptionsViaID(
|
|
IN PINFOHEADER pInfoHdr ,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN DWORD dwFeatureID,
|
|
IN PDEVMODE pDevmode
|
|
) ;
|
|
|
|
BOOL BMapDmColorToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
IN OUT PDWORD pdwOptIndex , // is current setting ok?
|
|
// if not return new index to caller
|
|
DWORD dwDmColor // what is requested in Devmode
|
|
) ;
|
|
|
|
BOOL BMapOptIDtoOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
OUT PDWORD pdwOptIndex , // return index to caller
|
|
DWORD dwFeatureGID,
|
|
DWORD dwOptID
|
|
) ;
|
|
|
|
BOOL BMapPaperDimToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
OUT PDWORD pdwOptIndex , // return index to caller
|
|
DWORD dwWidth, // in Microns
|
|
DWORD dwLength, // in Microns
|
|
OUT PDWORD pdwOptionIndexes
|
|
) ;
|
|
|
|
BOOL BMapResToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
OUT PDWORD pdwOptIndex , // return index to caller
|
|
DWORD dwXres,
|
|
DWORD dwYres
|
|
) ;
|
|
|
|
BOOL BGIDtoFeaIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
PDWORD pdwFeaIndex ,
|
|
DWORD dwFeatureGID ) ;
|
|
|
|
|
|
|
|
DWORD
|
|
MapToDeviceOptIndex(
|
|
IN PINFOHEADER pInfoHdr ,
|
|
IN DWORD dwFeatureID,
|
|
IN LONG lParam1,
|
|
IN LONG lParam2,
|
|
OUT PDWORD pdwOptionIndexes
|
|
) ;
|
|
|
|
|
|
DWORD
|
|
UniMapToDeviceOptIndex(
|
|
IN PINFOHEADER pInfoHdr ,
|
|
IN DWORD dwFeatureID,
|
|
IN LONG lParam1,
|
|
IN LONG lParam2,
|
|
OUT PDWORD pdwOptionIndexes, // used only for GID_PAGESIZE
|
|
IN PDWORD pdwPaperID // optional paperID
|
|
) ;
|
|
|
|
|
|
DWORD MapPaperAttribToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
IN PDWORD pdwPaperID , // optional paperID
|
|
DWORD dwWidth, // in Microns (set to zero to ignore)
|
|
DWORD dwLength, // in Microns
|
|
OUT PDWORD pdwOptionIndexes // cannot be NULL
|
|
) ;
|
|
|
|
|
|
BOOL
|
|
CheckFeatureOptionConflict(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN DWORD dwFeature1,
|
|
IN DWORD dwOption1,
|
|
IN DWORD dwFeature2,
|
|
IN DWORD dwOption2
|
|
) ;
|
|
|
|
BOOL
|
|
ResolveUIConflicts(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN INT iMode
|
|
) ;
|
|
|
|
BOOL
|
|
EnumEnabledOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
OUT PBOOL pbEnabledOptions ,
|
|
IN INT iMode
|
|
) ;
|
|
|
|
|
|
BOOL
|
|
EnumOptionsUnconstrainedByPrinterSticky(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
OUT PBOOL pbEnabledOptions
|
|
) ;
|
|
|
|
|
|
|
|
BOOL
|
|
EnumNewUIConflict(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN PBOOL pbSelectedOptions,
|
|
OUT PCONFLICTPAIR pConflictPair
|
|
) ;
|
|
|
|
BOOL
|
|
EnumNewPickOneUIConflict(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN DWORD dwOptionIndex,
|
|
OUT PCONFLICTPAIR pConflictPair
|
|
) ;
|
|
|
|
BOOL
|
|
BIsFeaOptionCurSelected(
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN DWORD dwOptionIndex
|
|
) ;
|
|
|
|
BOOL
|
|
BSelectivelyEnumEnabledOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN PBOOL pbHonorConstraints, // if non NULL
|
|
// points to array of BOOL corresponding to each feature.
|
|
// if TRUE means constraint involving this feature is
|
|
// to be honored. Otherwise ignore the constraint.
|
|
OUT PBOOL pbEnabledOptions, // assume uninitialized
|
|
// if pConflictPair is NULL else contains current or proposed
|
|
// selections. We will leave this array unchanged in this case.
|
|
IN DWORD dwOptSel, // if pConflictPair exists but pbEnabledOptions
|
|
// is NULL, assume pickone and dwOptSel holds that selection for
|
|
// the feature: dwFeatureIndex.
|
|
OUT PCONFLICTPAIR pConflictPair // if present, pbEnabledOptions
|
|
// actually lists the current selections. Function then
|
|
// exits after encountering the first conflict.
|
|
// if a conflict exists, all fields in pConflictPair
|
|
// will be properly initialized else dwFeatureIndex1 = -1
|
|
// the return value will be TRUE regardless.
|
|
) ;
|
|
|
|
BOOL
|
|
BEnumImposedConstraintsOnFeature
|
|
(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN DWORD dwTgtFeature,
|
|
IN DWORD dwFeature2,
|
|
IN DWORD dwOption2,
|
|
OUT PBOOL pbEnabledOptions,
|
|
OUT PCONFLICTPAIR pConflictPair // if present, pbEnabledOptions
|
|
) ;
|
|
|
|
DWORD DwFindNodeInCurLevel(
|
|
PATTRIB_TREE patt , // start of ATTRIBUTE tree array.
|
|
PATREEREF patr , // index to a level in the attribute tree.
|
|
DWORD dwOption // search current level for this option
|
|
) ;
|
|
|
|
BOOL BIsConstraintActive(
|
|
IN PCONSTRAINTS pcnstr , // root of Constraint nodes
|
|
IN DWORD dwCNode, // first constraint node in list.
|
|
IN PBOOL pbHonorConstraints, // if non NULL
|
|
IN POPTSELECT pOptions,
|
|
OUT PCONFLICTPAIR pConflictPair ) ;
|
|
|
|
#ifdef GMACROS
|
|
|
|
|
|
BOOL
|
|
ResolveDependentSettings(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions
|
|
) ;
|
|
|
|
|
|
void EnumSelectedOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN DWORD dwFeature,
|
|
IN PBOOL pbSelectedOptions) ;
|
|
|
|
BOOL
|
|
ExecuteMacro(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN DWORD dwFea, // what feature was selected in UI
|
|
IN DWORD dwOpt , // what option was selected in UI
|
|
OUT PBOOL pbFeaturesChanged // tell Amanda what Features were changed.
|
|
) ;
|
|
|
|
#endif
|
|
|
|
#endif PARSERDLL
|
|
|
|
|
|
// ------- end function declarations ------- //
|
|
|
|
|
|
|
|
PTSTR pwstrGenerateGPDfilename(
|
|
PTSTR ptstrSrcFilename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Generate a filename for the cached binary GPD data given a GPD filename
|
|
|
|
Arguments:
|
|
|
|
ptstrSrcFilename - Specifies the GPD src filename
|
|
|
|
Return Value:
|
|
|
|
Pointer to BPD filename string, NULL if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PTSTR ptstrBpdFilename, ptstrExtension;
|
|
INT iLength;
|
|
|
|
//
|
|
// If the GPD filename has .GPD extension, replace it with .BUD extension.
|
|
// Otherwise, append .BUD extension at the end.
|
|
//
|
|
|
|
if(!ptstrSrcFilename)
|
|
return NULL ; // will never happen in reality, just to silence PREFIX
|
|
|
|
iLength = _tcslen(ptstrSrcFilename);
|
|
|
|
if ((ptstrExtension = _tcsrchr(ptstrSrcFilename, TEXT('.'))) == NULL ||
|
|
_tcsicmp(ptstrExtension, GPD_FILENAME_EXT) != EQUAL_STRING)
|
|
{
|
|
WARNING(("Bad GPD filename extension: %ws\n", ptstrSrcFilename));
|
|
|
|
ptstrExtension = ptstrSrcFilename + iLength;
|
|
iLength += _tcslen(BUD_FILENAME_EXT);
|
|
}
|
|
|
|
//
|
|
// Allocate memory and compose the BUD filename
|
|
//
|
|
|
|
if (ptstrBpdFilename = MemAlloc((iLength + 1) * sizeof(TCHAR)))
|
|
{
|
|
// _tcscpy(ptstrBpdFilename, ptstrSrcFilename);
|
|
// _tcscpy(ptstrBpdFilename + (ptstrExtension - ptstrSrcFilename),
|
|
// BUD_FILENAME_EXT);
|
|
|
|
StringCchCopy(ptstrBpdFilename, iLength + 1, ptstrSrcFilename) ;
|
|
|
|
StringCchCopy(ptstrBpdFilename + (ptstrExtension - ptstrSrcFilename),
|
|
iLength + 1 - (ptstrExtension - ptstrSrcFilename) ,
|
|
BUD_FILENAME_EXT);
|
|
|
|
|
|
VERBOSE(("BUD filename: %ws\n", ptstrBpdFilename));
|
|
}
|
|
else
|
|
{
|
|
ERR(("Fatal: pwstrGenerateGPDfilename - unable to alloc %d bytes.\n",
|
|
(iLength + 1) * sizeof(TCHAR)));
|
|
}
|
|
|
|
return (ptstrBpdFilename);
|
|
}
|
|
|
|
|
|
#ifndef PARSERDLL
|
|
|
|
|
|
PCOMMAND
|
|
CommandPtr(
|
|
IN PGPDDRIVERINFO pGPDDrvInfo,
|
|
IN DWORD UniCmdID
|
|
)
|
|
{
|
|
return ((((PDWORD)((PBYTE)(pGPDDrvInfo)->pInfoHeader +
|
|
(pGPDDrvInfo)->DataType[DT_COMMANDTABLE].loOffset))
|
|
[(UniCmdID)] == UNUSED_ITEM ) ? NULL :
|
|
(PCOMMAND)((pGPDDrvInfo)->pubResourceData +
|
|
(pGPDDrvInfo)->DataType[DT_COMMANDARRAY].loOffset)
|
|
+ ((PDWORD)((PBYTE)(pGPDDrvInfo)->pInfoHeader +
|
|
(pGPDDrvInfo)->DataType[DT_COMMANDTABLE].loOffset))[(UniCmdID)]);
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitDefaultOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
OUT POPTSELECT poptsel,
|
|
IN INT iMaxOptions,
|
|
IN INT iMode
|
|
)
|
|
{
|
|
INT iOptionsNeeded ;
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
if(iMode != MODE_DOCANDPRINTER_STICKY)
|
|
{
|
|
POPTSELECT pOptions = NULL;
|
|
BOOL bStatus = TRUE ;
|
|
|
|
if(iMode == MODE_DOCUMENT_STICKY)
|
|
iOptionsNeeded = pRawData->dwDocumentFeatures ;
|
|
else // MODE_PRINTER_STICKY
|
|
iOptionsNeeded = pRawData->dwPrinterFeatures ;
|
|
|
|
if(iOptionsNeeded > iMaxOptions)
|
|
return(FALSE);
|
|
|
|
pOptions = (POPTSELECT)MemAlloc(sizeof(OPTSELECT) * MAX_COMBINED_OPTIONS) ;
|
|
if(!poptsel || !pOptions ||
|
|
!BinitDefaultOptionArray(pOptions, (PBYTE)pnRawData))
|
|
{
|
|
bStatus = FALSE;
|
|
}
|
|
|
|
if(!bStatus || !SeparateOptionArray(pnRawData,
|
|
pOptions, // pCombinedOptions,
|
|
poptsel, // dest array
|
|
iMaxOptions, iMode))
|
|
{
|
|
bStatus = FALSE;
|
|
ERR(("InitDefaultOptions: internal failure.\n"));
|
|
}
|
|
|
|
if(pOptions)
|
|
MemFree(pOptions) ;
|
|
|
|
return(bStatus);
|
|
}
|
|
else // MODE_DOCANDPRINTER_STICKY
|
|
{
|
|
iOptionsNeeded = pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures ;
|
|
if(iOptionsNeeded > iMaxOptions)
|
|
return(FALSE);
|
|
|
|
if(!poptsel ||
|
|
!BinitDefaultOptionArray(poptsel, (PBYTE)pnRawData))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SeparateOptionArray(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pCombinedOptions,
|
|
OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN INT iMode
|
|
)
|
|
{
|
|
DWORD dwNumSrcFea, dwNumDestFea, dwStart, dwI, dwDestTail,
|
|
dwDest, dwSrcTail;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
INT iOptionsNeeded;
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
|
|
dwStart = 0 ; // starting src index
|
|
|
|
if(iMode == MODE_DOCUMENT_STICKY)
|
|
{
|
|
dwNumSrcFea = pearTableContents[MTI_DFEATURE_OPTIONS].dwCount ;
|
|
// number of candidates - not same as num of doc sticky features.
|
|
dwNumDestFea = pRawData->dwDocumentFeatures ;
|
|
}
|
|
else // MODE_PRINTER_STICKY
|
|
{
|
|
dwNumSrcFea = pearTableContents[MTI_DFEATURE_OPTIONS].dwCount
|
|
+ pearTableContents[MTI_SYNTHESIZED_FEATURES].dwCount ;
|
|
dwNumDestFea = pRawData->dwPrinterFeatures ;
|
|
}
|
|
|
|
// assume pCombinedOptions large enough to
|
|
// hold all Feature and any pickmany selections.
|
|
|
|
dwDestTail = dwNumDestFea ; // where pickmany selections are stored.
|
|
dwDest = 0 ; // where to store first selection for each feature.
|
|
|
|
// first pass:
|
|
// Just count number of optselect elements needed.
|
|
|
|
iOptionsNeeded = 0 ;
|
|
|
|
for(dwI = dwStart ; dwI < dwStart + dwNumSrcFea ; dwI++)
|
|
{
|
|
DWORD dwNextOpt, dwFeatureType = FT_PRINTERPROPERTY, dwUnresolvedFeature ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
|
|
// is this a printer or doc sticky feature?
|
|
|
|
|
|
patrRoot = &(pfo[dwI].atrFeatureType) ;
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSFeatureTypeIndex,
|
|
(PBYTE)&dwFeatureType,
|
|
&dwUnresolvedFeature, *patrRoot, pCombinedOptions,
|
|
0, // set to any value. Doesn't matter.
|
|
&dwNextOpt) != TRI_SUCCESS)
|
|
{
|
|
ERR(("SeparateOptionArray: EextractValueFromTree failed.\n"));
|
|
return(FALSE) ;
|
|
}
|
|
|
|
|
|
|
|
if(dwI < pearTableContents[MTI_DFEATURE_OPTIONS].dwCount)
|
|
{
|
|
if(dwFeatureType != FT_PRINTERPROPERTY)
|
|
{
|
|
if(iMode == MODE_PRINTER_STICKY)
|
|
continue ;
|
|
}
|
|
else
|
|
{
|
|
if(iMode == MODE_DOCUMENT_STICKY)
|
|
continue ;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// synthesized features are always printer sticky.
|
|
if(iMode == MODE_DOCUMENT_STICKY)
|
|
continue ;
|
|
}
|
|
|
|
iOptionsNeeded++ ;
|
|
dwSrcTail = dwI ;
|
|
|
|
while(dwSrcTail = pCombinedOptions[dwSrcTail].ubNext)
|
|
{
|
|
iOptionsNeeded++ ;
|
|
}
|
|
}
|
|
|
|
if(iOptionsNeeded > iMaxOptions)
|
|
return(FALSE);
|
|
|
|
for(dwI = dwStart ; dwI < dwStart + dwNumSrcFea ; dwI++)
|
|
{
|
|
DWORD dwNextOpt, dwFeatureType, dwUnresolvedFeature ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
|
|
// is this a printer or doc sticky feature?
|
|
|
|
|
|
patrRoot = &(pfo[dwI].atrFeatureType) ;
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSFeatureTypeIndex,
|
|
(PBYTE)&dwFeatureType,
|
|
&dwUnresolvedFeature, *patrRoot, pCombinedOptions,
|
|
0, // set to any value. Doesn't matter.
|
|
&dwNextOpt) != TRI_SUCCESS)
|
|
{
|
|
ERR(("SeparateOptionArray: EextractValueFromTree failed.\n"));
|
|
return(FALSE) ;
|
|
}
|
|
|
|
|
|
|
|
if(dwI < pearTableContents[MTI_DFEATURE_OPTIONS].dwCount)
|
|
{
|
|
if(dwFeatureType != FT_PRINTERPROPERTY)
|
|
{
|
|
if(iMode == MODE_PRINTER_STICKY)
|
|
continue ;
|
|
}
|
|
else
|
|
{
|
|
if(iMode == MODE_DOCUMENT_STICKY)
|
|
continue ;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// synthesized features are always printer sticky.
|
|
if(iMode == MODE_DOCUMENT_STICKY)
|
|
continue ;
|
|
}
|
|
|
|
pOptions[dwDest].ubCurOptIndex = pCombinedOptions[dwI].ubCurOptIndex;
|
|
if(!pCombinedOptions[dwI].ubNext) // end of list
|
|
pOptions[dwDest].ubNext = 0 ;
|
|
else
|
|
{
|
|
dwSrcTail = pCombinedOptions[dwI].ubNext ;
|
|
// this node holds another selection.
|
|
pOptions[dwDest].ubNext = (BYTE)dwDestTail ;
|
|
|
|
while(dwSrcTail)
|
|
{
|
|
pOptions[dwDestTail].ubCurOptIndex =
|
|
pCombinedOptions[dwSrcTail].ubCurOptIndex;
|
|
pOptions[dwDestTail].ubNext = (BYTE)dwDestTail + 1 ;
|
|
dwDestTail++ ;
|
|
dwSrcTail = pCombinedOptions[dwSrcTail].ubNext ;
|
|
}
|
|
pOptions[dwDestTail - 1].ubNext = 0 ;
|
|
}
|
|
dwDest++ ;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CombineOptionArray(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
OUT POPTSELECT pCombinedOptions,
|
|
IN INT iMaxOptions,
|
|
IN POPTSELECT pDocOptions,
|
|
IN POPTSELECT pPrinterOptions
|
|
)
|
|
/* Note:
|
|
|
|
Either pDocOptions or pPrinterOptions could be NULL but not both. If pDocOptions
|
|
is NULL, then in the combined option array, the options for document-sticky
|
|
features will be OPTION_INDEX_ANY. Same is true when pPrinterOptions is NULL.
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
DWORD dwNumSrcFea, dwNumDestFea, dwStart, dwI, dwDestTail,
|
|
dwSrcTail, dwNDoc,
|
|
dwSrcPrnStickyIndex, dwSrcDocStickyIndex ;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
INT iOptionsNeeded;
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
DWORD dwFea, //Feature Index of Locale
|
|
dwOptIndex; // Index of the Option that matches
|
|
// the system locale.
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
|
|
dwStart = 0 ; // starting src index
|
|
|
|
|
|
dwNumDestFea = pRawData->dwDocumentFeatures +
|
|
pRawData->dwPrinterFeatures ;
|
|
|
|
|
|
|
|
// how many option nodes will be used in the combined array?
|
|
|
|
iOptionsNeeded = pRawData->dwDocumentFeatures ;
|
|
if(pDocOptions)
|
|
{
|
|
for(dwI = 0 ; dwI < pRawData->dwDocumentFeatures ; dwI++)
|
|
{
|
|
|
|
dwSrcTail = dwI ;
|
|
|
|
while(dwSrcTail = pDocOptions[dwSrcTail].ubNext)
|
|
{
|
|
iOptionsNeeded++ ;
|
|
}
|
|
}
|
|
}
|
|
iOptionsNeeded += pRawData->dwPrinterFeatures ;
|
|
if(pPrinterOptions)
|
|
{
|
|
for(dwI = 0 ; dwI < pRawData->dwPrinterFeatures ; dwI++)
|
|
{
|
|
|
|
dwSrcTail = dwI ;
|
|
|
|
while(dwSrcTail = pPrinterOptions[dwSrcTail].ubNext)
|
|
{
|
|
iOptionsNeeded++ ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(iOptionsNeeded > iMaxOptions)
|
|
return(FALSE);
|
|
|
|
dwDestTail = dwNumDestFea ; // start of pickmany selections
|
|
|
|
dwSrcPrnStickyIndex = dwSrcDocStickyIndex = 0 ;
|
|
// where to start reading from as we interleave the
|
|
// two sources to form the combined array.
|
|
|
|
for(dwI = 0 ; dwI < pearTableContents[MTI_DFEATURE_OPTIONS].dwCount +
|
|
pearTableContents[MTI_SYNTHESIZED_FEATURES].dwCount ;
|
|
dwI++)
|
|
{
|
|
DWORD dwNextOpt, dwFeatureType, dwUnresolvedFeature ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
POPTSELECT pSrcOptions ;
|
|
PDWORD pdwSrcIndex ;
|
|
|
|
|
|
// assume printer sticky until proven otherwise.
|
|
|
|
pSrcOptions = pPrinterOptions ; // may be null.
|
|
pdwSrcIndex = &dwSrcPrnStickyIndex ;
|
|
|
|
|
|
if(dwI < pearTableContents[MTI_DFEATURE_OPTIONS].dwCount)
|
|
{
|
|
// GPD defined features may be Doc or Printer sticky.
|
|
|
|
patrRoot = &(pfo[dwI].atrFeatureType) ;
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
|
|
// note we give EextractValueFromTree a ptr to
|
|
// an uninitialized option array pCombinedOptions just
|
|
// in case it has the urge to access an option array.
|
|
// I point out that FeatureType is not multi-valued.
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSFeatureTypeIndex,
|
|
(PBYTE)&dwFeatureType,
|
|
&dwUnresolvedFeature, *patrRoot, pCombinedOptions,
|
|
0, // set to any value. Doesn't matter.
|
|
&dwNextOpt) != TRI_SUCCESS)
|
|
{
|
|
ERR(("CombineOptionArray: EextractValueFromTree failed.\n"));
|
|
return(FALSE) ;
|
|
}
|
|
|
|
if(dwFeatureType != FT_PRINTERPROPERTY)
|
|
{
|
|
pSrcOptions = pDocOptions ;
|
|
pdwSrcIndex = &dwSrcDocStickyIndex ;
|
|
}
|
|
}
|
|
|
|
|
|
if(!pSrcOptions) // no option array supplied.
|
|
{
|
|
pCombinedOptions[dwI].ubCurOptIndex = OPTION_INDEX_ANY ;
|
|
pCombinedOptions[dwI].ubNext = 0 ; // eol
|
|
}
|
|
else
|
|
{
|
|
dwSrcTail = *pdwSrcIndex ;
|
|
|
|
pCombinedOptions[dwI].ubCurOptIndex =
|
|
pSrcOptions[*pdwSrcIndex].ubCurOptIndex ;
|
|
if(pSrcOptions[*pdwSrcIndex].ubNext)
|
|
{
|
|
pCombinedOptions[dwI].ubNext = (BYTE)dwDestTail ;
|
|
|
|
while(dwSrcTail = pSrcOptions[dwSrcTail].ubNext)
|
|
{
|
|
pCombinedOptions[dwDestTail].ubCurOptIndex =
|
|
pSrcOptions[dwSrcTail].ubCurOptIndex ;
|
|
pCombinedOptions[dwDestTail].ubNext = (BYTE)dwDestTail + 1;
|
|
dwDestTail++ ;
|
|
}
|
|
pCombinedOptions[dwDestTail - 1].ubNext = 0 ;
|
|
}
|
|
else
|
|
pCombinedOptions[dwI].ubNext = 0 ;
|
|
|
|
(*pdwSrcIndex)++ ;
|
|
}
|
|
}
|
|
|
|
// Special case processing for Locale. If there is a conflict between
|
|
// locale as stored in the registry ( i.e. the printer feature option
|
|
// related registry) and the System Locale, then give importance to
|
|
// the option that matches the system locale.
|
|
|
|
|
|
dwFea = dwOptIndex = (DWORD)-1; // Safety sake initialization.
|
|
if ( !BgetLocFeaOptIndex(pnRawData, &dwFea, &dwOptIndex) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( dwFea == -1 ) //Locale keyword not in gpd. Nothing to do.
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (dwOptIndex == -1) // Find the default option.
|
|
{
|
|
// Here we want to find the default option index.
|
|
// The assumption here is that Locale option is not dependent
|
|
// on any other feature. This is true cos Locale is only system
|
|
// dependent and should not depend on any other feature. But
|
|
// in the long run if some other dependency arises, we may have to
|
|
// change the code.
|
|
ATREEREF atrOptIDNode = pfo[dwFea].atrDefaultOption;
|
|
PBYTE pubHeap = (PBYTE)(pubRaw +
|
|
pearTableContents[MTI_STRINGHEAP]. loOffset) ;
|
|
|
|
if ( atrOptIDNode & ATTRIB_HEAP_VALUE)
|
|
{
|
|
dwOptIndex = *((PDWORD)(pubHeap +
|
|
(atrOptIDNode & ~ATTRIB_HEAP_VALUE))) ;
|
|
}
|
|
else {
|
|
ERR(("Error in processing Default Option for Feature Locale. Continuing....\n"));
|
|
return TRUE; //Dont do any processing.
|
|
}
|
|
// i.e.
|
|
}
|
|
// Could have used ReconstructOptionArray() but prefered to go
|
|
// with the constructs used in this function.
|
|
// Another assumption is that multiple options cannot be selected.
|
|
// Thats why pCombinedOptions[dwFea].ubNext = 0
|
|
pCombinedOptions[dwFea].ubCurOptIndex = (BYTE)dwOptIndex;
|
|
pCombinedOptions[dwFea].ubNext = 0;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
#ifndef KERNEL_MODE
|
|
|
|
PINFOHEADER
|
|
UpdateBinaryData(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN PINFOHEADER pInfoHdr,
|
|
IN POPTSELECT poptsel
|
|
)
|
|
{
|
|
|
|
DWORD dwNumFeatures, loFeatures, dwFea, dwI, dwNumOptions ,
|
|
dwSizeOption ;
|
|
PGPDDRIVERINFO pGPDdriverInfo;
|
|
PUIINFO pUIinfo ;
|
|
PFEATURE pFeaturesDest ;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubRaw, // raw binary data.
|
|
pubOptionsDest , // ptr to any of the several varieties
|
|
pubDestOptionEx ; // of option structures.
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ; // to BUDDATA
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
|
|
dwNumFeatures = pearTableContents[MTI_DFEATURE_OPTIONS].dwCount ;
|
|
dwNumFeatures += pearTableContents[MTI_SYNTHESIZED_FEATURES].dwCount ;
|
|
|
|
/* also works ...
|
|
dwNumFeatures =
|
|
pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures ;
|
|
*/
|
|
|
|
pGPDdriverInfo = (PGPDDRIVERINFO)((PBYTE)(pInfoHdr) +
|
|
pInfoHdr->loDriverOffset) ;
|
|
if(!BinitGlobals(&pGPDdriverInfo->Globals, (PBYTE)pnRawData, poptsel, TRUE) )
|
|
{
|
|
return(NULL) ;
|
|
}
|
|
|
|
pUIinfo = (PUIINFO)((PBYTE)(pInfoHdr) +
|
|
pInfoHdr->loUIInfoOffset) ;
|
|
|
|
if(!BinitUIinfo(pUIinfo, (PBYTE)pnRawData, poptsel, TRUE) )
|
|
{
|
|
return(NULL) ;
|
|
}
|
|
|
|
|
|
loFeatures = pUIinfo->loFeatureList ; // from pInfoHdr
|
|
|
|
pFeaturesDest = (PFEATURE)((PBYTE)(pInfoHdr) + loFeatures) ;
|
|
// always points to first Feature structure in array
|
|
|
|
for( dwFea = 0 ; dwFea < dwNumFeatures ; dwFea++)
|
|
{
|
|
dwSizeOption = (pFeaturesDest + dwFea)->dwOptionSize ;
|
|
dwNumOptions = pFeaturesDest[dwFea].Options.dwCount ;
|
|
pubOptionsDest = (PBYTE)(pInfoHdr) + pFeaturesDest[dwFea].Options.loOffset ;
|
|
|
|
|
|
if(!BinitFeatures(pFeaturesDest + dwFea, pfo + dwFea,
|
|
(PBYTE)pnRawData, poptsel, TRUE))
|
|
{
|
|
return(NULL) ;
|
|
}
|
|
|
|
for(dwI = 0 ; dwI < dwNumOptions ; dwI++)
|
|
{
|
|
if(((POPTION)pubOptionsDest)->loRenderOffset)
|
|
{
|
|
pubDestOptionEx = (PBYTE)(pInfoHdr) +
|
|
((POPTION)pubOptionsDest)->loRenderOffset ;
|
|
}
|
|
else
|
|
pubDestOptionEx = NULL ;
|
|
|
|
if(!BinitOptionFields(pubOptionsDest, pubDestOptionEx,
|
|
(PBYTE)pnRawData, dwFea, dwI, poptsel, pInfoHdr, TRUE) )
|
|
{
|
|
MemFree(pInfoHdr) ;
|
|
return(NULL) ;
|
|
}
|
|
pubOptionsDest += dwSizeOption ;
|
|
}
|
|
}
|
|
|
|
return(pInfoHdr);
|
|
}
|
|
#endif
|
|
|
|
|
|
BOOL
|
|
ReconstructOptionArray(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN PBOOL pbSelectedOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Modify an option array to change the selected options for the specified feature
|
|
|
|
Arguments:
|
|
|
|
pRawData - Points to raw binary printer description data
|
|
pOptions - Points to an array of OPTSELECT structures to be modified
|
|
iMaxOptions - Max number of entries in pOptions array
|
|
dwFeatureIndex - Specifies the index of printer feature in question
|
|
pbSelectedOptions - Which options of the specified feature is selected
|
|
|
|
Return Value:
|
|
|
|
FALSE if the input option array is not large enough to hold
|
|
all modified option values. TRUE otherwise.
|
|
|
|
Note:
|
|
|
|
Number of BOOLs in pSelectedOptions must match the number of options
|
|
for the specified feature.
|
|
|
|
This function always leaves the option array in a compact format (i.e.
|
|
all unused entries are left at the end of the array).
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL bStatus = TRUE ;
|
|
DWORD dwDestTail, dwSrcTail, dwNumFea , dwI ;
|
|
// POPTSELECT pNewOptions ;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
OPTSELECT pNewOptions[MAX_COMBINED_OPTIONS] ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
|
|
if(!pOptions)
|
|
{
|
|
ERR(("ReconstructOptionArray: caller passed in invalid pOptions.\n"));
|
|
return(FALSE); // Missing array.
|
|
}
|
|
|
|
#if 0
|
|
pNewOptions = (POPTSELECT)MemAlloc(sizeof(OPTSELECT) * MAX_COMBINED_OPTIONS) ;
|
|
|
|
if( !pNewOptions )
|
|
{
|
|
ERR(("Fatal: ReconstructOptionArray - unable to alloc %d bytes.\n",
|
|
sizeof(OPTSELECT) * MAX_COMBINED_OPTIONS));
|
|
return(FALSE); // Missing array.
|
|
}
|
|
#endif
|
|
|
|
|
|
dwDestTail = dwNumFea = pRawData->dwDocumentFeatures +
|
|
pRawData->dwPrinterFeatures ;
|
|
|
|
|
|
|
|
for(dwI = 0 ; dwI < dwNumFea ; dwI++)
|
|
{
|
|
if(dwI == dwFeatureIndex)
|
|
{
|
|
DWORD dwNumOptions, dwOpt ;
|
|
|
|
dwNumOptions = pfo[dwI].dwNumOptions ;
|
|
|
|
// determine first selected option, must have
|
|
// at least one.
|
|
|
|
for(dwOpt = 0 ; dwOpt < dwNumOptions &&
|
|
!pbSelectedOptions[dwOpt] ; dwOpt++)
|
|
{
|
|
; // null body
|
|
}
|
|
if(dwOpt >= dwNumOptions)
|
|
{
|
|
ERR(("ReconstructOptionArray: caller passed in invalid option selection.\n"));
|
|
bStatus = FALSE ;
|
|
break ;
|
|
}
|
|
pNewOptions[dwI].ubCurOptIndex = (BYTE)dwOpt ;
|
|
for(++dwOpt ; dwOpt < dwNumOptions &&
|
|
!pbSelectedOptions[dwOpt] ; dwOpt++)
|
|
{
|
|
; // null body
|
|
}
|
|
if(dwOpt == dwNumOptions) // no other options selected.
|
|
pNewOptions[dwI].ubNext = 0 ;
|
|
else
|
|
{
|
|
// pbSelectedOptions holds another selection.
|
|
pNewOptions[dwI].ubNext = (BYTE)dwDestTail ;
|
|
|
|
while(dwOpt < dwNumOptions)
|
|
{
|
|
pNewOptions[dwDestTail].ubCurOptIndex = (BYTE)dwOpt ;
|
|
pNewOptions[dwDestTail].ubNext = (BYTE)dwDestTail + 1 ;
|
|
dwDestTail++ ;
|
|
if(dwDestTail > MAX_COMBINED_OPTIONS)
|
|
{
|
|
ERR(("ReconstructOptionArray: exceeded limit of MAX_COMBINED_OPTIONS.\n"));
|
|
// MemFree(pNewOptions) ;
|
|
return(FALSE);
|
|
}
|
|
for(++dwOpt ; dwOpt < dwNumOptions &&
|
|
!pbSelectedOptions[dwOpt] ; dwOpt++)
|
|
{
|
|
; // null body
|
|
}
|
|
}
|
|
pNewOptions[dwDestTail - 1].ubNext = 0 ;
|
|
}
|
|
|
|
continue ;
|
|
}
|
|
pNewOptions[dwI].ubCurOptIndex = pOptions[dwI].ubCurOptIndex;
|
|
if(!(dwSrcTail = pOptions[dwI].ubNext)) // end of list
|
|
pNewOptions[dwI].ubNext = 0 ;
|
|
else
|
|
{
|
|
// dwSrcTail holds another selection.
|
|
pNewOptions[dwI].ubNext = (BYTE)dwDestTail ;
|
|
|
|
while(dwSrcTail)
|
|
{
|
|
pNewOptions[dwDestTail].ubCurOptIndex =
|
|
pOptions[dwSrcTail].ubCurOptIndex;
|
|
pNewOptions[dwDestTail].ubNext = (BYTE)dwDestTail + 1 ;
|
|
dwDestTail++ ;
|
|
if(dwDestTail > MAX_COMBINED_OPTIONS)
|
|
{
|
|
ERR(("ReconstructOptionArray: exceeded limit of MAX_COMBINED_OPTIONS.\n"));
|
|
// MemFree(pNewOptions) ;
|
|
return(FALSE);
|
|
}
|
|
dwSrcTail = pOptions[dwSrcTail].ubNext ;
|
|
}
|
|
pNewOptions[dwDestTail - 1].ubNext = 0 ;
|
|
}
|
|
}
|
|
|
|
if (dwDestTail > (DWORD)iMaxOptions)
|
|
{
|
|
ERR(("ReconstructOptionArray: exceeded size of array OPTSELECT.\n"));
|
|
bStatus = FALSE;
|
|
}
|
|
if(bStatus)
|
|
{
|
|
for(dwI = 0 ; dwI < dwDestTail ; dwI++)
|
|
pOptions[dwI] = pNewOptions[dwI] ;
|
|
}
|
|
// MemFree(pNewOptions) ;
|
|
return(bStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
ChangeOptionsViaID(
|
|
IN PINFOHEADER pInfoHdr ,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN DWORD dwFeatureID,
|
|
IN PDEVMODE pDevmode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Modifies an option array using the information in public devmode fields
|
|
|
|
Arguments:
|
|
|
|
pRawData - Points to raw binary printer description data
|
|
pOptions - Points to the option array to be modified
|
|
dwFeatureID - Specifies which field(s) of the input devmode should be used
|
|
pDevmode - Specifies the input devmode
|
|
|
|
Return Value:
|
|
TRUE if successful, FALSE if the specified feature ID is not supported
|
|
or there is an error
|
|
|
|
Note:
|
|
|
|
We assume the input devmode fields have been validated by the caller.
|
|
this GID: is determined by this devmode field: optID
|
|
|
|
GID_RESOLUTION dmPrintQuality, dmYResolution
|
|
GID_PAGESIZE dmPaperSize, dmPaperLength, dmPaperWidth CL_CONS_PAPERSIZE
|
|
GID_PAGEREGION N/A
|
|
GID_DUPLEX dmDuplex CL_CONS_DUPLEX
|
|
GID_INPUTSLOT dmDefaultSource CL_CONS_INPUTSLOT
|
|
GID_MEDIATYPE dmMediaType CL_CONS_MEDIATYPE
|
|
GID_MEMOPTION N/A
|
|
GID_COLORMODE N/A (hack something if needed.)
|
|
GID_ORIENTATION dmOrientation CL_CONS_ORIENTATION
|
|
GID_PAGEPROTECTION N/A
|
|
GID_COLLATE dmCollate CL_CONS_COLLATE
|
|
{DMCOLLATE_TRUE, DMCOLLATE_FALSE}
|
|
GID_OUTPUTBIN N/A
|
|
GID_HALFTONING N/A
|
|
|
|
see DEVMODE in sdk\inc\wingdi.h
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOL bStatus = FALSE ;
|
|
DWORD dwFeaIndex = 0, dwOptIndex, dwOptID ;
|
|
|
|
|
|
switch(dwFeatureID)
|
|
{
|
|
case GID_RESOLUTION:
|
|
{
|
|
DWORD dwXres, dwYres ;
|
|
// we assume caller has initialized both dmPrintQuality and
|
|
// dmYResolution.
|
|
|
|
dwXres = pDevmode->dmPrintQuality ;
|
|
dwYres = pDevmode->dmYResolution ;
|
|
|
|
bStatus = BMapResToOptIndex(pInfoHdr, &dwOptIndex, dwXres, dwYres) ;
|
|
if(bStatus &&
|
|
(bStatus = BGIDtoFeaIndex(pInfoHdr,
|
|
&dwFeaIndex, dwFeatureID)) )
|
|
{
|
|
// don't need to worry about truncating
|
|
// a list of options, these features
|
|
// are all PICKONE.
|
|
pOptions[dwFeaIndex].ubCurOptIndex = (BYTE)dwOptIndex ;
|
|
pOptions[dwFeaIndex].ubNext = 0 ;
|
|
}
|
|
return (bStatus);
|
|
}
|
|
case GID_PAGESIZE:
|
|
{
|
|
if( pDevmode->dmFields & DM_PAPERLENGTH &&
|
|
pDevmode->dmFields & DM_PAPERWIDTH &&
|
|
pDevmode->dmPaperWidth &&
|
|
pDevmode->dmPaperLength)
|
|
{
|
|
// must convert devmode's tenths of mm to microns
|
|
// before calling.
|
|
|
|
bStatus = BMapPaperDimToOptIndex(pInfoHdr, &dwOptIndex,
|
|
pDevmode->dmPaperWidth * 100L,
|
|
pDevmode->dmPaperLength * 100L, NULL) ;
|
|
}
|
|
else if(pDevmode->dmFields & DM_PAPERSIZE)
|
|
{
|
|
dwOptID = pDevmode->dmPaperSize ;
|
|
bStatus = BMapOptIDtoOptIndex(pInfoHdr, &dwOptIndex,
|
|
dwFeatureID, dwOptID) ;
|
|
}
|
|
else
|
|
bStatus = FALSE ;
|
|
|
|
if(bStatus &&
|
|
(bStatus = BGIDtoFeaIndex(pInfoHdr,
|
|
&dwFeaIndex, dwFeatureID)) )
|
|
{
|
|
pOptions[dwFeaIndex].ubCurOptIndex = (BYTE)dwOptIndex ;
|
|
pOptions[dwFeaIndex].ubNext = 0 ;
|
|
return (bStatus); // must exit now.
|
|
}
|
|
break ;
|
|
}
|
|
case GID_DUPLEX:
|
|
{
|
|
if(pDevmode->dmFields & DM_DUPLEX)
|
|
{
|
|
dwOptID = pDevmode->dmDuplex ;
|
|
bStatus = TRUE ;
|
|
}
|
|
break ;
|
|
}
|
|
case GID_INPUTSLOT:
|
|
{
|
|
if(pDevmode->dmFields & DM_DEFAULTSOURCE)
|
|
{
|
|
dwOptID = pDevmode->dmDefaultSource ;
|
|
bStatus = TRUE ;
|
|
}
|
|
break ;
|
|
}
|
|
case GID_MEDIATYPE:
|
|
{
|
|
if(pDevmode->dmFields & DM_MEDIATYPE)
|
|
{
|
|
dwOptID = pDevmode->dmMediaType ;
|
|
bStatus = TRUE ;
|
|
}
|
|
break ;
|
|
}
|
|
case GID_COLORMODE:
|
|
{
|
|
if(pDevmode->dmFields & DM_COLOR)
|
|
{
|
|
// special processing since devmode
|
|
// only specifies BW or color printing.
|
|
|
|
bStatus = BGIDtoFeaIndex(pInfoHdr,
|
|
&dwFeaIndex, dwFeatureID) ;
|
|
|
|
if(!bStatus) // dwFeaIndex could be invalid at this point.
|
|
return (bStatus);
|
|
|
|
// what is the current color setting?
|
|
dwOptIndex = pOptions[dwFeaIndex].ubCurOptIndex ;
|
|
|
|
if(bStatus &&
|
|
(bStatus = BMapDmColorToOptIndex(pInfoHdr, &dwOptIndex,
|
|
pDevmode->dmColor)) )
|
|
{
|
|
pOptions[dwFeaIndex].ubCurOptIndex = (BYTE)dwOptIndex ;
|
|
pOptions[dwFeaIndex].ubNext = 0 ;
|
|
}
|
|
}
|
|
return (bStatus);
|
|
}
|
|
case GID_ORIENTATION:
|
|
{
|
|
if(pDevmode->dmFields & DM_ORIENTATION)
|
|
{
|
|
dwOptID = pDevmode->dmOrientation ;
|
|
|
|
|
|
if(dwOptID == DMORIENT_PORTRAIT)
|
|
dwOptID = ROTATE_NONE ;
|
|
else
|
|
{
|
|
dwOptID = ROTATE_90 ;
|
|
bStatus = BMapOptIDtoOptIndex(pInfoHdr, &dwOptIndex,
|
|
dwFeatureID, dwOptID) ;
|
|
if(!bStatus)
|
|
{
|
|
dwOptID = ROTATE_270 ;
|
|
}
|
|
}
|
|
|
|
bStatus = TRUE ;
|
|
}
|
|
break ;
|
|
}
|
|
case GID_COLLATE:
|
|
{
|
|
if(pDevmode->dmFields & DM_COLLATE)
|
|
{
|
|
dwOptID = pDevmode->dmCollate ;
|
|
bStatus = TRUE ;
|
|
}
|
|
break ;
|
|
}
|
|
default:
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
// Complete processing for typical case.
|
|
|
|
if(bStatus)
|
|
{
|
|
bStatus = BMapOptIDtoOptIndex(pInfoHdr, &dwOptIndex,
|
|
dwFeatureID, dwOptID) ;
|
|
}
|
|
if(bStatus &&
|
|
(bStatus = BGIDtoFeaIndex(pInfoHdr,
|
|
&dwFeaIndex, dwFeatureID) ))
|
|
{
|
|
// don't need to worry about truncating
|
|
// a list of options, these features
|
|
// are all PICKONE.
|
|
pOptions[dwFeaIndex].ubCurOptIndex = (BYTE)dwOptIndex ;
|
|
pOptions[dwFeaIndex].ubNext = 0 ;
|
|
}
|
|
return (bStatus);
|
|
}
|
|
|
|
BOOL BMapDmColorToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
IN OUT PDWORD pdwOptIndex , // is current setting ok?
|
|
// if not return new index to caller
|
|
DWORD dwDmColor // what is requested in Devmode
|
|
)
|
|
{
|
|
PUIINFO pUIInfo ;
|
|
PFEATURE pFeature ;
|
|
DWORD dwNumOpts, loOptOffset, dwI ;
|
|
PCOLORMODE pColorModeOption ;
|
|
BOOL bColor ;
|
|
DWORD loOptExOffset ;
|
|
PCOLORMODEEX pColorModeOptionEx ;
|
|
|
|
|
|
bColor = (dwDmColor == DMCOLOR_COLOR) ;
|
|
|
|
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHdr) ;
|
|
pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_COLORMODE) ;
|
|
if(!pFeature)
|
|
return(FALSE) ; // no such feature defined in GPD
|
|
dwNumOpts = pFeature->Options.dwCount ;
|
|
loOptOffset = pFeature->Options.loOffset ;
|
|
|
|
if(*pdwOptIndex >= dwNumOpts) // option index out of range - fix for 185245
|
|
{
|
|
*pdwOptIndex = pFeature->dwDefaultOptIndex ; // use the default option
|
|
return(FALSE) ;
|
|
}
|
|
|
|
pColorModeOption = OFFSET_TO_POINTER(pInfoHdr, loOptOffset) ;
|
|
|
|
loOptExOffset = pColorModeOption[*pdwOptIndex].GenericOption.loRenderOffset ;
|
|
pColorModeOptionEx = OFFSET_TO_POINTER(pInfoHdr, loOptExOffset) ;
|
|
|
|
if(bColor == pColorModeOptionEx->bColor)
|
|
return(TRUE) ; // currently selected colormode
|
|
// matches devmode request.
|
|
|
|
loOptExOffset = pColorModeOption[pFeature->dwDefaultOptIndex].
|
|
GenericOption.loRenderOffset ;
|
|
pColorModeOptionEx = OFFSET_TO_POINTER(pInfoHdr, loOptExOffset) ;
|
|
|
|
if(bColor == pColorModeOptionEx->bColor)
|
|
{
|
|
*pdwOptIndex = pFeature->dwDefaultOptIndex ;
|
|
return(TRUE) ; // the default colormode option
|
|
} // matches devmode request.
|
|
|
|
|
|
// last ditch effort - just find the first matching one.
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
loOptExOffset = pColorModeOption[dwI].GenericOption.loRenderOffset ;
|
|
pColorModeOptionEx = OFFSET_TO_POINTER(pInfoHdr, loOptExOffset) ;
|
|
|
|
if(bColor == pColorModeOptionEx->bColor)
|
|
{
|
|
*pdwOptIndex = dwI ;
|
|
return(TRUE) ;
|
|
}
|
|
}
|
|
return(FALSE) ; // no matching colormode found.
|
|
}
|
|
|
|
BOOL BMapOptIDtoOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
OUT PDWORD pdwOptIndex , // return index to caller
|
|
DWORD dwFeatureGID,
|
|
DWORD dwOptID
|
|
)
|
|
{
|
|
PUIINFO pUIInfo ;
|
|
PFEATURE pFeature ;
|
|
DWORD dwNumOpts, loOptOffset, dwI, dwIDOffset, dwOptSize, dwCurID ;
|
|
POPTION pOption ;
|
|
|
|
switch(dwFeatureGID)
|
|
{
|
|
case GID_HALFTONING:
|
|
dwIDOffset = offsetof(HALFTONING, dwHTID ) ;
|
|
break ;
|
|
case GID_DUPLEX:
|
|
dwIDOffset = offsetof(DUPLEX, dwDuplexID ) ;
|
|
break ;
|
|
case GID_ORIENTATION:
|
|
dwIDOffset = offsetof(ORIENTATION, dwRotationAngle ) ;
|
|
break ;
|
|
case GID_PAGESIZE:
|
|
dwIDOffset = offsetof(PAGESIZE, dwPaperSizeID ) ;
|
|
break ;
|
|
case GID_INPUTSLOT:
|
|
dwIDOffset = offsetof(INPUTSLOT, dwPaperSourceID ) ;
|
|
break ;
|
|
case GID_MEDIATYPE:
|
|
dwIDOffset = offsetof(MEDIATYPE, dwMediaTypeID ) ;
|
|
break ;
|
|
case GID_COLLATE:
|
|
dwIDOffset = offsetof(COLLATE, dwCollateID ) ;
|
|
break ;
|
|
default:
|
|
return(FALSE); // this feature has no ID value!
|
|
}
|
|
|
|
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHdr) ;
|
|
pFeature = GET_PREDEFINED_FEATURE(pUIInfo, dwFeatureGID) ;
|
|
if(!pFeature)
|
|
return(FALSE) ; // no such feature defined in GPD
|
|
dwNumOpts = pFeature->Options.dwCount ;
|
|
loOptOffset = pFeature->Options.loOffset ;
|
|
dwOptSize = pFeature->dwOptionSize ;
|
|
|
|
pOption = OFFSET_TO_POINTER(pInfoHdr, loOptOffset) ;
|
|
|
|
// just find the first matching one.
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
dwCurID = *(PDWORD)((PBYTE)pOption + dwI * dwOptSize + dwIDOffset) ;
|
|
if(dwOptID == dwCurID)
|
|
{
|
|
*pdwOptIndex = dwI ;
|
|
return(TRUE) ;
|
|
}
|
|
}
|
|
return(FALSE) ; // no matching ID found.
|
|
}
|
|
|
|
|
|
BOOL BMapPaperDimToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
OUT PDWORD pdwOptIndex , // return index to caller
|
|
DWORD dwWidth, // in Microns
|
|
DWORD dwLength, // in Microns
|
|
OUT PDWORD pdwOptionIndexes
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map logical values to PaperSize option index
|
|
|
|
Arguments:
|
|
|
|
pdwOptIndex - if pdwOptionIndexs == NULL, this
|
|
holds the option index of the first paper matching the
|
|
requested dimensions. Otherwise this holds the number
|
|
of papers matching the requested dimensions.
|
|
dwWidth , dwLength - requested Paper Size in Microns
|
|
pdwOptionIndexes - if Not NULL, this array will be initialized
|
|
with all option indicies of papers which match the requested size.
|
|
In this case the return value
|
|
is the number of elements in the array initialized. Currently
|
|
we assume the array is large enough (256 elements).
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE: found one or more papers of the size requested.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUIINFO pUIInfo ;
|
|
PGPDDRIVERINFO pDrvInfo ;
|
|
PFEATURE pFeature ;
|
|
DWORD dwNumOpts, loOptOffset, dwI ,
|
|
dwError, dwErrorY, dwCustomIndex,
|
|
dwOptWidth , dwOptLength,
|
|
dwMinWidth , dwMinLength,
|
|
dwMaxWidth , dwMaxLength,
|
|
dwOutArrayIndex = 0;
|
|
PPAGESIZE pPaperOption ;
|
|
BOOL bFits = FALSE ; // does custom size fit request?
|
|
|
|
// Convert from Microns to Master units.
|
|
|
|
|
|
dwWidth /= 100 ; // microns to tenths of mm
|
|
dwLength /= 100 ;
|
|
|
|
pDrvInfo = (PGPDDRIVERINFO) GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHdr) ;
|
|
|
|
dwWidth *= pDrvInfo->Globals.ptMasterUnits.x ;
|
|
dwLength *= pDrvInfo->Globals.ptMasterUnits.y ;
|
|
|
|
dwWidth /= 254 ;
|
|
dwLength /= 254 ;
|
|
|
|
dwError = pDrvInfo->Globals.ptMasterUnits.x / 100 ;
|
|
dwErrorY = pDrvInfo->Globals.ptMasterUnits.y / 100 ;
|
|
|
|
dwError = (dwError > dwErrorY) ? dwError : dwErrorY ;
|
|
dwError = (dwError > 3) ? dwError : 3 ;
|
|
|
|
// give leeway of 3 master units or 1/100 inch whichever
|
|
// is greater.
|
|
|
|
dwMinWidth = (dwWidth < dwError) ? 0 : (dwWidth - dwError) ;
|
|
dwMinLength = (dwLength < dwError) ? 0 : (dwLength - dwError) ;
|
|
|
|
dwMaxWidth = dwWidth + dwError ;
|
|
dwMaxLength = dwLength + dwError ;
|
|
|
|
|
|
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHdr) ;
|
|
pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_PAGESIZE) ;
|
|
if(!pFeature)
|
|
return(FALSE) ; // no such feature defined in GPD
|
|
dwNumOpts = pFeature->Options.dwCount ;
|
|
loOptOffset = pFeature->Options.loOffset ;
|
|
|
|
pPaperOption = OFFSET_TO_POINTER(pInfoHdr, loOptOffset) ;
|
|
|
|
|
|
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
if(pPaperOption[dwI].dwPaperSizeID != DMPAPER_USER)
|
|
{
|
|
dwOptWidth = pPaperOption[dwI].szPaperSize.cx ;
|
|
dwOptLength = pPaperOption[dwI].szPaperSize.cy ;
|
|
if(dwOptWidth > dwMinWidth && dwOptWidth < dwMaxWidth &&
|
|
dwOptLength > dwMinLength && dwOptLength < dwMaxLength )
|
|
{
|
|
if(pdwOptionIndexes)
|
|
pdwOptionIndexes[dwOutArrayIndex++] = dwI ;
|
|
else
|
|
{
|
|
*pdwOptIndex = dwI ;
|
|
return(TRUE) ;
|
|
}
|
|
}
|
|
}
|
|
else // this is the custom size:
|
|
{
|
|
DWORD loOptExOffset ;
|
|
PPAGESIZEEX pPaperOptionEx ;
|
|
|
|
loOptExOffset = pPaperOption[dwI].GenericOption.loRenderOffset ;
|
|
pPaperOptionEx = OFFSET_TO_POINTER(pInfoHdr, loOptExOffset) ;
|
|
|
|
// does it fit the requested size?
|
|
if(dwWidth <= (DWORD)pPaperOptionEx->ptMaxSize.x &&
|
|
dwWidth >= (DWORD)pPaperOptionEx->ptMinSize.x &&
|
|
dwLength <= (DWORD)pPaperOptionEx->ptMaxSize.y &&
|
|
dwLength >= (DWORD)pPaperOptionEx->ptMinSize.y )
|
|
{
|
|
bFits = TRUE ;
|
|
dwCustomIndex = dwI ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pdwOptionIndexes)
|
|
{
|
|
if(bFits)
|
|
{
|
|
pdwOptionIndexes[dwOutArrayIndex++] = dwCustomIndex ;
|
|
}
|
|
*pdwOptIndex = dwOutArrayIndex ;
|
|
// cover the case where dwOutArrayIndex = 0.
|
|
if(dwOutArrayIndex)
|
|
return(TRUE) ;
|
|
return(FALSE) ;
|
|
}
|
|
|
|
if(bFits)
|
|
{
|
|
*pdwOptIndex = dwCustomIndex ;
|
|
return(TRUE) ;
|
|
}
|
|
return(FALSE) ;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL BMapResToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
OUT PDWORD pdwOptIndex , // return index to caller
|
|
DWORD dwXres,
|
|
DWORD dwYres
|
|
)
|
|
{
|
|
PUIINFO pUIInfo ;
|
|
PFEATURE pFeature ;
|
|
DWORD dwNumOpts, loOptOffset, dwI ;
|
|
DWORD dwHighRes, dwLowRes, dwMedRes, dwDefRes, dwCurRes,
|
|
// in pixels per square inch.
|
|
dwHighIndex, dwLowIndex, dwMedIndex, dwDefIndex ;
|
|
PRESOLUTION pResOption ;
|
|
|
|
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHdr) ;
|
|
pFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_RESOLUTION) ;
|
|
if(!pFeature)
|
|
return(FALSE) ; // no such feature defined in GPD
|
|
dwNumOpts = pFeature->Options.dwCount ;
|
|
loOptOffset = pFeature->Options.loOffset ;
|
|
|
|
pResOption = OFFSET_TO_POINTER(pInfoHdr, loOptOffset) ;
|
|
|
|
|
|
if((signed)dwXres > 0)
|
|
{
|
|
|
|
dwDefIndex = pFeature->dwDefaultOptIndex ;
|
|
if(dwXres == (DWORD)pResOption[dwDefIndex].iXdpi &&
|
|
dwYres == (DWORD)pResOption[dwDefIndex].iYdpi)
|
|
{
|
|
*pdwOptIndex = dwDefIndex ;
|
|
return(TRUE) ;
|
|
}
|
|
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
if(dwXres == (DWORD)pResOption[dwI].iXdpi &&
|
|
dwYres == (DWORD)pResOption[dwI].iYdpi)
|
|
{
|
|
*pdwOptIndex = dwI ;
|
|
return(TRUE) ;
|
|
}
|
|
}
|
|
}
|
|
else if ((signed)dwXres > RES_ID_IGNORE) // OEM defined ID
|
|
{
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
if(dwXres == (DWORD)pResOption[dwI].dwResolutionID)
|
|
{
|
|
*pdwOptIndex = dwI ;
|
|
return(TRUE) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if exact match fails, or predefined negative value or nonsense
|
|
// resort to fuzzy match.
|
|
|
|
// first determine the highest, lowest, 2nd highest and default resolutions.
|
|
|
|
dwHighIndex = dwLowIndex = dwMedIndex = dwDefIndex =
|
|
pFeature->dwDefaultOptIndex ;
|
|
|
|
dwHighRes = dwLowRes = dwMedRes = dwDefRes =
|
|
(DWORD)pResOption[dwDefIndex].iXdpi *
|
|
(DWORD)pResOption[dwDefIndex].iYdpi ;
|
|
|
|
// note overflow possible if resolution exceeds 64k dpi.
|
|
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
dwCurRes = (DWORD)pResOption[dwI].iXdpi *
|
|
(DWORD)pResOption[dwI].iYdpi ;
|
|
|
|
if(dwCurRes > dwHighRes)
|
|
{
|
|
dwHighIndex = dwI ;
|
|
dwHighRes = dwCurRes ;
|
|
}
|
|
else if(dwCurRes < dwLowRes)
|
|
{
|
|
dwLowIndex = dwI ;
|
|
dwLowRes = dwCurRes ;
|
|
}
|
|
else if(dwCurRes < dwHighRes && dwCurRes > dwLowRes &&
|
|
(dwMedRes == dwHighRes || dwMedRes == dwLowRes || dwCurRes > dwMedRes))
|
|
{
|
|
dwMedIndex = dwI ; // if more than one middle res possible
|
|
dwMedRes = dwCurRes ; // choose the largest.
|
|
}
|
|
|
|
}
|
|
|
|
// if (default res is not the highest or lowest, make default res the middle resolution
|
|
if(dwDefRes < dwHighRes && dwDefRes > dwLowRes)
|
|
{
|
|
dwMedIndex = dwDefIndex ;
|
|
dwMedRes = dwDefRes ; // unnecessary code, but just in case
|
|
// like the last break in a switch statement.
|
|
}
|
|
|
|
switch(dwXres)
|
|
{
|
|
case(DMRES_DRAFT):
|
|
case(DMRES_LOW):
|
|
*pdwOptIndex = dwLowIndex ;
|
|
break;
|
|
case(DMRES_MEDIUM):
|
|
*pdwOptIndex = dwMedIndex ;
|
|
break;
|
|
case(DMRES_HIGH):
|
|
*pdwOptIndex = dwHighIndex ;
|
|
break;
|
|
default:
|
|
*pdwOptIndex = dwDefIndex ;
|
|
break;
|
|
}
|
|
return(TRUE) ;
|
|
}
|
|
|
|
|
|
BOOL BGIDtoFeaIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
PDWORD pdwFeaIndex ,
|
|
DWORD dwFeatureGID )
|
|
{
|
|
PUIINFO pUIInfo ;
|
|
PFEATURE pFeature ;
|
|
|
|
pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHdr) ;
|
|
pFeature = GET_PREDEFINED_FEATURE(pUIInfo, dwFeatureGID) ;
|
|
if(!pFeature)
|
|
return(FALSE) ; // no such feature defined in GPD
|
|
|
|
*pdwFeaIndex = (DWORD)GET_INDEX_FROM_FEATURE(pUIInfo, pFeature) ;
|
|
return(TRUE) ;
|
|
}
|
|
|
|
|
|
DWORD
|
|
MapToDeviceOptIndex(
|
|
IN PINFOHEADER pInfoHdr ,
|
|
IN DWORD dwFeatureID,
|
|
IN LONG lParam1,
|
|
IN LONG lParam2,
|
|
OUT PDWORD pdwOptionIndexes // used only for GID_PAGESIZE
|
|
)
|
|
{
|
|
return ( UniMapToDeviceOptIndex(
|
|
pInfoHdr , dwFeatureID, lParam1, lParam2,
|
|
pdwOptionIndexes, // used only for GID_PAGESIZE
|
|
NULL) ) ;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
UniMapToDeviceOptIndex(
|
|
IN PINFOHEADER pInfoHdr ,
|
|
IN DWORD dwFeatureID,
|
|
IN LONG lParam1,
|
|
IN LONG lParam2,
|
|
OUT PDWORD pdwOptionIndexes, // used only for GID_PAGESIZE
|
|
IN PDWORD pdwPaperID // optional paperID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map logical values to device feature option index
|
|
|
|
Arguments:
|
|
|
|
pRawData - Points to raw binary printer description data
|
|
dwFeatureID - Indicate which feature the logical values are related to
|
|
lParam1, lParam2 - Parameters depending on dwFeatureID
|
|
pdwOptionIndexes - if Not NULL, means fill this array with all indicies
|
|
which match the search criteria. In this case the return value
|
|
is the number of elements in the array initialized. Currently
|
|
we assume the array is large enough (256 elements).
|
|
|
|
dwFeatureID = GID_PAGESIZE:
|
|
map logical paper specification to physical page size option
|
|
|
|
lParam1 = paper width in microns
|
|
lParam2 = paper height in microns
|
|
|
|
IF lParam1 or 2 is set to zero, this function assumes
|
|
pdwPaperID points to the OptionID of a paper.
|
|
It will return the first paper found matching this ID.
|
|
|
|
dwFeatureID = GID_RESOLUTION:
|
|
map logical resolution to physical resolution option
|
|
|
|
lParam1 = x-resolution in dpi
|
|
lParam2 = y-resolution in dpi
|
|
|
|
Return Value:
|
|
|
|
Index of the feature option corresponding to the specified logical values;
|
|
OPTION_INDEX_ANY if the specified logical values cannot be mapped to
|
|
any feature option.
|
|
|
|
if pdwOptionIndexes Not NULL, the return value is the number of elements
|
|
written to. Zero means the specified logical values cannot be mapped to
|
|
any feature option.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD dwOptIndex;
|
|
|
|
|
|
switch (dwFeatureID)
|
|
{
|
|
case GID_PAGESIZE:
|
|
{
|
|
if(pdwOptionIndexes)
|
|
return( MapPaperAttribToOptIndex(
|
|
pInfoHdr ,
|
|
pdwPaperID , // optional paperID
|
|
(DWORD)lParam1, (DWORD)lParam2, // in Microns
|
|
pdwOptionIndexes) ) ;
|
|
|
|
if(BMapPaperDimToOptIndex(pInfoHdr, &dwOptIndex,
|
|
(DWORD)lParam1, (DWORD)lParam2, NULL) )
|
|
return(dwOptIndex) ;
|
|
break ;
|
|
}
|
|
case GID_RESOLUTION:
|
|
{
|
|
if( BMapResToOptIndex(pInfoHdr, &dwOptIndex,
|
|
(DWORD)lParam1, (DWORD)lParam2) )
|
|
return(dwOptIndex) ;
|
|
break ;
|
|
}
|
|
default:
|
|
break ;
|
|
}
|
|
return(OPTION_INDEX_ANY) ;
|
|
}
|
|
|
|
DWORD MapPaperAttribToOptIndex(
|
|
PINFOHEADER pInfoHdr ,
|
|
IN PDWORD pdwPaperID , // optional paperID
|
|
DWORD dwWidth, // in Microns (set to zero to ignore)
|
|
DWORD dwLength, // in Microns
|
|
OUT PDWORD pdwOptionIndexes // cannot be NULL
|
|
)
|
|
{
|
|
DWORD dwNumFound;
|
|
BOOL bStatus ;
|
|
|
|
if(dwWidth && dwLength)
|
|
{
|
|
if( BMapPaperDimToOptIndex(pInfoHdr, &dwNumFound,
|
|
dwWidth , dwLength, pdwOptionIndexes) )
|
|
return(dwNumFound);
|
|
return(0);
|
|
}
|
|
|
|
if(pdwPaperID) // use paperID instead of dimensions
|
|
{
|
|
bStatus = BMapOptIDtoOptIndex(pInfoHdr, pdwOptionIndexes,
|
|
GID_PAGESIZE, *pdwPaperID) ;
|
|
return(bStatus ? 1 : 0) ;
|
|
}
|
|
return(0); // if given nothing, return nothing
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckFeatureOptionConflict(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN DWORD dwFeature1,
|
|
IN DWORD dwOption1,
|
|
IN DWORD dwFeature2,
|
|
IN DWORD dwOption2
|
|
)
|
|
{
|
|
#ifndef KERNEL_MODE
|
|
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubHeap , // start of string heap.
|
|
pubRaw ; // raw binary data.
|
|
DWORD dwNodeIndex ,
|
|
dwCNode ; // index to a Constraint node
|
|
PATTRIB_TREE patt ; // start of ATTRIBUTE tree array.
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
// PINVALIDCOMBO pinvc ; // root of invalid combo nodes
|
|
PCONSTRAINTS pcnstr ; // root of Constraint nodes
|
|
BOOL bReflected = FALSE ;
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
patt = (PATTRIB_TREE)(pubRaw +
|
|
pearTableContents[MTI_ATTRIBTREE].loOffset) ;
|
|
// pinvc = (PINVALIDCOMBO) (pubRaw +
|
|
// pearTableContents[MTI_INVALIDCOMBO].loOffset) ;
|
|
pcnstr = (PCONSTRAINTS) (pubRaw +
|
|
pearTableContents[MTI_CONSTRAINTS].loOffset) ;
|
|
pubHeap = (PBYTE)(pubRaw + pearTableContents[MTI_STRINGHEAP].
|
|
loOffset) ;
|
|
|
|
TRYAGAIN:
|
|
|
|
patrRoot = &(pfo[dwFeature1].atrConstraints) ;
|
|
|
|
dwNodeIndex = DwFindNodeInCurLevel(patt , patrRoot , dwOption1) ;
|
|
|
|
if(dwNodeIndex == INVALID_INDEX)
|
|
goto REFLECTCONSTRAINT ;
|
|
|
|
if(patt[dwNodeIndex].eOffsetMeans != VALUE_AT_HEAP)
|
|
{
|
|
ERR(("Internal error. CheckFeatureOptionConflict - Unexpected Sublevel found for atrConstraints.\n"));
|
|
goto REFLECTCONSTRAINT ;
|
|
}
|
|
|
|
dwCNode = *(PDWORD)(pubHeap + patt[dwNodeIndex].dwOffset) ;
|
|
|
|
while(1)
|
|
{
|
|
if(pcnstr[dwCNode].dwFeature == dwFeature2 &&
|
|
pcnstr[dwCNode].dwOption == dwOption2)
|
|
return(TRUE) ; // a constraint does exist.
|
|
|
|
dwCNode = pcnstr[dwCNode].dwNextCnstrnt ;
|
|
if(dwCNode == END_OF_LIST)
|
|
break ;
|
|
}
|
|
|
|
REFLECTCONSTRAINT :
|
|
|
|
if(!bReflected)
|
|
{
|
|
DWORD dwSwap ;
|
|
|
|
dwSwap = dwFeature2 ;
|
|
dwFeature2 = dwFeature1 ;
|
|
dwFeature1 = dwSwap ;
|
|
|
|
dwSwap = dwOption2 ;
|
|
dwOption2 = dwOption1 ;
|
|
dwOption1 = dwSwap ;
|
|
|
|
bReflected = TRUE ;
|
|
goto TRYAGAIN;
|
|
}
|
|
|
|
// else continue on to FINDINVALIDCOMBOS
|
|
|
|
// oops this function doesn't care about
|
|
// InvalidCombos! It only knows about
|
|
// 2 qualified objects.
|
|
|
|
|
|
|
|
#else
|
|
RIP(("CheckFeatureOptionConflict not implemented in Kernel Mode")) ;
|
|
#endif
|
|
return(FALSE); // no constraint found.
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ValidateDocOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validate the devmode option array and correct any invalid option selections
|
|
|
|
Arguments:
|
|
|
|
pnRawData - Points to raw binary printer description data
|
|
pOptions - Points to an array of OPTSELECT structures that need validation
|
|
iMaxOptions - Max number of entries in pOptions array
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
INT NumDocFea = 0;
|
|
INT iIndex = 0;
|
|
DWORD nFeatures = 0 ; // total number of Doc and Printer Features
|
|
DWORD FeaIndex = 0 ;
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
POPTSELECT pCombinedOptions = NULL; // holds result of merging pOptions with a NULL array
|
|
POPTSELECT pDefaultOptions = NULL; // holds a default option array. Source of default values.
|
|
BOOL bStatus = TRUE ;
|
|
DWORD MaxIndex = (iMaxOptions < MAX_COMBINED_OPTIONS) ? iMaxOptions : MAX_COMBINED_OPTIONS ;
|
|
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
NumDocFea = pRawData->dwDocumentFeatures ;
|
|
|
|
if(!pOptions)
|
|
{
|
|
RIP(("ValidateDocOptions: NULL Option array not permitted.\n"));
|
|
return ;
|
|
}
|
|
|
|
if(iMaxOptions < NumDocFea)
|
|
{
|
|
RIP(("ValidateDocOptions: Option array too small: %d < %d\n", iMaxOptions, NumDocFea));
|
|
goto Abort;
|
|
}
|
|
pubRaw = (PBYTE)pRawData ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw + pearTableContents[MTI_DFEATURE_OPTIONS].
|
|
loOffset) ; // location of Feature 0.
|
|
|
|
// allocate memory to hold combined option array
|
|
// allocate another one to hold initialized default option array
|
|
|
|
pCombinedOptions = (POPTSELECT)MemAlloc(sizeof(OPTSELECT) * MAX_COMBINED_OPTIONS) ;
|
|
pDefaultOptions = (POPTSELECT)MemAlloc(sizeof(OPTSELECT) * MAX_COMBINED_OPTIONS) ;
|
|
|
|
if( !pCombinedOptions || !pDefaultOptions )
|
|
goto Abort;
|
|
|
|
// verify any pick many slots don't create overlapping or endless loops.
|
|
// use pCombinedOptions to track them.
|
|
for(iIndex = NumDocFea ; iIndex < MAX_COMBINED_OPTIONS ; iIndex++)
|
|
{
|
|
pCombinedOptions[iIndex].ubCurOptIndex = 0 ; // these are available to hold pickmany selections
|
|
}
|
|
for(iIndex = 0 ; iIndex < NumDocFea ; iIndex++)
|
|
{
|
|
DWORD NextArrayEle = pOptions[iIndex].ubNext ;
|
|
|
|
for ( ; (NextArrayEle != NULL_OPTSELECT) ; NextArrayEle = pOptions[NextArrayEle].ubNext)
|
|
{
|
|
if((NextArrayEle >= MaxIndex) || ((INT)NextArrayEle < NumDocFea) ||
|
|
(pCombinedOptions[NextArrayEle].ubCurOptIndex) )
|
|
{ // NextArrayEle out of bounds or overwrites a previous slot.
|
|
pOptions[iIndex].ubNext = NULL_OPTSELECT;
|
|
break; // just terminate this pickmany list.
|
|
}
|
|
pCombinedOptions[NextArrayEle].ubCurOptIndex = 1 ; // reserve this slot.
|
|
}
|
|
}
|
|
|
|
|
|
bStatus = InitDefaultOptions( pnRawData, pDefaultOptions, MAX_COMBINED_OPTIONS,
|
|
MODE_DOCANDPRINTER_STICKY) ;
|
|
|
|
if(!bStatus)
|
|
goto Abort;
|
|
|
|
// must merge input pOptions to create a combined option array.
|
|
|
|
bStatus = CombineOptionArray( pnRawData, pCombinedOptions, iMaxOptions,
|
|
pOptions, NULL) ;
|
|
|
|
if(!bStatus)
|
|
goto Abort;
|
|
|
|
|
|
nFeatures = pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures ;
|
|
|
|
if(nFeatures > MAX_COMBINED_OPTIONS)
|
|
goto Abort;
|
|
|
|
for(FeaIndex = 0 ; FeaIndex < nFeatures ; FeaIndex++)
|
|
{
|
|
DWORD nOptions = 0 ; // number of options available for this Feature
|
|
DWORD NextArrayEle = 0 ; // index into option array esp for PickMany
|
|
DWORD cSelectedOptions = 0; // how many options have been selected for this feature?
|
|
|
|
nOptions = pfo[FeaIndex].dwNumOptions ;
|
|
NextArrayEle = FeaIndex;
|
|
bStatus = TRUE;
|
|
|
|
do
|
|
{
|
|
cSelectedOptions++;
|
|
|
|
if ((NextArrayEle >= MAX_COMBINED_OPTIONS) || // index out of range
|
|
(pCombinedOptions[NextArrayEle].ubCurOptIndex >= nOptions) || // selected option out of range
|
|
(cSelectedOptions > nOptions)) // too many options selected (for pick many)
|
|
{
|
|
//
|
|
// either the option index is out of range,
|
|
// or the current option selection is invalid,
|
|
// or the number of selected options (for PICKMANY)
|
|
// exceeds available options
|
|
//
|
|
|
|
bStatus = FALSE;
|
|
break;
|
|
}
|
|
|
|
NextArrayEle = pCombinedOptions[NextArrayEle].ubNext;
|
|
|
|
} while (NextArrayEle != NULL_OPTSELECT);
|
|
if (!bStatus)
|
|
{
|
|
pCombinedOptions[FeaIndex].ubCurOptIndex =
|
|
pDefaultOptions[FeaIndex].ubCurOptIndex;
|
|
|
|
pCombinedOptions[FeaIndex].ubNext = NULL_OPTSELECT;
|
|
}
|
|
}
|
|
// separate combined option array into doc sticky part and
|
|
// store that in pOptions.
|
|
|
|
bStatus = SeparateOptionArray(pnRawData, pCombinedOptions,
|
|
pOptions, iMaxOptions, MODE_DOCUMENT_STICKY ) ;
|
|
|
|
if(!bStatus)
|
|
goto Abort;
|
|
|
|
|
|
if(pCombinedOptions)
|
|
MemFree(pCombinedOptions) ;
|
|
if(pDefaultOptions)
|
|
MemFree(pDefaultOptions) ;
|
|
return ; // Normal return path
|
|
|
|
Abort: // something has gone totally haywire.
|
|
if(iMaxOptions > NumDocFea )
|
|
iMaxOptions = NumDocFea ;
|
|
|
|
for(iIndex = 0 ; iIndex < iMaxOptions ; iIndex++)
|
|
{
|
|
pOptions[iIndex].ubCurOptIndex = 0 ;
|
|
pOptions[iIndex].ubNext = NULL_OPTSELECT;
|
|
}
|
|
if(pCombinedOptions)
|
|
MemFree(pCombinedOptions) ;
|
|
if(pDefaultOptions)
|
|
MemFree(pDefaultOptions) ;
|
|
return ; // error return path.
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ResolveUIConflicts(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN INT iMode
|
|
)
|
|
{
|
|
DWORD dwNumFeatures, dwFea, dwStart, dwI, dwDestTail,
|
|
dwDest, dwSrcTail, dwNumOpts, dwNEnabled, dwJ ;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
PDWORD pdwPriority ;
|
|
BOOL bStatus = FALSE, bUnresolvedConflict = FALSE ,
|
|
bEnable = FALSE ; // feature will constrain others
|
|
PBOOL pbUseConstrnt, pbEnabledOptions, pbSelectedOptions ;
|
|
INT iOptionsNeeded;
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
|
|
|
|
#ifdef GMACROS
|
|
if(!ResolveDependentSettings( pnRawData, pOptions, iMaxOptions) )
|
|
return(FALSE);
|
|
#endif
|
|
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
pdwPriority = (PDWORD)(pubRaw +
|
|
pearTableContents[MTI_PRIORITYARRAY].loOffset) ;
|
|
|
|
dwNumFeatures = pearTableContents[MTI_DFEATURE_OPTIONS].dwCount ;
|
|
dwNumFeatures += pearTableContents[MTI_SYNTHESIZED_FEATURES].dwCount ;
|
|
|
|
if(dwNumFeatures > (DWORD)iMaxOptions)
|
|
{
|
|
iOptionsNeeded = dwNumFeatures ;
|
|
return(FALSE); // too many to save in option array.
|
|
}
|
|
|
|
#if 0
|
|
pbUseConstrnt = (PBOOL)MemAlloc(dwNumFeatures * sizeof(BOOL) ) ;
|
|
pbEnabledOptions = (PBOOL)MemAlloc(256 * sizeof(BOOL) ) ;
|
|
pbSelectedOptions = (PBOOL)MemAlloc(256 * sizeof(BOOL) ) ;
|
|
#endif
|
|
|
|
pbSelectedOptions = (PBOOL)MemAlloc((256*2 + dwNumFeatures) * sizeof(BOOL) ) ;
|
|
// this is the union of the allowable selections
|
|
// and what was actually selected in pOptions for this feature.
|
|
// BUG_BUG: assumes we won't have more than 256 options
|
|
|
|
pbEnabledOptions = pbSelectedOptions + 256 ;
|
|
// these are the allowable selections
|
|
pbUseConstrnt = pbEnabledOptions + 256 ;
|
|
|
|
if(!(pbUseConstrnt && pbEnabledOptions && pbSelectedOptions ))
|
|
{
|
|
ERR(("Fatal: ResolveUIConflicts - unable to alloc requested memory: %d bytes.\n",
|
|
dwNumFeatures * sizeof(BOOL)));
|
|
goto ABORTRESOLVEUICONFLICTS ;
|
|
}
|
|
|
|
for(dwI = 0 ; dwI < dwNumFeatures ; dwI++)
|
|
pbUseConstrnt[dwI] = FALSE ;
|
|
|
|
|
|
for(dwNEnabled = dwI = 0 ; dwI < dwNumFeatures ; dwI++)
|
|
{
|
|
// The order of evaluation is determined
|
|
// by the priority array.
|
|
|
|
dwFea = pdwPriority[dwI] ;
|
|
|
|
bEnable = FALSE ;
|
|
|
|
if(iMode == MODE_DOCANDPRINTER_STICKY)
|
|
bEnable = TRUE ;
|
|
else
|
|
{
|
|
DWORD dwFeatureType = FT_PRINTERPROPERTY, dwNextOpt, dwUnresolvedFeature ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
|
|
// is this a printer or doc sticky feature?
|
|
|
|
|
|
patrRoot = &(pfo[dwFea].atrFeatureType) ;
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSFeatureTypeIndex,
|
|
(PBYTE)&dwFeatureType,
|
|
&dwUnresolvedFeature, *patrRoot, pOptions,
|
|
0, // set to any value. Doesn't matter.
|
|
&dwNextOpt) != TRI_SUCCESS)
|
|
{
|
|
ERR(("ResolveUIConflicts: EextractValueFromTree failed.\n"));
|
|
bUnresolvedConflict = TRUE ;
|
|
goto ABORTRESOLVEUICONFLICTS ; // return(FALSE) ;
|
|
}
|
|
|
|
if(dwFeatureType != FT_PRINTERPROPERTY)
|
|
{
|
|
if(iMode == MODE_DOCUMENT_STICKY)
|
|
bEnable = TRUE ;
|
|
}
|
|
else
|
|
{
|
|
if(iMode == MODE_PRINTER_STICKY)
|
|
bEnable = TRUE ;
|
|
}
|
|
}
|
|
|
|
if(bEnable) // Feature is to be applied as constraint
|
|
{
|
|
pbUseConstrnt[dwFea] = TRUE ;
|
|
dwNEnabled++ ;
|
|
}
|
|
else
|
|
continue ; // not interested in this feature
|
|
if(dwNEnabled < 2)
|
|
continue ; // not enough Features enabled
|
|
// to constrain each other.
|
|
|
|
bStatus = BSelectivelyEnumEnabledOptions(
|
|
pnRawData,
|
|
pOptions,
|
|
dwFea,
|
|
pbUseConstrnt, // if non NULL
|
|
pbEnabledOptions,
|
|
0,
|
|
NULL // pConflictPair
|
|
) ;
|
|
|
|
|
|
dwNumOpts = pfo[dwFea].dwNumOptions ;
|
|
|
|
for(dwJ = 0 ; dwJ < dwNumOpts ; dwJ++)
|
|
pbSelectedOptions[dwJ] = FALSE ;
|
|
|
|
if(!bStatus)
|
|
{
|
|
pbSelectedOptions[0] = TRUE ;
|
|
// just set this to a harmless value.
|
|
}
|
|
else
|
|
{
|
|
DWORD dwNext = dwFea ;
|
|
while(1)
|
|
{
|
|
if(pbEnabledOptions[pOptions[dwNext].ubCurOptIndex])
|
|
pbSelectedOptions[pOptions[dwNext].ubCurOptIndex] = TRUE ;
|
|
dwNext = pOptions[dwNext].ubNext ;
|
|
if(!dwNext)
|
|
break ; // end of list of options.
|
|
}
|
|
}
|
|
|
|
for(dwJ = 0 ; dwJ < dwNumOpts ; dwJ++)
|
|
{
|
|
if(pbSelectedOptions[dwJ])
|
|
break ; // is anything actually selected?
|
|
}
|
|
if(dwJ >= dwNumOpts)
|
|
{
|
|
DWORD dwDefaultOption, dwNextOpt, dwUnresolvedFeature ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
|
|
|
|
// none of the original selections survived
|
|
// see if the default option can be used.
|
|
// first, determine the index of the default option.
|
|
|
|
patrRoot = &(pfo[dwFea].atrDefaultOption) ;
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSdefaultOptionIndex,
|
|
(PBYTE)&dwDefaultOption,
|
|
&dwUnresolvedFeature, *patrRoot, pOptions,
|
|
0, // set to any value. Doesn't matter.
|
|
&dwNextOpt) == TRI_SUCCESS &&
|
|
pbEnabledOptions[dwDefaultOption])
|
|
{
|
|
pbSelectedOptions[dwDefaultOption] = TRUE ;
|
|
}
|
|
else // randomly pick something that isn't constrained.
|
|
{
|
|
if(!dwFea) // hack for synthesized Inputslot.
|
|
pbEnabledOptions[0] = FALSE ; // never allow autoselect to be selected
|
|
// if it wasn't initially selected. bug 100722
|
|
|
|
for(dwJ = 0 ; dwJ < dwNumOpts ; dwJ++)
|
|
{
|
|
if(pbEnabledOptions[dwJ])
|
|
break ;
|
|
}
|
|
if(dwJ >= dwNumOpts)
|
|
{
|
|
ERR(("ResolveUIConflicts: Constraints prevent any option from being selected!\n"));
|
|
pbSelectedOptions[0] = TRUE ; // ignoring constraint.
|
|
bUnresolvedConflict = TRUE ;
|
|
}
|
|
else
|
|
pbSelectedOptions[dwJ] = TRUE ; // Picked one.
|
|
}
|
|
}
|
|
|
|
bStatus = ReconstructOptionArray(
|
|
pnRawData,
|
|
pOptions,
|
|
iMaxOptions,
|
|
dwFea,
|
|
pbSelectedOptions) ;
|
|
if(!bStatus)
|
|
{
|
|
ERR(("ResolveUIConflicts: ReconstructOptionArray failed.\n"));
|
|
bUnresolvedConflict = TRUE ;
|
|
}
|
|
} // end of processing for this feature
|
|
|
|
ABORTRESOLVEUICONFLICTS:
|
|
#if 0
|
|
if(pbUseConstrnt)
|
|
MemFree(pbUseConstrnt) ;
|
|
if(pbEnabledOptions)
|
|
MemFree(pbEnabledOptions) ;
|
|
#endif
|
|
if(pbSelectedOptions)
|
|
MemFree(pbSelectedOptions) ;
|
|
|
|
return(!bUnresolvedConflict);
|
|
}
|
|
|
|
BOOL
|
|
EnumEnabledOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
OUT PBOOL pbEnabledOptions ,
|
|
IN INT iMode
|
|
// either MODE_DOCANDPRINTER_STICKY or MODE_PRINTER_STICKY
|
|
)
|
|
{
|
|
#ifndef KERNEL_MODE
|
|
|
|
if(iMode == MODE_PRINTER_STICKY)
|
|
{
|
|
return(EnumOptionsUnconstrainedByPrinterSticky(
|
|
pnRawData,
|
|
pOptions,
|
|
dwFeatureIndex,
|
|
pbEnabledOptions
|
|
) ) ;
|
|
}
|
|
else
|
|
{
|
|
return(BSelectivelyEnumEnabledOptions(
|
|
pnRawData,
|
|
pOptions,
|
|
dwFeatureIndex,
|
|
NULL, // pbHonorConstraints
|
|
pbEnabledOptions,
|
|
0, // dwOptSel
|
|
NULL) ) ;
|
|
}
|
|
#else
|
|
RIP(("GpdEnumEnabledOptions not implemented in Kernel Mode")) ;
|
|
return(FALSE);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
EnumOptionsUnconstrainedByPrinterSticky(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
OUT PBOOL pbEnabledOptions
|
|
)
|
|
{
|
|
DWORD dwNumFeatures, dwFea, dwI, dwNumOpts, dwNEnabled, dwJ ;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
BOOL bStatus = FALSE ;
|
|
PBOOL pbUseConstrnt ;
|
|
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
|
|
dwNumFeatures = pearTableContents[MTI_DFEATURE_OPTIONS].dwCount ;
|
|
dwNumFeatures += pearTableContents[MTI_SYNTHESIZED_FEATURES].dwCount ;
|
|
|
|
pbUseConstrnt = (PBOOL)MemAlloc(dwNumFeatures * sizeof(BOOL) ) ;
|
|
|
|
if(!pbUseConstrnt)
|
|
{
|
|
ERR(("Fatal: EnumOptionsUnconstrainedByPrinterSticky - unable to alloc requested memory: %d bytes.\n",
|
|
dwNumFeatures * sizeof(BOOL)));
|
|
goto ABORTENUMOPTIONSUNCONSTRAINEDBYPRINTERSTICKY ;
|
|
}
|
|
|
|
for(dwI = 0 ; dwI < dwNumFeatures ; dwI++)
|
|
pbUseConstrnt[dwI] = FALSE ;
|
|
|
|
|
|
for(dwNEnabled = dwFea = 0 ; dwFea < dwNumFeatures ; dwFea++)
|
|
{
|
|
DWORD dwFeatureType = FT_PRINTERPROPERTY,
|
|
dwNextOpt, dwUnresolvedFeature ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
|
|
|
|
// is this a printer or doc sticky feature?
|
|
|
|
|
|
patrRoot = &(pfo[dwFea].atrFeatureType) ;
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSFeatureTypeIndex,
|
|
(PBYTE)&dwFeatureType,
|
|
&dwUnresolvedFeature, *patrRoot, pOptions,
|
|
0, // set to any value. Doesn't matter.
|
|
&dwNextOpt) != TRI_SUCCESS)
|
|
{
|
|
ERR(("ResolveUIConflicts: EextractValueFromTree failed.\n"));
|
|
bStatus = FALSE ;
|
|
goto ABORTENUMOPTIONSUNCONSTRAINEDBYPRINTERSTICKY ;
|
|
}
|
|
|
|
|
|
if(dwFeatureType == FT_PRINTERPROPERTY)
|
|
{
|
|
pbUseConstrnt[dwFea] = TRUE ;
|
|
dwNEnabled++ ;
|
|
}
|
|
}
|
|
|
|
|
|
if(!pbUseConstrnt[dwFeatureIndex]) // queried feature isn't PrinterSticky
|
|
{
|
|
pbUseConstrnt[dwFeatureIndex] = TRUE ;
|
|
dwNEnabled++ ;
|
|
}
|
|
|
|
if(dwNEnabled < 2)
|
|
{
|
|
dwNumOpts = pfo[dwFeatureIndex].dwNumOptions ;
|
|
|
|
for(dwJ = 0 ; dwJ < dwNumOpts ; dwJ++)
|
|
pbEnabledOptions[dwJ] = TRUE ;
|
|
|
|
bStatus = TRUE ; // not enough Features enabled
|
|
// to constrain each other.
|
|
}
|
|
else
|
|
{
|
|
bStatus = BSelectivelyEnumEnabledOptions(
|
|
pnRawData,
|
|
pOptions,
|
|
dwFeatureIndex,
|
|
pbUseConstrnt, // if non NULL
|
|
pbEnabledOptions,
|
|
0,
|
|
NULL // pConflictPair
|
|
) ;
|
|
}
|
|
|
|
ABORTENUMOPTIONSUNCONSTRAINEDBYPRINTERSTICKY:
|
|
if(pbUseConstrnt)
|
|
MemFree(pbUseConstrnt) ;
|
|
|
|
return(bStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
EnumNewUIConflict(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN PBOOL pbSelectedOptions,
|
|
OUT PCONFLICTPAIR pConflictPair
|
|
)
|
|
{
|
|
#ifndef KERNEL_MODE
|
|
|
|
|
|
BSelectivelyEnumEnabledOptions(
|
|
pnRawData,
|
|
pOptions,
|
|
dwFeatureIndex,
|
|
NULL,
|
|
pbSelectedOptions,
|
|
0, // dwOptSel
|
|
pConflictPair ) ;
|
|
|
|
|
|
return (pConflictPair->dwFeatureIndex1 != 0xFFFFFFFF);
|
|
#else
|
|
RIP(("GpdEnumNewUIConflict not implemented in Kernel Mode")) ;
|
|
return(FALSE);
|
|
#endif
|
|
}
|
|
|
|
BOOL
|
|
EnumNewPickOneUIConflict(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN DWORD dwOptionIndex,
|
|
OUT PCONFLICTPAIR pConflictPair
|
|
)
|
|
{
|
|
#ifndef KERNEL_MODE
|
|
|
|
BSelectivelyEnumEnabledOptions(
|
|
pnRawData,
|
|
pOptions,
|
|
dwFeatureIndex,
|
|
NULL,
|
|
NULL, // pbSelectedOptions
|
|
dwOptionIndex,
|
|
pConflictPair ) ;
|
|
|
|
return (pConflictPair->dwFeatureIndex1 != 0xFFFFFFFF);
|
|
#else
|
|
RIP(("GpdEnumNewPickOneUIConflict not implemented in Kernel Mode")) ;
|
|
return(FALSE);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
BIsFeaOptionCurSelected(
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN DWORD dwOptionIndex
|
|
)
|
|
/*
|
|
returns TRUE if the specified Feature/Option is
|
|
currently selected in pOptions. FALSE otherwise.
|
|
*/
|
|
{
|
|
DWORD dwSrcTail ;
|
|
|
|
if(pOptions[dwFeatureIndex].ubCurOptIndex == dwOptionIndex)
|
|
return(TRUE);
|
|
|
|
dwSrcTail = pOptions[dwFeatureIndex].ubNext ;
|
|
|
|
while(dwSrcTail) // PickMany options
|
|
{
|
|
if(pOptions[dwSrcTail].ubCurOptIndex == dwOptionIndex)
|
|
return(TRUE);
|
|
dwSrcTail = pOptions[dwSrcTail].ubNext ;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
BSelectivelyEnumEnabledOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN POPTSELECT pOptions,
|
|
IN DWORD dwFeatureIndex,
|
|
IN PBOOL pbHonorConstraints, // if non NULL
|
|
// points to array of BOOL corresponding to each feature.
|
|
// if TRUE means constraint involving this feature is
|
|
// to be honored. Otherwise ignore the constraint.
|
|
OUT PBOOL pbEnabledOptions, // assume uninitialized
|
|
// if pConflictPair is NULL else contains current or proposed
|
|
// selections. We will leave this array unchanged in this case.
|
|
IN DWORD dwOptSel, // if pConflictPair exists but pbEnabledOptions
|
|
// is NULL, assume pickone and dwOptSel holds that selection for
|
|
// the feature: dwFeatureIndex.
|
|
OUT PCONFLICTPAIR pConflictPair // if present, pbEnabledOptions
|
|
// actually lists the current selections. Function then
|
|
// exits after encountering the first conflict.
|
|
// if a conflict exists, all fields in pConflictPair
|
|
// will be properly initialized else dwFeatureIndex1 = -1
|
|
// the return value will be TRUE regardless.
|
|
)
|
|
/*
|
|
return value is FALSE if every option for this
|
|
feature is constrained or other abnormal condition
|
|
was encountered.
|
|
|
|
*/
|
|
{
|
|
PDFEATURE_OPTIONS pfo ;
|
|
PBYTE pubHeap , // start of string heap.
|
|
pubRaw ; // raw binary data.
|
|
PENHARRAYREF pearTableContents ;
|
|
DWORD dwI, dwNumFea , dwNumOpts, dwFea, dwSrcTail, dwNodeIndex,
|
|
dwCFeature, dwCOption ,
|
|
dwCNode, dwICNode, dwNextInvCombo;
|
|
BOOL bStatus, bConstrained, bNextLinkFound ;
|
|
PATTRIB_TREE patt ; // start of ATTRIBUTE tree array.
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
PCONSTRAINTS pcnstr ; // root of Constraint nodes
|
|
PINVALIDCOMBO pinvc ; // root of invalid combo nodes
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
BOOL pbNewEnabledOptions[MAX_COMBINED_OPTIONS] ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
patt = (PATTRIB_TREE)(pubRaw +
|
|
pearTableContents[MTI_ATTRIBTREE].loOffset) ;
|
|
pcnstr = (PCONSTRAINTS) (pubRaw +
|
|
pearTableContents[MTI_CONSTRAINTS].loOffset) ;
|
|
pinvc = (PINVALIDCOMBO) (pubRaw +
|
|
pearTableContents[MTI_INVALIDCOMBO].loOffset) ;
|
|
pubHeap = (PBYTE)(pubRaw + pearTableContents[MTI_STRINGHEAP].
|
|
loOffset) ;
|
|
|
|
|
|
dwNumFea = pRawData->dwDocumentFeatures +
|
|
pRawData->dwPrinterFeatures ;
|
|
|
|
dwNumOpts = pfo[dwFeatureIndex].dwNumOptions ;
|
|
|
|
|
|
if(pConflictPair)
|
|
{
|
|
pConflictPair->dwFeatureIndex1 = dwFeatureIndex ;
|
|
pConflictPair->dwFeatureIndex2 = 0xFFFFFFFF;
|
|
// Gets set to indicate we have a constraint.
|
|
// leave pbEnabledOptions as is. These are
|
|
// the options currently selected for this feature.
|
|
|
|
#if 0
|
|
if(!(pbNewEnabledOptions = (PBOOL)MemAlloc(dwNumOpts * sizeof(BOOL) ) ))
|
|
{
|
|
ERR(("Fatal: BSelectivelyEnumEnabledOptions - unable to alloc %d bytes.\n",
|
|
dwNumOpts * sizeof(BOOL) ));
|
|
return(FALSE) ;
|
|
}
|
|
#endif
|
|
|
|
if(pbEnabledOptions)
|
|
{
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
pbNewEnabledOptions[dwI] = pbEnabledOptions[dwI] ;
|
|
}
|
|
else
|
|
{
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
pbNewEnabledOptions[dwI] = FALSE ;
|
|
pbNewEnabledOptions[dwOptSel] = TRUE ;
|
|
}
|
|
|
|
pbEnabledOptions = pbNewEnabledOptions ; // forget the original.
|
|
}
|
|
else
|
|
{
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
pbEnabledOptions[dwI] = TRUE ;
|
|
}
|
|
|
|
if(!pbEnabledOptions)
|
|
{
|
|
RIP(("BSelectivelyEnumEnabledOptions: pbEnabledOptions is NULL")) ;
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
for(dwFea = 0 ; dwFea < dwNumFea ; dwFea++)
|
|
{
|
|
if(dwFea == dwFeatureIndex)
|
|
continue ;
|
|
if(pbHonorConstraints && !pbHonorConstraints[dwFea])
|
|
continue ;
|
|
|
|
bStatus = BEnumImposedConstraintsOnFeature(pnRawData, dwFeatureIndex,
|
|
dwFea, pOptions[dwFea].ubCurOptIndex, pbEnabledOptions, pConflictPair) ;
|
|
if(pConflictPair && pConflictPair->dwFeatureIndex2 != 0xFFFFFFFF)
|
|
{
|
|
// MemFree(pbEnabledOptions) ;
|
|
return(TRUE) ; // Meaningless return value.
|
|
}
|
|
|
|
dwSrcTail = pOptions[dwFea].ubNext ;
|
|
|
|
while(dwSrcTail) // PickMany options
|
|
{
|
|
if(!BEnumImposedConstraintsOnFeature(pnRawData, dwFeatureIndex,
|
|
dwFea, pOptions[dwSrcTail].ubCurOptIndex, pbEnabledOptions,
|
|
pConflictPair) )
|
|
bStatus = FALSE;
|
|
if(pConflictPair && pConflictPair->dwFeatureIndex2 != 0xFFFFFFFF)
|
|
{
|
|
// MemFree(pbEnabledOptions) ;
|
|
return(TRUE) ; // Meaningless return value.
|
|
}
|
|
dwSrcTail = pOptions[dwSrcTail].ubNext ;
|
|
}
|
|
}
|
|
|
|
patrRoot = &(pfo[dwFeatureIndex].atrConstraints) ;
|
|
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
if(!pbEnabledOptions[dwI])
|
|
continue ;
|
|
dwNodeIndex = DwFindNodeInCurLevel(patt , patrRoot , dwI) ;
|
|
|
|
if(dwNodeIndex == INVALID_INDEX)
|
|
continue ; // this option has no constraints
|
|
if(patt[dwNodeIndex].eOffsetMeans != VALUE_AT_HEAP)
|
|
{
|
|
ERR(("Internal error. BSelectivelyEnumEnabledOptions - Unexpected Sublevel found for atrConstraints.\n"));
|
|
continue ; // skip this anomaly
|
|
}
|
|
dwCNode = *(PDWORD)(pubHeap + patt[dwNodeIndex].dwOffset) ;
|
|
|
|
if(BIsConstraintActive(pcnstr , dwCNode, pbHonorConstraints, pOptions, pConflictPair) )
|
|
{
|
|
pbEnabledOptions[dwI] = FALSE ;
|
|
if(pConflictPair)
|
|
{
|
|
// MemFree(pbEnabledOptions) ;
|
|
pConflictPair->dwOptionIndex1 = dwI ;
|
|
return(TRUE) ; // Meaningless return value.
|
|
}
|
|
}
|
|
}
|
|
|
|
// lastly must walk InvalidCombos for each option of dwFeatureIndex
|
|
// and mark pbEnabledOptions accordingly.
|
|
|
|
patrRoot = &(pfo[dwFeatureIndex].atrInvalidCombos) ;
|
|
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
if(!pbEnabledOptions[dwI])
|
|
continue ;
|
|
|
|
dwNodeIndex = DwFindNodeInCurLevel(patt , patrRoot , dwI) ;
|
|
|
|
if(dwNodeIndex == INVALID_INDEX)
|
|
continue ; // this option has no invalid combos
|
|
if(patt[dwNodeIndex].eOffsetMeans != VALUE_AT_HEAP)
|
|
{
|
|
ERR(("Internal error. BSelectivelyEnumEnabledOptions - Unexpected Sublevel found for atrInvalidCombos.\n"));
|
|
continue ; // skip this anomaly
|
|
}
|
|
dwICNode = patt[dwNodeIndex].dwOffset ;
|
|
|
|
while(dwICNode != END_OF_LIST)
|
|
// search through each applicable invalid combo
|
|
{
|
|
dwNextInvCombo = END_OF_LIST ; // fail safe - stop
|
|
// search in the event this invalid combo doesn't
|
|
// contain dwFeatureIndex/dwI
|
|
bConstrained = TRUE ; // Assume true initially
|
|
bNextLinkFound = FALSE ;
|
|
while(dwICNode != END_OF_LIST)
|
|
// for each element comprising the invalid combo
|
|
{
|
|
if(!bNextLinkFound &&
|
|
pinvc[dwICNode].dwFeature == dwFeatureIndex &&
|
|
(pinvc[dwICNode].dwOption == dwI ||
|
|
(WORD)pinvc[dwICNode].dwOption == (WORD)DEFAULT_INIT))
|
|
{
|
|
dwNextInvCombo = pinvc[dwICNode].dwNewCombo ;
|
|
bNextLinkFound = TRUE ;
|
|
// we are just asking if this option was selected
|
|
// will it trigger an invalid combo?
|
|
// this means currently this option is not selected
|
|
// but we want to pretend for the purposes of
|
|
// evaluating invalid combos that it is.
|
|
// this is why an else if() statement follows.
|
|
}
|
|
else if(bConstrained && ((pbHonorConstraints &&
|
|
!pbHonorConstraints[pinvc[dwICNode].dwFeature])
|
|
|| !BIsFeaOptionCurSelected(pOptions,
|
|
pinvc[dwICNode].dwFeature,
|
|
pinvc[dwICNode].dwOption) ) )
|
|
{
|
|
bConstrained = FALSE ;
|
|
}
|
|
else if(pConflictPair)
|
|
{
|
|
// need to remember one of the constrainers
|
|
// so we can emit a warning message.
|
|
dwCFeature = pinvc[dwICNode].dwFeature ;
|
|
dwCOption = pinvc[dwICNode].dwOption ;
|
|
}
|
|
|
|
if(!bConstrained && bNextLinkFound)
|
|
break ; // no need to keep traversing elements
|
|
// in this invalid combo.
|
|
dwICNode = pinvc[dwICNode].dwNextElement ;
|
|
}
|
|
if(bConstrained)
|
|
{
|
|
pbEnabledOptions[dwI] = FALSE ;
|
|
|
|
if(pConflictPair)
|
|
{
|
|
pConflictPair->dwOptionIndex1 = dwI ;
|
|
pConflictPair->dwFeatureIndex2 = dwCFeature ;
|
|
pConflictPair->dwOptionIndex2 = dwCOption ;
|
|
|
|
// MemFree(pbEnabledOptions) ;
|
|
return(TRUE) ; // Meaningless return value.
|
|
}
|
|
|
|
break ; // no need to see if any other invalid
|
|
// combos apply. One is enough.
|
|
}
|
|
dwICNode = dwNextInvCombo ;
|
|
}
|
|
}
|
|
if(pConflictPair)
|
|
{
|
|
pConflictPair->dwFeatureIndex1 = 0xFFFFFFFF ;
|
|
// no constraints found.
|
|
// MemFree(pbEnabledOptions) ;
|
|
return(TRUE) ; // Meaningless return value.
|
|
}
|
|
for(dwI = 0 ; dwI < dwNumOpts ; dwI++)
|
|
{
|
|
if(pbEnabledOptions[dwI])
|
|
break ;
|
|
}
|
|
if(dwI >= dwNumOpts)
|
|
bStatus = FALSE ; // Feature is disabled.
|
|
return(bStatus) ;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BEnumImposedConstraintsOnFeature
|
|
(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN DWORD dwTgtFeature,
|
|
IN DWORD dwFeature2,
|
|
IN DWORD dwOption2,
|
|
OUT PBOOL pbEnabledOptions,
|
|
OUT PCONFLICTPAIR pConflictPair // if present, pbEnabledOptions
|
|
)
|
|
/*
|
|
This function only searches for the unidirctional
|
|
constraints found at dwFeature2, dwOption2 and
|
|
records their effect on the options of feature1 by
|
|
setting to FALSE the BOOL element in pbEnabledOptions
|
|
corresponding to the option disabled.
|
|
(ANDing mask)
|
|
Assumes: pbEnabledOptions is properly initialized to all
|
|
TRUE (or was that way at some point.) This function never
|
|
sets any elements TRUE. Only sets some elements FALSE.
|
|
*/
|
|
{
|
|
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
// PMINIRAWBINARYDATA pmrbd ;
|
|
PBYTE pubHeap , // start of string heap.
|
|
pubRaw ; // raw binary data.
|
|
DWORD dwNodeIndex ,
|
|
dwCNode ; // index to a Constraint node
|
|
PATTRIB_TREE patt ; // start of ATTRIBUTE tree array.
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
// PINVALIDCOMBO pinvc ; // root of invalid combo nodes
|
|
PCONSTRAINTS pcnstr ; // root of Constraint nodes
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
patt = (PATTRIB_TREE)(pubRaw +
|
|
pearTableContents[MTI_ATTRIBTREE].loOffset) ;
|
|
// pinvc = (PINVALIDCOMBO) (pubRaw +
|
|
// pearTableContents[MTI_INVALIDCOMBO].loOffset) ;
|
|
pcnstr = (PCONSTRAINTS) (pubRaw +
|
|
pearTableContents[MTI_CONSTRAINTS].loOffset) ;
|
|
pubHeap = (PBYTE)(pubRaw + pearTableContents[MTI_STRINGHEAP].
|
|
loOffset) ;
|
|
|
|
|
|
|
|
patrRoot = &(pfo[dwFeature2].atrConstraints) ;
|
|
|
|
dwNodeIndex = DwFindNodeInCurLevel(patt , patrRoot , dwOption2) ;
|
|
|
|
if(dwNodeIndex == INVALID_INDEX)
|
|
return(TRUE) ; // no imposed constraints found
|
|
|
|
if(patt[dwNodeIndex].eOffsetMeans != VALUE_AT_HEAP)
|
|
{
|
|
ERR(("Internal error. BEnumImposedConstraintsOnFeature - Unexpected Sublevel found for atrConstraints.\n"));
|
|
return(FALSE) ;
|
|
}
|
|
|
|
dwCNode = *(PDWORD)(pubHeap + patt[dwNodeIndex].dwOffset) ;
|
|
|
|
while(1)
|
|
{
|
|
if(pcnstr[dwCNode].dwFeature == dwTgtFeature &&
|
|
pbEnabledOptions[pcnstr[dwCNode].dwOption] == TRUE )
|
|
{
|
|
pbEnabledOptions[pcnstr[dwCNode].dwOption] = FALSE ;
|
|
// this option in dwTgtFeature is constrained.
|
|
if(pConflictPair)
|
|
{
|
|
pConflictPair->dwOptionIndex1 = pcnstr[dwCNode].dwOption ;
|
|
pConflictPair->dwFeatureIndex2 = dwFeature2 ;
|
|
pConflictPair->dwOptionIndex2 = dwOption2 ;
|
|
return(TRUE) ; // Meaningless return value.
|
|
}
|
|
}
|
|
|
|
dwCNode = pcnstr[dwCNode].dwNextCnstrnt ;
|
|
if(dwCNode == END_OF_LIST)
|
|
break ;
|
|
}
|
|
|
|
return(TRUE) ; // nothing bad happened.
|
|
}
|
|
|
|
DWORD DwFindNodeInCurLevel(
|
|
PATTRIB_TREE patt , // start of ATTRIBUTE tree array.
|
|
PATREEREF patr , // index to a level in the attribute tree.
|
|
DWORD dwOption // search current level for this option
|
|
)
|
|
|
|
/*
|
|
this function returns the node index to the node containing
|
|
the specified dwOption in the selected level of the tree.
|
|
If the specified option branch does not exist, the function returns
|
|
INVALID_INDEX.
|
|
Assumes caller has verified dwFeature matches.
|
|
*/
|
|
{
|
|
DWORD dwNodeIndex ;
|
|
|
|
if(*patr == ATTRIB_UNINITIALIZED)
|
|
return(INVALID_INDEX) ;
|
|
|
|
if(*patr & ATTRIB_HEAP_VALUE)
|
|
{
|
|
ERR(("Internal error. DwFindNodeInCurLevel - Unexpected branchless node found.\n"));
|
|
return(INVALID_INDEX) ;
|
|
}
|
|
|
|
// search for matching option.
|
|
|
|
dwNodeIndex = *patr ;
|
|
|
|
while(1)
|
|
{
|
|
if(patt[dwNodeIndex].dwOption == dwOption )
|
|
{
|
|
// we found it!
|
|
return(dwNodeIndex) ;
|
|
}
|
|
if(patt[dwNodeIndex].dwNext == END_OF_LIST)
|
|
break ;
|
|
dwNodeIndex = patt[dwNodeIndex].dwNext ;
|
|
}
|
|
return(INVALID_INDEX) ;
|
|
}
|
|
|
|
|
|
BOOL BIsConstraintActive(
|
|
IN PCONSTRAINTS pcnstr , // root of Constraint nodes
|
|
IN DWORD dwCNode, // first constraint node in list.
|
|
IN PBOOL pbHonorConstraints, // if non NULL
|
|
IN POPTSELECT pOptions,
|
|
OUT PCONFLICTPAIR pConflictPair )
|
|
/*
|
|
This function walks the list of constraint nodes
|
|
starting at dwNodeIndex and checks to see if the
|
|
Feature/Option specified within is in fact currently
|
|
selected in pOptions. If yes, immediately return true.
|
|
If not, go to the next node in the list and repeat.
|
|
*/
|
|
{
|
|
while(1)
|
|
{
|
|
if(!pbHonorConstraints || pbHonorConstraints[pcnstr[dwCNode].dwFeature])
|
|
{
|
|
if(BIsFeaOptionCurSelected(pOptions,
|
|
pcnstr[dwCNode].dwFeature,
|
|
pcnstr[dwCNode].dwOption) )
|
|
{
|
|
if(pConflictPair)
|
|
{
|
|
pConflictPair->dwFeatureIndex2 = pcnstr[dwCNode].dwFeature;
|
|
pConflictPair->dwOptionIndex2 = pcnstr[dwCNode].dwOption ;
|
|
}
|
|
return(TRUE) ; // a constraint does exist.
|
|
}
|
|
}
|
|
|
|
dwCNode = pcnstr[dwCNode].dwNextCnstrnt ;
|
|
if(dwCNode == END_OF_LIST)
|
|
break ;
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
#ifdef GMACROS
|
|
|
|
// note: must precede calls to ResolveUIConflict
|
|
// with a call to ResolveDependentSettings
|
|
|
|
BOOL
|
|
ResolveDependentSettings(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions
|
|
)
|
|
// Note this function does handle multiple selections
|
|
// it will treat them as additional links in the chain.
|
|
{
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
PLISTNODE plstRoot ; // start of LIST array
|
|
DWORD dwListsRoot, dwListIndex; // Root of the chain
|
|
DWORD dwNumFeatures, dwI, dwJ, dwFea, dwNodeIndex,
|
|
dwFeature, dwOption ;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
PDWORD pdwPriority ;
|
|
PQUALNAME pqn ; // the dword in the list node is actually a
|
|
// qualified name structure.
|
|
INT iOptionsNeeded;
|
|
PBOOL pbOneShotFlag, pbSelectedOptions ;
|
|
BOOL bMatchFound ; // a DependentSettings matches the current config.
|
|
POPTSELECT pDestOptions ;
|
|
BOOL bStatus = TRUE ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
pdwPriority = (PDWORD)(pubRaw +
|
|
pearTableContents[MTI_PRIORITYARRAY].loOffset) ;
|
|
|
|
plstRoot = (PLISTNODE)(pubRaw + pearTableContents[MTI_LISTNODES].
|
|
loOffset) ;
|
|
|
|
dwNumFeatures = pearTableContents[MTI_DFEATURE_OPTIONS].dwCount ;
|
|
dwNumFeatures += pearTableContents[MTI_SYNTHESIZED_FEATURES].dwCount ;
|
|
|
|
if(dwNumFeatures > (DWORD)iMaxOptions)
|
|
{
|
|
iOptionsNeeded = dwNumFeatures ;
|
|
return(FALSE); // too many to save in option array.
|
|
}
|
|
|
|
pbOneShotFlag = (PBOOL)MemAlloc(dwNumFeatures * sizeof(BOOL) ) ;
|
|
pbSelectedOptions = (PBOOL)MemAlloc(iMaxOptions * sizeof(BOOL) ) ;
|
|
// iMaxOptions must be greater than the max number of options availible for
|
|
// any feature.
|
|
|
|
|
|
// to extend to pickmany, have a dest optionarray.
|
|
// each time the source optionarray completely contains
|
|
// a DependentSettings list (in that each Fea.Option
|
|
// listed as a DependentSetting is also selected in the
|
|
// source option array) we turn on those Fea.Options
|
|
// in the dest option array. After all DependentSettings
|
|
// lists for that feature have been processed, we set
|
|
// the OneShotFlag for each Feature that has been affected
|
|
// in the dest option array. For each such feature we will
|
|
// let the dest option array determine the setting of the
|
|
// source option array.
|
|
// this code does not verify that a Feature is pickmany
|
|
// before treating it as pickmany. If the source option
|
|
// array has more than one option selected for a feature,
|
|
// that feature is automatically treated as a pickmany.
|
|
|
|
|
|
pDestOptions = (POPTSELECT)MemAlloc(iMaxOptions * sizeof(OPTSELECT) ) ;
|
|
// 'or' all acceptable DependentSettings here.
|
|
|
|
if(!(pbOneShotFlag && pDestOptions && pbSelectedOptions))
|
|
{
|
|
ERR(("Fatal: ResolveDependentSettings - unable to alloc requested memory: %d bytes.\n",
|
|
dwNumFeatures * sizeof(BOOL)));
|
|
bStatus = FALSE ;
|
|
goto ABORTRESOLVEDEPENDENTSETTINGS ;
|
|
}
|
|
|
|
for(dwI = 0 ; dwI < dwNumFeatures ; dwI++)
|
|
pbOneShotFlag[dwI] = FALSE ;
|
|
// this boolean array tracks if the feature has been
|
|
// referenced in a DependentSettings entry.
|
|
// If a feature is referenced again in DependentSettings
|
|
// entry belonging to another feature, the subsequent
|
|
// references will be ignored. This ensures only the
|
|
// highest priority Feature's request shall have precedence.
|
|
|
|
|
|
for(dwI = 0 ; dwI < dwNumFeatures ; dwI++)
|
|
{
|
|
DWORD dwNextOpt, dwListsRootOpt1 ;
|
|
// The order of evaluation is determined
|
|
// by the priority array.
|
|
|
|
|
|
dwFea = pdwPriority[dwI] ;
|
|
pbOneShotFlag[dwFea] = TRUE ;
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
dwListsRootOpt1 = END_OF_LIST ; // list for the 1st selected
|
|
// option of a pickmany feature.
|
|
|
|
for( dwJ = 0 ; dwJ < dwNumFeatures ; dwJ++)
|
|
{
|
|
pDestOptions[dwJ].ubCurOptIndex = OPTION_INDEX_ANY ;
|
|
pDestOptions[dwJ].ubNext = 0 ; // eol
|
|
// DestOptions is now blank.
|
|
}
|
|
|
|
bMatchFound = FALSE ;
|
|
|
|
|
|
do
|
|
{ // for each option selected in a pick many feature
|
|
// treat associated DepSettings same as more than
|
|
// one DepSettings entry defined for one feature.
|
|
|
|
{
|
|
DWORD dwUnresolvedFeature ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
|
|
patrRoot = &(pfo[dwFea].atrDependentSettings) ;
|
|
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSDepSettingsIndex,
|
|
(PBYTE)&dwListsRoot,
|
|
&dwUnresolvedFeature, *patrRoot, pOptions,
|
|
dwFea,
|
|
&dwNextOpt) != TRI_SUCCESS)
|
|
{
|
|
goto END_OF_FOR_LOOP ; // no DependentSettings to apply.
|
|
}
|
|
if(dwListsRoot == END_OF_LIST)
|
|
continue; // maybe another option does have a list.
|
|
|
|
}
|
|
|
|
if(dwListsRootOpt1 == END_OF_LIST) // first time thru do loop?
|
|
dwListsRootOpt1 = dwListsRoot ;
|
|
|
|
// now we need to see if the current pOption matches any
|
|
// of the lists accessed using dwListsRoot.
|
|
|
|
for(dwListIndex = dwListsRoot ;
|
|
dwListIndex != END_OF_LIST ;
|
|
dwListIndex = plstRoot[dwListIndex].dwNextItem )
|
|
{
|
|
// for each DepSettings list....
|
|
// now walk that DepSettings list at dwListIndex and compare
|
|
// to current settings at pOptions. If there is a match, use
|
|
// depSettings list to OR on options in pDestOptions.
|
|
// Note: Features with their one-shot flag set cannot be
|
|
// considered. They will be ignored.
|
|
BOOL bActiveMatch = FALSE, // requires an actual match
|
|
bOptionArrayMatchesDepSettings = TRUE ; // assume true
|
|
// until proven otherwise.
|
|
for(dwNodeIndex = plstRoot[dwListIndex].dwData ; dwNodeIndex != END_OF_LIST ;
|
|
dwNodeIndex = plstRoot[dwNodeIndex].dwNextItem)
|
|
{
|
|
pqn = (PQUALNAME)(&plstRoot[dwNodeIndex].dwData) ;
|
|
dwFeature = pqn->wFeatureID ;
|
|
dwOption = pqn->wOptionID ;
|
|
if(pbOneShotFlag[dwFeature] == TRUE)
|
|
continue;
|
|
if(!BIsFeaOptionCurSelected(pOptions, dwFeature, dwOption) )
|
|
{
|
|
bOptionArrayMatchesDepSettings = FALSE ;
|
|
break;
|
|
}
|
|
else
|
|
bActiveMatch = TRUE;
|
|
}
|
|
|
|
if(bOptionArrayMatchesDepSettings && bActiveMatch)
|
|
// at least one DepSetting was honored.
|
|
{
|
|
// 'or' DepSettings into DestOptions
|
|
for(dwNodeIndex = plstRoot[dwListIndex].dwData ; dwNodeIndex != END_OF_LIST ;
|
|
dwNodeIndex = plstRoot[dwNodeIndex].dwNextItem)
|
|
{
|
|
pqn = (PQUALNAME)(&plstRoot[dwNodeIndex].dwData) ;
|
|
dwFeature = pqn->wFeatureID ;
|
|
dwOption = pqn->wOptionID ;
|
|
if(pbOneShotFlag[dwFeature] == TRUE)
|
|
continue;
|
|
// select dwOption in DestOptions in addition to any other options
|
|
// already selected.
|
|
EnumSelectedOptions(pnRawData, pDestOptions, dwFeature,
|
|
pbSelectedOptions) ;
|
|
if(!pbSelectedOptions[dwOption]) // the option that should be selected isn't.
|
|
{ // so let's turn it on.
|
|
pbSelectedOptions[dwOption] = TRUE ; // This is the ORing process.
|
|
ReconstructOptionArray( pnRawData, pDestOptions, iMaxOptions,
|
|
dwFeature, pbSelectedOptions ) ;
|
|
bMatchFound = TRUE ; // there really is something to set.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} while (dwNextOpt);
|
|
|
|
if (dwListsRootOpt1 == END_OF_LIST)
|
|
continue; // you cannot set anything if there is no list to use.
|
|
|
|
if (!bMatchFound)
|
|
{
|
|
// set dest Option array according to depSettings(dwListsRoot)
|
|
for(dwNodeIndex = plstRoot[dwListsRootOpt1].dwData ; dwNodeIndex != END_OF_LIST ;
|
|
dwNodeIndex = plstRoot[dwNodeIndex].dwNextItem)
|
|
{
|
|
pqn = (PQUALNAME)(&plstRoot[dwNodeIndex].dwData) ;
|
|
dwFeature = pqn->wFeatureID ;
|
|
dwOption = pqn->wOptionID ;
|
|
if(pbOneShotFlag[dwFeature] == TRUE)
|
|
continue;
|
|
pDestOptions[dwFeature].ubCurOptIndex = (BYTE)dwOption ;
|
|
}
|
|
}
|
|
|
|
// propagate Dest option array settings to pOptions
|
|
// note which features got set and set their one-shot
|
|
// flag.
|
|
|
|
|
|
for( dwFeature = 0 ; dwFeature < dwNumFeatures ; dwFeature++)
|
|
{
|
|
if(pDestOptions[dwFeature].ubCurOptIndex == OPTION_INDEX_ANY)
|
|
continue;
|
|
EnumSelectedOptions( pnRawData, pDestOptions,
|
|
dwFeature, pbSelectedOptions) ;
|
|
|
|
ReconstructOptionArray( pnRawData, pOptions, iMaxOptions,
|
|
dwFeature, pbSelectedOptions ) ;
|
|
pbOneShotFlag[dwFeature] = TRUE ;
|
|
}
|
|
|
|
END_OF_FOR_LOOP:
|
|
; // dummy statement after every label.
|
|
} // end for loop. for each Feature in order of priority.
|
|
|
|
ABORTRESOLVEDEPENDENTSETTINGS:
|
|
if(pbOneShotFlag)
|
|
MemFree(pbOneShotFlag);
|
|
if(pDestOptions)
|
|
MemFree(pDestOptions);
|
|
if(pbSelectedOptions)
|
|
MemFree(pbSelectedOptions);
|
|
return(bStatus);
|
|
}
|
|
|
|
|
|
void EnumSelectedOptions(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN DWORD dwFeature,
|
|
IN PBOOL pbSelectedOptions)
|
|
{
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
DWORD dwNumOptions, dwI, dwOption, dwNextOpt ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
|
|
|
|
dwNumOptions = pfo[dwFeature].dwNumOptions ;
|
|
|
|
for( dwI = 0 ; dwI < dwNumOptions ; dwI++)
|
|
pbSelectedOptions[dwI] = FALSE ;
|
|
|
|
|
|
if((dwOption = pOptions[dwFeature].ubCurOptIndex) == OPTION_INDEX_ANY)
|
|
return;
|
|
|
|
pbSelectedOptions[dwOption] = TRUE ;
|
|
dwNextOpt = dwFeature ; // case of pick many
|
|
while(dwNextOpt = pOptions[dwNextOpt].ubNext)
|
|
{
|
|
pbSelectedOptions[pOptions[dwNextOpt].ubCurOptIndex] = TRUE ;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
BOOL
|
|
ExecuteMacro(
|
|
IN PRAWBINARYDATA pnRawData,
|
|
IN OUT POPTSELECT pOptions,
|
|
IN INT iMaxOptions,
|
|
IN DWORD dwFea, // what feature was selected in UI
|
|
IN DWORD dwOpt , // what option was selected in UI
|
|
OUT PBOOL pbFeaturesChanged // tell Amanda what Features were changed.
|
|
)
|
|
// does this for one feature and one option only!
|
|
{
|
|
PRAWBINARYDATA pRawData ;
|
|
PSTATICFIELDS pStatic ;
|
|
PBYTE pubRaw ; // raw binary data.
|
|
PLISTNODE plstRoot ; // start of LIST array
|
|
DWORD dwListsRoot, dwListIndex; // Root of the chain
|
|
DWORD dwNumFeatures, dwI, dwJ, dwNodeIndex,
|
|
dwFeature, dwOption ;
|
|
PENHARRAYREF pearTableContents ;
|
|
PDFEATURE_OPTIONS pfo ;
|
|
PDWORD pdwPriority ;
|
|
PQUALNAME pqn ; // the dword in the list node is actually a
|
|
// qualified name structure.
|
|
INT iOptionsNeeded;
|
|
PBOOL pbOneShotFlag, pbSelectedOptions ;
|
|
BOOL bHigherPri, // divides features into two groups those with higher priority
|
|
// than dwFea, and those with lower priority.
|
|
// the Macro cannot change Features with higher priority.
|
|
bMatchFound ; // a DependentSettings matches the current config.
|
|
POPTSELECT pDestOptions ;
|
|
BOOL bStatus = TRUE ;
|
|
|
|
pStatic = (PSTATICFIELDS)pnRawData ; // transform pubRaw from PSTATIC
|
|
pRawData = (PRAWBINARYDATA)pStatic->pubBUDData ;
|
|
// to BUDDATA
|
|
|
|
pubRaw = (PBYTE)pRawData ;
|
|
// pmrbd = (PMINIRAWBINARYDATA)pubRaw ;
|
|
|
|
|
|
|
|
pearTableContents = (PENHARRAYREF)(pubRaw + sizeof(MINIRAWBINARYDATA)) ;
|
|
pfo = (PDFEATURE_OPTIONS)(pubRaw +
|
|
pearTableContents[MTI_DFEATURE_OPTIONS].loOffset) ;
|
|
pdwPriority = (PDWORD)(pubRaw +
|
|
pearTableContents[MTI_PRIORITYARRAY].loOffset) ;
|
|
|
|
plstRoot = (PLISTNODE)(pubRaw + pearTableContents[MTI_LISTNODES].
|
|
loOffset) ;
|
|
|
|
dwNumFeatures = pearTableContents[MTI_DFEATURE_OPTIONS].dwCount ;
|
|
dwNumFeatures += pearTableContents[MTI_SYNTHESIZED_FEATURES].dwCount ;
|
|
|
|
if(dwNumFeatures > (DWORD)iMaxOptions)
|
|
{
|
|
iOptionsNeeded = dwNumFeatures ;
|
|
return(FALSE); // too many to save in option array.
|
|
}
|
|
|
|
pbOneShotFlag = (PBOOL)MemAlloc(dwNumFeatures * sizeof(BOOL) ) ;
|
|
pbSelectedOptions = (PBOOL)MemAlloc(iMaxOptions * sizeof(BOOL) ) ;
|
|
// iMaxOptions must be greater than the max number of options availible for
|
|
// any feature.
|
|
|
|
|
|
// to extend to pickmany, have a dest optionarray.
|
|
// each time the source optionarray completely contains
|
|
// a DependentSettings list (in that each Fea.Option
|
|
// listed as a DependentSetting is also selected in the
|
|
// source option array) we turn on those Fea.Options
|
|
// in the dest option array. After all DependentSettings
|
|
// lists for that feature have been processed, we set
|
|
// the OneShotFlag for each Feature that has been affected
|
|
// in the dest option array. For each such feature we will
|
|
// let the dest option array determine the setting of the
|
|
// source option array.
|
|
// this code does not verify that a Feature is pickmany
|
|
// before treating it as pickmany. If the source option
|
|
// array has more than one option selected for a feature,
|
|
// that feature is automatically treated as a pickmany.
|
|
|
|
|
|
pDestOptions = (POPTSELECT)MemAlloc(iMaxOptions * sizeof(OPTSELECT) ) ;
|
|
// 'or' all acceptable DependentSettings here.
|
|
|
|
if(!(pbOneShotFlag && pDestOptions && pbSelectedOptions))
|
|
{
|
|
ERR(("Fatal: ResolveDependentSettings - unable to alloc requested memory: %d bytes.\n",
|
|
dwNumFeatures * sizeof(BOOL)));
|
|
bStatus = FALSE ;
|
|
goto ABORTEXECUTEMACROS ;
|
|
}
|
|
|
|
|
|
for(bHigherPri = TRUE, dwI = 0 ; dwI < dwNumFeatures ; dwI++)
|
|
{
|
|
pbFeaturesChanged[dwI] = FALSE ; // start with no Features changed
|
|
pbOneShotFlag[pdwPriority[dwI]] = bHigherPri ;
|
|
if(pdwPriority[dwI] == dwFea)
|
|
bHigherPri = FALSE ; // all remaining features are of lower priority
|
|
// and therefore susceptible to getting changed by the macro.
|
|
}
|
|
// this boolean array tracks if the feature has been
|
|
// referenced in a DependentSettings entry.
|
|
// If a feature is referenced again in DependentSettings
|
|
// entry belonging to another feature, the subsequent
|
|
// references will be ignored. This ensures only the
|
|
// highest priority Feature's request shall have precedence.
|
|
|
|
|
|
{
|
|
DWORD dwNextOpt ;
|
|
// The order of evaluation is determined
|
|
// by the priority array.
|
|
|
|
|
|
dwNextOpt = 0 ; // extract info for first option selected for
|
|
// this feature.
|
|
|
|
for( dwJ = 0 ; dwJ < dwNumFeatures ; dwJ++)
|
|
{
|
|
pDestOptions[dwJ].ubCurOptIndex = OPTION_INDEX_ANY ;
|
|
pDestOptions[dwJ].ubNext = 0 ; // eol
|
|
// DestOptions is now blank.
|
|
}
|
|
|
|
bMatchFound = FALSE ;
|
|
|
|
|
|
|
|
{
|
|
DWORD dwUnresolvedFeature, dwOldOpt ;
|
|
PATREEREF patrRoot ; // root of attribute tree to navigate.
|
|
|
|
patrRoot = &(pfo[dwFea].atrUIChangeTriggersMacro) ;
|
|
|
|
// if dwFea is a pickmany, we must force selection of
|
|
// the Macro associated with just dwOpt. We do this by
|
|
// changing the optionarray temporarily.
|
|
|
|
dwOldOpt = pOptions[dwFea].ubCurOptIndex ;
|
|
pOptions[dwFea].ubCurOptIndex = (BYTE)dwOpt ;
|
|
|
|
if(EextractValueFromTree((PBYTE)pnRawData, pStatic->dwSSUIChangeTriggersMacroIndex,
|
|
(PBYTE)&dwListsRoot,
|
|
&dwUnresolvedFeature, *patrRoot, pOptions,
|
|
dwFea,
|
|
&dwNextOpt) != TRI_SUCCESS)
|
|
{
|
|
pOptions[dwFea].ubCurOptIndex = (BYTE)dwOldOpt ; // restore
|
|
goto ABORTEXECUTEMACROS ; // no UIChangeTriggersMacro to apply.
|
|
}
|
|
pOptions[dwFea].ubCurOptIndex = (BYTE)dwOldOpt ; // restore
|
|
if(dwListsRoot == END_OF_LIST)
|
|
goto ABORTEXECUTEMACROS ; // no UIChangeTriggersMacro to apply.
|
|
}
|
|
|
|
|
|
// now we need to see if the current pOption matches any
|
|
// of the lists accessed using dwListsRoot.
|
|
|
|
for(dwListIndex = dwListsRoot ;
|
|
dwListIndex != END_OF_LIST ;
|
|
dwListIndex = plstRoot[dwListIndex].dwNextItem )
|
|
{
|
|
// for each DepSettings list....
|
|
// now walk that DepSettings list at dwListIndex and compare
|
|
// to current settings at pOptions. If there is a match, use
|
|
// depSettings list to OR on options in pDestOptions.
|
|
// Note: Features with their one-shot flag set cannot be
|
|
// considered. They will be ignored.
|
|
BOOL bActiveMatch = FALSE, // requires an actual match
|
|
bOptionArrayMatchesDepSettings = TRUE ; // assume true
|
|
// until proven otherwise.
|
|
for(dwNodeIndex = plstRoot[dwListIndex].dwData ; dwNodeIndex != END_OF_LIST ;
|
|
dwNodeIndex = plstRoot[dwNodeIndex].dwNextItem)
|
|
{
|
|
pqn = (PQUALNAME)(&plstRoot[dwNodeIndex].dwData) ;
|
|
dwFeature = pqn->wFeatureID ;
|
|
dwOption = pqn->wOptionID ;
|
|
if(pbOneShotFlag[dwFeature] == TRUE)
|
|
continue;
|
|
if(!BIsFeaOptionCurSelected(pOptions, dwFeature, dwOption) )
|
|
{
|
|
bOptionArrayMatchesDepSettings = FALSE ;
|
|
break;
|
|
}
|
|
else
|
|
bActiveMatch = TRUE;
|
|
}
|
|
|
|
if(bOptionArrayMatchesDepSettings && bActiveMatch)
|
|
// at least one DepSetting was honored.
|
|
{
|
|
// 'or' DepSettings into DestOptions
|
|
for(dwNodeIndex = plstRoot[dwListIndex].dwData ; dwNodeIndex != END_OF_LIST ;
|
|
dwNodeIndex = plstRoot[dwNodeIndex].dwNextItem)
|
|
{
|
|
pqn = (PQUALNAME)(&plstRoot[dwNodeIndex].dwData) ;
|
|
dwFeature = pqn->wFeatureID ;
|
|
dwOption = pqn->wOptionID ;
|
|
if(pbOneShotFlag[dwFeature] == TRUE)
|
|
continue;
|
|
// select dwOption in DestOptions in addition to any other options
|
|
// already selected.
|
|
EnumSelectedOptions(pnRawData, pDestOptions, dwFeature,
|
|
pbSelectedOptions) ;
|
|
if(!pbSelectedOptions[dwOption]) // the option that should be selected isn't.
|
|
{ // so let's turn it on.
|
|
pbSelectedOptions[dwOption] = TRUE ; // This is the ORing process.
|
|
ReconstructOptionArray( pnRawData, pDestOptions, iMaxOptions,
|
|
dwFeature, pbSelectedOptions ) ;
|
|
bMatchFound = TRUE ; // there really is something to set.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!bMatchFound)
|
|
{
|
|
// set dest Option array according to depSettings(dwListsRoot)
|
|
for(dwNodeIndex = plstRoot[dwListsRoot].dwData ; dwNodeIndex != END_OF_LIST ;
|
|
dwNodeIndex = plstRoot[dwNodeIndex].dwNextItem)
|
|
{
|
|
pqn = (PQUALNAME)(&plstRoot[dwNodeIndex].dwData) ;
|
|
dwFeature = pqn->wFeatureID ;
|
|
dwOption = pqn->wOptionID ;
|
|
if(pbOneShotFlag[dwFeature] == TRUE)
|
|
continue;
|
|
pDestOptions[dwFeature].ubCurOptIndex = (BYTE)dwOption ;
|
|
}
|
|
}
|
|
|
|
// propagate Dest option array settings to pOptions
|
|
// note which features got set and set their one-shot
|
|
// flag.
|
|
|
|
|
|
for( dwFeature = 0 ; dwFeature < dwNumFeatures ; dwFeature++)
|
|
{
|
|
if(pDestOptions[dwFeature].ubCurOptIndex == OPTION_INDEX_ANY)
|
|
continue;
|
|
EnumSelectedOptions( pnRawData, pDestOptions,
|
|
dwFeature, pbSelectedOptions) ;
|
|
|
|
ReconstructOptionArray( pnRawData, pOptions, iMaxOptions,
|
|
dwFeature, pbSelectedOptions ) ;
|
|
pbOneShotFlag[dwFeature] = TRUE ;
|
|
pbFeaturesChanged[dwFeature] = TRUE ; // this Feature may have changed
|
|
}
|
|
|
|
} // end non-existent for loop.
|
|
|
|
ABORTEXECUTEMACROS:
|
|
if(pbOneShotFlag)
|
|
MemFree(pbOneShotFlag);
|
|
if(pDestOptions)
|
|
MemFree(pDestOptions);
|
|
if(pbSelectedOptions)
|
|
MemFree(pbSelectedOptions);
|
|
return(bStatus);
|
|
}
|
|
#endif
|
|
|
|
#endif PARSERDLL
|