// 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