HRESULT CWiaDriver::ValidateFormatProperties()

in wia/ProdScan/Validate.cpp [56:595]


HRESULT CWiaDriver::ValidateFormatProperties(
    _In_ BYTE*                    pWiasContext,
    _In_ WIA_PROPERTY_CONTEXT*    pPropertyContext,
    UINT                          nDocumentHandlingSelect)
{
    HRESULT hr = S_OK;

    LONG lDataType = WIA_DATA_COLOR;
    LONG lIntent = WIA_INTENT_NONE;
    LONG lDepth = 24;
    LONG lChannelsPerPixel = 3;
    LONG lBitsPerChannel = 8;
    GUID guidFormat = WiaImgFmt_UNDEFINED;
    LONG lCompression = WIA_COMPRESSION_NONE;
    BSTR bstrFileExtension = NULL;
    BYTE bRawBitsPerChannel[3] = {};

    BOOL bDataTypeChanged = FALSE;
    BOOL bIntentChanged = FALSE;
    BOOL bImageTypeIntentChanged = FALSE;
    BOOL bDepthChanged = FALSE;
    BOOL bFormatChanged = FALSE;
    BOOL bCompressionChanged = FALSE;

    PROPSPEC ps[3] = {};
    ULONG nPropSpec = 0;

    if ((!pWiasContext) || (!pPropertyContext))
    {
        hr = E_INVALIDARG;
        WIAEX_ERROR((g_hInst, "Invalid parameters, hr = 0x%08X", hr));
    }

    if (SUCCEEDED(hr))
    {
        //
        // Check which color properties have been changed (ignore failures).
        // Note that the Auto item supports only format, tymed and compression:
        //
        if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect))
        {
            wiasIsPropChanged(WIA_IPA_DATATYPE, pPropertyContext, &bDataTypeChanged);
            wiasIsPropChanged(WIA_IPS_CUR_INTENT, pPropertyContext, &bIntentChanged);
            wiasIsPropChanged(WIA_IPA_DEPTH, pPropertyContext, &bDepthChanged);
        }
        wiasIsPropChanged(WIA_IPA_FORMAT, pPropertyContext, &bFormatChanged);
        wiasIsPropChanged(WIA_IPA_COMPRESSION, pPropertyContext, &bCompressionChanged);

        if ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect))
        {
            //
            // Read the current WIA_IPS_CUR_INTENT value:
            //
            if (SUCCEEDED(hr))
            {
                hr = wiasReadPropLong(pWiasContext, WIA_IPS_CUR_INTENT, &lIntent, NULL, TRUE);
                if (FAILED(hr))
                {
                    WIAEX_ERROR((g_hInst, "Error reading current WIA_IPS_CUR_INTENT, hr = 0x%08X", hr));
                }
            }

            //
            // When the intent is changed check if an image type intent flag is set:
            //
            if (SUCCEEDED(hr))
            {
                bImageTypeIntentChanged = (BOOL)(bIntentChanged && (WIA_INTENT_IMAGE_TYPE_MASK & lIntent));
            }
        }
    }

    //
    // Read the other current property values (no matter if each respective property was changed or not):
    //

    if (SUCCEEDED(hr) && (bDataTypeChanged || bIntentChanged || bDepthChanged) &&
        ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)))
    {
        hr = wiasReadPropLong(pWiasContext, WIA_IPA_DATATYPE, &lDataType, NULL, TRUE);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_DATATYPE, hr = 0x%08X", hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = wiasReadPropLong(pWiasContext, WIA_IPA_DEPTH, &lDepth, NULL, TRUE);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_DEPTH, hr = 0x%08X", hr));
            }
        }
    }

    if (SUCCEEDED(hr) && (bFormatChanged || bCompressionChanged))
    {
        hr = wiasReadPropLong(pWiasContext, WIA_IPA_COMPRESSION, &lCompression, NULL, TRUE);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_COMPRESSION, hr = 0x%08X", hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = wiasReadPropGuid(pWiasContext, WIA_IPA_FORMAT, &guidFormat, NULL, TRUE);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Error reading current WIA_IPA_FORMAT, hr = 0x%08X", hr));
            }
        }
    }

    //
    // If the application changed the image type intent the driver must consider
    // that WIA_IPA_DATA_TYPE was changed to the value apropriate for the new
    // intent no matter if the application set WIA_IPA_DATA_TYPE and to what value:
    //
    if (SUCCEEDED(hr) && bImageTypeIntentChanged)
    {
        //
        // If multiple color intents are set at the same time consider
        // just one and give the highest priority to highest bitdepth:
        //
        if (WIA_INTENT_IMAGE_TYPE_COLOR & lIntent)
        {
            bDataTypeChanged = TRUE;
            lDataType = WIA_DATA_COLOR;
        }
        else if (WIA_INTENT_IMAGE_TYPE_GRAYSCALE & lIntent)
        {
            bDataTypeChanged = TRUE;
            lDataType = WIA_DATA_GRAYSCALE;
        }
    }

    //
    // Validate the new current values against the total supported values for
    // each of the changed properties with write access in this category:
    //
    // WIA_IPA_DATATYPE
    // WIA_IPS_CUR_INTENT
    // WIA_IPA_DEPTH
    // WIA_IPA_FORMAT
    // WIA_IPA_TYMED (skipped here since its value cannot be changed for this driver)
    // WIA_IPA_COMPRESSION
    //
    // This sample driver can validate color and format properties separately
    // since none of its color modes (WIA_IPA_DATATYPE and WIA_IPA_DEPTH
    // combinations) are dependent on format changes (WIA_IPA_FORMAT,
    // WIA_IPA_TYMED -ignored here- and WIA_IPA_COMPRESSION combinations).
    // If the driver would also support WIA_DATA_BW, WIA_COMPRESSION_G4
    // and WiaImgFmt_TIFF the driver would need to validate all the color
    // and format properties together (for example WIA_DATA_BW and
    // WIA_COMPRESSION_G4 do neither work with WiaImgFmt_EXIF).
    //
    if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) &&
        (bDataTypeChanged || bIntentChanged || bDepthChanged))
    {
        nPropSpec = 0;

        if (bDataTypeChanged)
        {
            ps[nPropSpec].ulKind = PRSPEC_PROPID;
            ps[nPropSpec].propid = WIA_IPA_DATATYPE;
            nPropSpec++;
        }

        if (bIntentChanged)
        {
            ps[nPropSpec].ulKind = PRSPEC_PROPID;
            ps[nPropSpec].propid = WIA_IPS_CUR_INTENT;
            nPropSpec++;
        }

        if (bDepthChanged)
        {
            ps[nPropSpec].ulKind = PRSPEC_PROPID;
            ps[nPropSpec].propid = WIA_IPA_DEPTH;
            nPropSpec++;
        }

        hr = wiasValidateItemProperties(pWiasContext, nPropSpec, ps);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Invalid color property value(s) requested, hr = 0x%08X", hr));
        }
    }

    if (SUCCEEDED(hr) && (bFormatChanged || bCompressionChanged))
    {
        nPropSpec = 0;

        if (bFormatChanged)
        {
            ps[nPropSpec].ulKind = PRSPEC_PROPID;
            ps[nPropSpec].propid = WIA_IPA_FORMAT;
            nPropSpec++;
        }

        if (bCompressionChanged)
        {
            ps[nPropSpec].ulKind = PRSPEC_PROPID;
            ps[nPropSpec].propid = WIA_IPA_COMPRESSION;
            nPropSpec++;
        }

        hr = wiasValidateItemProperties(pWiasContext, nPropSpec, ps);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Invalid format property value(s) requested, hr = 0x%08X", hr));
        }
    }

    //
    // Additional validation for WIA_IPA_DATATYPE and WIA_IPA_DEPTH:
    //
    if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) &&
        (bDataTypeChanged || bDepthChanged))
    {
        if (bDataTypeChanged && bDepthChanged)
        {
            if (((WIA_DATA_COLOR == lDataType) && (8 == lDepth)) ||
                ((WIA_DATA_GRAYSCALE == lDataType) && (24 == lDepth)))
            {
                hr = E_INVALIDARG;
                WIAEX_ERROR((g_hInst, "Unsupported data type (%u) - depth (%u) combination requested, hr = 0x%08X",
                    lDataType, lDepth, hr));
            }
        }
        else if (bDataTypeChanged && (!bDepthChanged))
        {
            if (WIA_DATA_COLOR == lDataType)
            {
                lDepth = 24;
            }
            else if (WIA_DATA_GRAYSCALE == lDataType)
            {
                lDepth = 8;
            }
            else if (WIA_DATA_AUTO == lDataType)
            {
                lDepth = WIA_DEPTH_AUTO;
            }
        }
        else if ((!bDataTypeChanged) && bDepthChanged)
        {
            if (8 == lDepth)
            {
                lDataType = WIA_DATA_GRAYSCALE;
            }
            else if (24 == lDepth)
            {
                lDataType = WIA_DATA_COLOR;
            }
            else if (WIA_DEPTH_AUTO == lDepth)
            {
                lDataType = WIA_DATA_AUTO;
            }
        }
    }

    //
    // Additional validation for WIA_IPA_FORMAT and WIA_IPA_COMPRESSION (skipped for the
    // sample non-image sources since those do not support compresssed data transfers):
    //
    if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect) ||
        (AUTO_SOURCE == nDocumentHandlingSelect)) && (bFormatChanged || bCompressionChanged))
    {
        if (bFormatChanged && (!bCompressionChanged))
        {
            //
            // If WIA_IPA_FORMAT if changed alone, update WIA_IPA_COMPRESSION to match:
            //
            if (IsEqualGUID(guidFormat, WiaImgFmt_EXIF))
            {
                lCompression = WIA_COMPRESSION_JPEG;
            }
            else if (IsEqualGUID(guidFormat, WiaImgFmt_BMP) || IsEqualGUID(guidFormat, WiaImgFmt_RAW))
            {
                lCompression = WIA_COMPRESSION_NONE;
            }
        }
        else if ((!bFormatChanged) && bCompressionChanged)
        {
            //
            // If WIA_IPA_COMPRESSION if changed alone, update WIA_IPA_FORMAT to match:
            //
            if ((WIA_COMPRESSION_JPEG == lCompression) || (WIA_COMPRESSION_AUTO == lCompression))
            {
                guidFormat = WiaImgFmt_EXIF;
            }
            else if (WIA_COMPRESSION_NONE == lCompression)
            {
                guidFormat = WiaImgFmt_BMP;
            }
        }
        else if (bFormatChanged && bCompressionChanged)
        {
            //
            // If both WIA_IPA_FORMAT and WIA_IPA_COMPRESSION are changed, verify that their values work together:
            //
            if (((WIA_COMPRESSION_NONE == lCompression) && IsEqualGUID(guidFormat, WiaImgFmt_EXIF)) ||
                (((WIA_COMPRESSION_JPEG == lCompression) || (WIA_COMPRESSION_AUTO == lCompression)) &&
                    (IsEqualGUID(guidFormat, WiaImgFmt_BMP) || IsEqualGUID(guidFormat, WiaImgFmt_RAW))))
            {
                hr = E_INVALIDARG;
                WIAEX_ERROR((g_hInst, "Unsupported file format - compression mode combination, hr = 0x%08X", hr));
            }
        }
    }

    //
    // Update current values:
    //

    if (SUCCEEDED(hr) && ((FLAT == nDocumentHandlingSelect) || (FEED == nDocumentHandlingSelect)) &&
        (bDataTypeChanged || bIntentChanged || bDepthChanged))
    {
        //
        // WIA_IPA_DATATYPE:
        //
        hr = wiasWritePropLong(pWiasContext, WIA_IPA_DATATYPE, lDataType);
        if (FAILED(hr))
        {
            WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_DATATYPE, hr = 0x%08X", hr));
        }
        else
        {
            wiasSetPropChanged(WIA_IPA_DATATYPE, pPropertyContext, TRUE);
        }

        //
        // WIA_IPS_CUR_INTENT
        //
        // If an image type intent is set we must make sure it matches the current WIA_IPA_DATATYPE.
        // Don't do anything if the application changes any of the other intent flags.
        //
        if (SUCCEEDED(hr) && (lIntent & WIA_INTENT_IMAGE_TYPE_MASK))
        {
            //
            // Reset all current image type intent flags.
            //
            lIntent &= ~ WIA_INTENT_IMAGE_TYPE_MASK;

            //
            // .. and add just the one apropriate with the current WIA_IPA_DATATYPE value:
            //

            switch (lDataType)
            {
                case WIA_DATA_COLOR:
                    lIntent |= WIA_INTENT_IMAGE_TYPE_COLOR;
                    break;

                case WIA_DATA_GRAYSCALE:
                    lIntent |= WIA_INTENT_IMAGE_TYPE_GRAYSCALE;
            }

            hr = wiasWritePropLong(pWiasContext, WIA_IPS_CUR_INTENT, lIntent);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPS_CUR_INTENT, hr = 0x%08X", hr));
            }
            else
            {
                wiasSetPropChanged(WIA_IPS_CUR_INTENT, pPropertyContext, TRUE);
            }
        }

        //
        // WIA_IPA_DEPTH:
        //
        if (SUCCEEDED(hr))
        {
            hr = wiasWritePropLong(pWiasContext, WIA_IPA_DEPTH, lDepth);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_DEPTH, hr = 0x%08X", hr));
            }
            else
            {
                wiasSetPropChanged(WIA_IPA_DEPTH, pPropertyContext, TRUE);
            }
        }

        //
        // WIA_IPA_CHANNELS_PER_PIXEL:
        //
        if (SUCCEEDED(hr))
        {
            lChannelsPerPixel = (24 == lDepth) ? 3 : 1;

            hr = wiasWritePropLong(pWiasContext, WIA_IPA_CHANNELS_PER_PIXEL, lChannelsPerPixel);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_CHANNELS_PER_PIXEL, hr = 0x%08X", hr));
            }
            else
            {
                wiasSetPropChanged(WIA_IPA_CHANNELS_PER_PIXEL, pPropertyContext, TRUE);
            }
        }

        //
        // WIA_IPA_BITS_PER_CHANNEL:
        //
        if (SUCCEEDED(hr))
        {
            lBitsPerChannel = 8;

            hr = wiasWritePropLong(pWiasContext, WIA_IPA_BITS_PER_CHANNEL, lBitsPerChannel);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_BITS_PER_CHANNEL, hr = 0x%08X", hr));
            }
            else
            {
                wiasSetPropChanged(WIA_IPA_BITS_PER_CHANNEL, pPropertyContext, TRUE);
            }
        }

        //
        // WIA_IPA_RAW_BITS_PER_CHANNEL
        //
        if (SUCCEEDED(hr))
        {
            for (int i = 0; i < lChannelsPerPixel; i++)
            {
                bRawBitsPerChannel[i] = 8;
            }

            hr = wiasWritePropBin(pWiasContext, WIA_IPA_RAW_BITS_PER_CHANNEL, lChannelsPerPixel, bRawBitsPerChannel);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_RAW_BITS_PER_CHANNEL, hr = 0x%08X", hr));
            }
            else
            {
                wiasSetPropChanged(WIA_IPA_RAW_BITS_PER_CHANNEL, pPropertyContext, TRUE);
            }
        }
    }

    if (SUCCEEDED(hr) && (bFormatChanged || bCompressionChanged))
    {
        //
        // WIA_IPA_COMPRESSION:
        //
        if (SUCCEEDED(hr))
        {
            hr = wiasWritePropLong(pWiasContext, WIA_IPA_COMPRESSION, lCompression);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_COMPRESSION, hr = 0x%08X", hr));
            }
            else
            {
                wiasSetPropChanged(WIA_IPA_COMPRESSION, pPropertyContext, TRUE);
            }
        }

        //
        // WIA_IPA_FORMAT:
        //
        if (SUCCEEDED(hr))
        {
            hr = wiasWritePropGuid(pWiasContext, WIA_IPA_FORMAT, guidFormat);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_FORMAT, hr = 0x%08X", hr));
            }
            else
            {
                wiasSetPropChanged(WIA_IPA_COMPRESSION, pPropertyContext, TRUE);
            }
        }

        //
        // WIA_IPA_FILENAME_EXTENSION:
        //

        if (SUCCEEDED(hr))
        {
            if (IsEqualGUID(guidFormat, WiaImgFmt_BMP))
            {
                bstrFileExtension = SysAllocString(FILE_EXT_BMP);
            }
            else if (IsEqualGUID(guidFormat, WiaImgFmt_EXIF))
            {
                bstrFileExtension = SysAllocString(FILE_EXT_JPG);
            }
            else if (IsEqualGUID(guidFormat, WiaImgFmt_RAW) || IsEqualGUID(guidFormat, WiaImgFmt_RAWBAR) ||
                IsEqualGUID(guidFormat, WiaImgFmt_RAWPAT) || IsEqualGUID(guidFormat, WiaImgFmt_RAWMIC))
            {
                bstrFileExtension = SysAllocString(FILE_EXT_RAW);
            }
            else if (IsEqualGUID(guidFormat, WiaImgFmt_CSV))
            {
                bstrFileExtension = SysAllocString(FILE_EXT_CSV);
            }
            else if (IsEqualGUID(guidFormat, WiaImgFmt_TXT))
            {
                bstrFileExtension = SysAllocString(FILE_EXT_TXT);
            }
            else if (IsEqualGUID(guidFormat, WiaImgFmt_XMLBAR) || IsEqualGUID(guidFormat, WiaImgFmt_XMLPAT) ||
                IsEqualGUID(guidFormat, WiaImgFmt_XMLMIC))
            {
                bstrFileExtension = SysAllocString(FILE_EXT_XML);
            }
            else
            {
                hr = E_FAIL;
                WIAEX_ERROR((g_hInst, "Unsupported file format, hr = 0x%08X", hr));
            }
        }

        if (SUCCEEDED(hr) && (!bstrFileExtension))
        {
            hr = E_OUTOFMEMORY;
            WIAEX_ERROR((g_hInst, "Unable to allocate memory for new file extension, hr = 0x%08X", hr));
        }

        if (SUCCEEDED(hr))
        {
            hr = wiasWritePropStr(pWiasContext, WIA_IPA_FILENAME_EXTENSION, bstrFileExtension);
            if (FAILED(hr))
            {
                WIAEX_ERROR((g_hInst, "Failed to update WIA_IPA_FILENAME_EXTENSION, hr = 0x%08X", hr));
            }
        }
    }

    if (bstrFileExtension)
    {
        SysFreeString(bstrFileExtension);
    }

    return hr;
}