Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1153 lines
26 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
CheckBmp.cpp
Abstract:
BMP file format checking routines
Author:
Hakki T. Bostanci (hakkib) 17-Dec-1999
Revision History:
--*/
#include "stdafx.h"
#include "Wrappers.h"
#include "LogWindow.h"
#include "LogWrappers.h"
#include "Argv.h"
#include "CheckBmp.h"
#ifdef _CONSOLE
TCHAR szDecVal[] = _T("%-15s = %d");
TCHAR szHexVal[] = _T("%-15s = 0x%08x");
TCHAR szStrVal[] = _T("%-15s = %s");
TCHAR szDblVal[] = _T("%-15s = %.4lf");
#else //_CONSOLE
TCHAR szDecVal[] = _T("%s = %d");
TCHAR szHexVal[] = _T("%s = 0x%08x");
TCHAR szStrVal[] = _T("%s = %s");
TCHAR szDblVal[] = _T("%s = %.4lf");
#endif //_CONSOLE
//////////////////////////////////////////////////////////////////////////
//
// HeaderSize
//
// Routine Description:
// returns the size of the bitmap header
//
// Arguments:
//
// Return Value:
//
inline
DWORD
HeaderSize(
const VOID *pBitmapInfo
)
{
return *(PDWORD)pBitmapInfo;
}
//////////////////////////////////////////////////////////////////////////
//
// WidthBytes
//
// Routine Description:
// calculates the number of bytes in a BMP row (that should be DWORD aligned)
//
// Arguments:
//
// Return Value:
//
inline
DWORD
WidthBytes(
DWORD dwWidth,
DWORD dwBitCount
)
{
return (((dwWidth * dwBitCount) + 31) & ~31) >> 3;
}
//////////////////////////////////////////////////////////////////////////
//
// FXPT_TO_FLPT, FXPT2DOT30_TO_FLPT, FXPT16DOT16_TO_FLPT
//
// Routine Description:
// floating point to fixed point conversion macros
//
// Arguments:
//
// Return Value:
//
inline
double
FXPT_TO_FLPT(
long nFixed,
int nPoint
)
{
double nInteger = nFixed >> nPoint;
double nFraction = ldexp(nFixed & ((1 << nPoint) - 1), -nPoint);
return nInteger + nFraction;
}
inline
double
FXPT2DOT30_TO_FLPT(
FXPT2DOT30 nFixed
)
{
return FXPT_TO_FLPT(nFixed, 30);
}
inline
double
FXPT16DOT16_TO_FLPT(
FXPT16DOT16 nFixed
)
{
return FXPT_TO_FLPT(nFixed, 16);
}
//////////////////////////////////////////////////////////////////////////
//
// Contiguous
//
// Routine Description:
// Tests whether the 1's are contiguous in an integers, i.e. 00000111,
// 00011100, 11100000, 00000000, 11111111 are OK but 00101100 is not
//
// Arguments:
//
// Return Value:
//
template <class T>
BOOL Contiguous(T Bits)
{
const NumBits = sizeof(T) * 8;
T i = 0;
while (i < NumBits && (Bits & (1 << i)) == 0) ++i;
while (i < NumBits && (Bits & (1 << i)) != 0) ++i;
while (i < NumBits && (Bits & (1 << i)) == 0) ++i;
return i == NumBits;
}
//////////////////////////////////////////////////////////////////////////
//
// CheckColorMasks
//
// Routine Description:
// checks the validity of the color masks in a bitfields type bmp.
// the masks should not overlap and the bits should be contiguous
// within each map
//
// Arguments:
//
// Return Value:
//
BOOL
CheckColorMasks(
DWORD dwRedMask,
DWORD dwGreenMask,
DWORD dwBlueMask
)
{
return
(dwRedMask & dwGreenMask) == 0 &&
(dwRedMask & dwBlueMask) == 0 &&
(dwGreenMask & dwBlueMask) == 0 &&
Contiguous(dwRedMask) &&
Contiguous(dwGreenMask) &&
Contiguous(dwBlueMask);
}
//////////////////////////////////////////////////////////////////////////
//
//
//
// Routine Description:
// compares two RGBTRIPLE's
//
// Arguments:
//
// Return Value:
//
inline bool __cdecl operator <(const RGBTRIPLE &lhs, const RGBTRIPLE &rhs)
{
return
RGB(lhs.rgbtRed, lhs.rgbtGreen, lhs.rgbtBlue) <
RGB(rhs.rgbtRed, rhs.rgbtGreen, rhs.rgbtBlue);
}
//////////////////////////////////////////////////////////////////////////
//
//
//
// Routine Description:
//
//
// Arguments:
//
// Return Value:
//
inline void __cdecl LOG_INFO(PCTSTR pFormat, ...)
{
va_list arglist;
va_start(arglist, pFormat);
g_pLog->LogV(TLS_INFO | TLS_VARIATION, 0, 0, pFormat, arglist);
}
inline void __cdecl LOG_ERROR(DWORD dwLogLevel, PCTSTR pFormat, ...)
{
va_list arglist;
va_start(arglist, pFormat);
g_pLog->LogV(dwLogLevel | TLS_VARIATION, 0, 0, pFormat, arglist);
}
//////////////////////////////////////////////////////////////////////////
//
// CheckBmp
//
// Routine Description:
// Main entry point for this module. Checks the validity of a BMP
// file or an in-memory image.
//
// Arguments:
//
// Return Value:
//
BOOL CheckBmp(PVOID pDIB, DWORD dwDIBSize, BOOL bSkipFileHeader)
{
return CCheckBmp().Check(pDIB, dwDIBSize, bSkipFileHeader);
}
BOOL CheckBmp(PCTSTR pszFileName)
{
CInFile TheFile(pszFileName);
CFileMapping TheMap(TheFile, 0, PAGE_READONLY);
CMapViewOfFile<VOID> TheData(TheMap, FILE_MAP_READ);
return CCheckBmp().Check(TheData, GetFileSize(TheFile, 0), FALSE);
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::Check
//
// Routine Description:
//
// Arguments:
//
// Return Value:
//
CCheckBmp::Check(PVOID pDIB, DWORD dwDIBSize, BOOL bSkipFileHeader)
{
ZeroMemory(this, sizeof(*this));
LOG_INFO(szDecVal, _T("DibSize"), dwDIBSize);
m_pDIB = pDIB;
m_nDIBSize = dwDIBSize;
return
(bSkipFileHeader || CheckFileHeader()) &&
CheckBitmapInfo() &&
CheckPalette() &&
CheckPixelData();
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckFileHeader
//
// Routine Description:
// Checks BITMAPFILEHEADER
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckFileHeader()
{
BOOL bResult = TRUE;
m_pFileHeader = m_pDIB;
m_nFileHeaderSize = sizeof(BITMAPFILEHEADER);
PBITMAPFILEHEADER pbmfh = (PBITMAPFILEHEADER) m_pDIB;
// bfType
// should read "BM"
LOG_INFO(szHexVal, _T("Type"), pbmfh->bfType);
if (LOBYTE(pbmfh->bfType) != 'B' || HIBYTE(pbmfh->bfType) != 'M')
{
LOG_ERROR(TLS_SEV2, _T("Unexpected bitmap file type"));
bResult = FALSE;
}
// bfSize
// should equal file size
LOG_INFO(szDecVal, _T("Size"), pbmfh->bfSize);
if (pbmfh->bfSize != m_nDIBSize)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected bitmap file size"));
bResult = FALSE;
}
// bfReserved1, bfReserved2
// should be zero
LOG_INFO(szDecVal, _T("Reserved1"), pbmfh->bfReserved1);
LOG_INFO(szDecVal, _T("Reserved2"), pbmfh->bfReserved2);
if (pbmfh->bfReserved1 != 0 || pbmfh->bfReserved2 != 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Reserved value"));
bResult = FALSE;
}
// bfOffBits
// will be checked in CheckPixelData
LOG_INFO(szDecVal, _T("OffBits"), pbmfh->bfOffBits);
m_pPixelData = (PBYTE) pbmfh + pbmfh->bfOffBits;
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckBitmapInfo
//
// Routine Description:
// Checks the bitmap header according to the header size
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckBitmapInfo()
{
BOOL bResult = TRUE;
m_pInfoHeader = (PBYTE) m_pDIB + m_nFileHeaderSize;
PBITMAPINFO pbmi = (PBITMAPINFO) m_pInfoHeader;
m_nInfoHeaderSize = pbmi->bmiHeader.biSize;
LOG_INFO(szDecVal, _T("Size"), pbmi->bmiHeader.biSize);
switch (pbmi->bmiHeader.biSize)
{
case sizeof(BITMAPCOREHEADER):
bResult = CheckBitmapCoreHeader();
break;
case sizeof(BITMAPINFOHEADER):
bResult = CheckBitmapInfoHeader();
break;
case sizeof(BITMAPV4HEADER):
bResult = CheckBitmapV4Header();
break;
case sizeof(BITMAPV5HEADER):
bResult = CheckBitmapV5Header();
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected header size"));
bResult = FALSE;
}
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckPalette
//
// Routine Description:
// Checks the bitmap color palette
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckPalette()
{
BOOL bResult = TRUE;
m_pPalette = (PBYTE) m_pInfoHeader + m_nInfoHeaderSize;
std::set<RGBTRIPLE> UsedColors;
if (m_nInfoHeaderSize == sizeof(BITMAPCOREHEADER))
{
RGBTRIPLE *prgbt = (RGBTRIPLE *) m_pPalette;
for (int i = 0; i < m_nPaletteSize / sizeof(RGBTRIPLE); ++i)
{
/*LOG_INFO(
_T("Color %3d: R=%02x G=%02x B=%02x"),
i,
prgbt[i].rgbtRed,
prgbt[i].rgbtGreen,
prgbt[i].rgbtBlue
);*/
if (!UsedColors.insert(prgbt[i]).second)
{
LOG_ERROR(
TLS_SEV3,
_T("Repeated palette entry %3d: R=%02x G=%02x B=%02x"),
i,
prgbt[i].rgbtRed,
prgbt[i].rgbtGreen,
prgbt[i].rgbtBlue
);
bResult = FALSE;
}
}
}
else
{
LPRGBQUAD prgbq = (LPRGBQUAD) m_pPalette;
for (int i = 0; i < m_nPaletteSize / sizeof(RGBQUAD); ++i)
{
/*LOG_INFO(
_T("Color %3d: R=%02x G=%02x B=%02x A=%02x"),
i,
prgbq[i].rgbRed,
prgbq[i].rgbGreen,
prgbq[i].rgbBlue,
prgbq[i].rgbReserved
);*/
if (prgbq[i].rgbReserved != 0)
{
LOG_ERROR(
TLS_SEV3,
_T("Unexpected rgbReserved value in palette entry %3d: R=%02x G=%02x B=%02x A=%02x"),
i,
prgbq[i].rgbRed,
prgbq[i].rgbGreen,
prgbq[i].rgbBlue,
prgbq[i].rgbReserved
);
bResult = FALSE;
}
RGBTRIPLE rgbt;
rgbt.rgbtRed = prgbq[i].rgbRed;
rgbt.rgbtGreen = prgbq[i].rgbGreen;
rgbt.rgbtBlue = prgbq[i].rgbBlue;
if (!UsedColors.insert(rgbt).second)
{
LOG_ERROR(
TLS_SEV3,
_T("Repeated palette entry %3d: R=%02x G=%02x B=%02x A=%02x"),
i,
prgbq[i].rgbRed,
prgbq[i].rgbGreen,
prgbq[i].rgbBlue,
prgbq[i].rgbReserved
);
bResult = FALSE;
}
}
}
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckPixelData
//
// Routine Description:
// Checks the bitmap color palette
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckPixelData()
{
BOOL bResult = TRUE;
PVOID pExpectedPixelData = (PBYTE) m_pPalette + m_nPaletteSize;
if (m_pProfile != 0 && m_pProfile <= pExpectedPixelData)
{
pExpectedPixelData = (PBYTE) m_pProfile + m_nProfileSize;
}
if (m_pPixelData != 0 && m_pPixelData != pExpectedPixelData)
{
LOG_ERROR(TLS_SEV3, _T("Unexpected OffBits value"));
bResult = FALSE;
}
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckBitmapCoreHeader
//
// Routine Description:
// Checks BITMAPCOREHEADER
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckBitmapCoreHeader()
{
BOOL bResult = TRUE;
PBITMAPCOREHEADER pbih = (PBITMAPCOREHEADER) m_pInfoHeader;
// bcWidth
// should be positive
LOG_INFO(szDecVal, _T("Width"), pbih->bcWidth);
if (pbih->bcWidth <= 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Width value"));
bResult = FALSE;
}
// bcHeight
// should be positive
LOG_INFO(szDecVal, _T("Height"), pbih->bcHeight);
if (pbih->bcHeight <= 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Height value"));
bResult = FALSE;
}
// bcPlanes
// should be 1
LOG_INFO(szDecVal, _T("Planes"), pbih->bcPlanes);
if (pbih->bcPlanes != 1)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Planes value"));
}
// bcBitCount
// can be 1, 4, 8 or 24
LOG_INFO(szDecVal, _T("BitCount"), pbih->bcBitCount);
switch (pbih->bcBitCount)
{
case 1:
case 4:
case 8:
m_nPaletteSize = (1 << pbih->bcBitCount) * sizeof(RGBTRIPLE);
break;
case 24:
m_nPaletteSize = 0;
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value"));
bResult = FALSE;
break;
}
m_nPixelDataSize =
WidthBytes(pbih->bcWidth, pbih->bcBitCount) * pbih->bcHeight;
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckBitmapInfoHeader
//
// Routine Description:
// Checks BITMAPINFOHEADER
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckBitmapInfoHeader()
{
PBITMAPINFOHEADER pbih = (PBITMAPINFOHEADER) m_pInfoHeader;
BOOL bResult = TRUE;
// biWidth
// should be positive
LOG_INFO(szDecVal, _T("Width"), pbih->biWidth);
if (pbih->biWidth <= 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Width value"));
bResult = FALSE;
}
// biHeight
// should not be zero, if negative, should be BI_RGB or BI_BITFIELDS
LOG_INFO(szDecVal, _T("Height"), pbih->biHeight);
if (pbih->biHeight == 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Height value"));
bResult = FALSE;
}
if (pbih->biHeight < 0)
{
switch (pbih->biCompression)
{
case BI_RGB:
case BI_BITFIELDS:
case BI_JPEG:
case BI_PNG:
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected Compression value for negative Height"));
bResult = FALSE;
break;
}
}
// biPlanes
// should be 1
LOG_INFO(szDecVal, _T("Planes"), pbih->biPlanes);
if (pbih->biPlanes != 1)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Planes value"));
}
// biBitCount
// can be 0 (only for BI_JPEG or BI_PNG), 1, 4, 8, 16, 24 or 32
LOG_INFO(szDecVal, _T("BitCount"), pbih->biBitCount);
switch (pbih->biBitCount)
{
case 0:
switch (pbih->biCompression)
{
case BI_JPEG:
case BI_PNG:
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected Compression value for zero BitCount"));
bResult = FALSE;
break;
}
break;
case 1:
case 4:
case 8:
m_nPaletteSize = (1 << pbih->biBitCount) * sizeof(RGBQUAD);
break;
case 16:
case 24:
case 32:
m_nPaletteSize = 0;
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value"));
bResult = FALSE;
break;
}
// biCompression
switch (pbih->biCompression)
{
case BI_RGB:
LOG_INFO(szStrVal, _T("Compression"), _T("BI_RGB"));
break;
case BI_RLE8:
LOG_INFO(szStrVal, _T("Compression"), _T("BI_RLE8"));
if (pbih->biBitCount != 8)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value for BI_RLE8"));
bResult = FALSE;
}
break;
case BI_RLE4:
LOG_INFO(szStrVal, _T("Compression"), _T("BI_RLE4"));
if (pbih->biBitCount != 4)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount value for BI_RLE4"));
bResult = FALSE;
}
break;
case BI_BITFIELDS:
{
LOG_INFO(szStrVal, _T("Compression"), _T("BI_BITFIELDS"));
DWORD dwRedMask = ((PDWORD)(pbih + 1))[0];
DWORD dwGreenMask = ((PDWORD)(pbih + 1))[1];
DWORD dwBlueMask = ((PDWORD)(pbih + 1))[2];
if (pbih->biSize == sizeof(BITMAPINFOHEADER))
{
m_nInfoHeaderSize += 3 * sizeof(DWORD);
LOG_INFO(szHexVal, _T("RedMask"), dwRedMask);
LOG_INFO(szHexVal, _T("GreenMask"), dwGreenMask);
LOG_INFO(szHexVal, _T("BlueMask"), dwBlueMask);
}
switch (pbih->biBitCount)
{
case 16:
if (
(dwRedMask != 0x7C00 || dwGreenMask != 0x03E0 || dwBlueMask != 0x001F) &&
(dwRedMask != 0xF800 || dwGreenMask != 0x07E0 || dwBlueMask != 0x001F)
)
{
LOG_ERROR(TLS_WARN, _T("Unexpected color masks for Win9x BI_BITFIELDS"));
}
else
{
if ((dwRedMask | dwGreenMask | dwBlueMask) & 0xFFFF0000)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected color masks for 16-bit BI_BITFIELDS"));
bResult = FALSE;
}
if (!CheckColorMasks(dwRedMask, dwGreenMask, dwBlueMask))
{
LOG_ERROR(TLS_SEV2, _T("Unexpected color masks for BI_BITFIELDS"));
bResult = FALSE;
}
}
break;
case 32:
if (dwRedMask != 0x00FF0000 || dwGreenMask != 0x0000FF00 || dwBlueMask != 0x000000FF)
{
LOG_ERROR(TLS_WARN, _T("Unexpected color masks for Win9x BI_BITFIELDS"));
}
else
{
if (!CheckColorMasks(dwRedMask, dwGreenMask, dwBlueMask))
{
LOG_ERROR(TLS_SEV2, _T("Unexpected color masks for BI_BITFIELDS"));
bResult = FALSE;
}
}
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected BitCount for BI_BITFIELDS"));
bResult = FALSE;
break;
}
break;
}
case BI_JPEG:
LOG_INFO(szStrVal, _T("Compression"), _T("BI_JPEG"));
break;
case BI_PNG:
LOG_INFO(szStrVal, _T("Compression"), _T("BI_PNG"));
break;
default:
LOG_INFO(szDecVal, _T("Compression"), pbih->biCompression);
LOG_ERROR(TLS_SEV2, _T("Unexpected Compression value"));
bResult = FALSE;
break;
}
// biSizeImage
// should not be negative, can be zero only for BI_RGB
LOG_INFO(szDecVal, _T("SizeImage"), pbih->biSizeImage);
if ((LONG) pbih->biSizeImage < 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected SizeImage value"));
bResult = FALSE;
}
m_nPixelDataSize =
WidthBytes(Abs(pbih->biWidth), pbih->biBitCount) * Abs(pbih->biHeight);
if (pbih->biSizeImage != 0)
{
if (pbih->biCompression == BI_RGB && m_nPixelDataSize != pbih->biSizeImage)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected SizeImage value"));
bResult = FALSE;
}
m_nPixelDataSize = pbih->biSizeImage;
}
else
{
if (pbih->biCompression != BI_RGB)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected SizeImage value for non BI_RGB bitmap"));
bResult = FALSE;
}
}
// biClrUsed
// should not be greater than the max number of bitdepth colors
LOG_INFO(szDecVal, _T("ClrUsed"), pbih->biClrUsed);
if (pbih->biClrUsed != 0)
{
if (pbih->biBitCount < 16 && pbih->biClrUsed * sizeof(RGBQUAD) > m_nPaletteSize)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected ClrUsed value for the BitCount"));
bResult = FALSE;
}
else
{
m_nPaletteSize = pbih->biClrUsed * sizeof(RGBQUAD);
}
}
// biClrImportant
// should be equal to or less than biClrUsed
LOG_INFO(szDecVal, _T("ClrImportant"), pbih->biClrImportant);
if (pbih->biClrUsed != 0 && pbih->biClrImportant > pbih->biClrUsed)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected ClrImportant value"));
bResult = FALSE;
}
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckBitmapV4Header
//
// Routine Description:
// Checks BITMAPV4HEADER
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckBitmapV4Header()
{
BOOL bResult = CheckBitmapInfoHeader();
PBITMAPV4HEADER pbih = (PBITMAPV4HEADER) m_pInfoHeader;
// bV4RedMask, bV4GreenMask, bV4BlueMask, bV4AlphaMask
// already checked in the info header
LOG_INFO(szHexVal, _T("RedMask"), pbih->bV4RedMask);
LOG_INFO(szHexVal, _T("GreenMask"), pbih->bV4GreenMask);
LOG_INFO(szHexVal, _T("BlueMask"), pbih->bV4BlueMask);
LOG_INFO(szHexVal, _T("AlphaMask"), pbih->bV4AlphaMask);
// bV4CSType
// should be one of LCS_ types
switch (pbih->bV4CSType)
{
case LCS_CALIBRATED_RGB:
LOG_INFO(szStrVal, _T("CSType"), _T("LCS_CALIBRATED_RGB"));
break;
case LCS_sRGB:
LOG_INFO(szStrVal, _T("CSType"), _T("LCS_sRGB"));
break;
case LCS_WINDOWS_COLOR_SPACE:
LOG_INFO(szStrVal, _T("CSType"), _T("LCS_WINDOWS_COLOR_SPACE"));
break;
case PROFILE_LINKED:
LOG_INFO(szStrVal, _T("CSType"), _T("PROFILE_LINKED"));
break;
case PROFILE_EMBEDDED:
LOG_INFO(szStrVal, _T("CSType"), _T("PROFILE_EMBEDDED"));
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected CSType value"));
bResult = FALSE;
break;
}
// bV4Endpoints, bV4GammaRed, bV4GammaGreen, bV4GammaBlue
// should be present only for LCS_CALIBRATED_RGB
LOG_INFO(szDblVal, _T("EndpointRedX"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzRed.ciexyzX));
LOG_INFO(szDblVal, _T("EndpointRedY"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzRed.ciexyzY));
LOG_INFO(szDblVal, _T("EndpointRedZ"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzRed.ciexyzZ));
LOG_INFO(szDblVal, _T("EndpointGreenX"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzGreen.ciexyzX));
LOG_INFO(szDblVal, _T("EndpointGreenY"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzGreen.ciexyzY));
LOG_INFO(szDblVal, _T("EndpointGreenZ"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzGreen.ciexyzZ));
LOG_INFO(szDblVal, _T("EndpointBlueX"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzBlue.ciexyzX));
LOG_INFO(szDblVal, _T("EndpointBlueY"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzBlue.ciexyzY));
LOG_INFO(szDblVal, _T("EndpointBlueZ"), FXPT2DOT30_TO_FLPT(pbih->bV4Endpoints.ciexyzBlue.ciexyzZ));
LOG_INFO(szDblVal, _T("GammaRed"), FXPT16DOT16_TO_FLPT(pbih->bV4GammaRed));
LOG_INFO(szDblVal, _T("GammaGreen"), FXPT16DOT16_TO_FLPT(pbih->bV4GammaGreen));
LOG_INFO(szDblVal, _T("GammaBlue"), FXPT16DOT16_TO_FLPT(pbih->bV4GammaBlue));
if (pbih->bV4CSType != LCS_CALIBRATED_RGB)
{
// bugbug: how can I check a valid colorspace?
if (
pbih->bV4Endpoints.ciexyzRed.ciexyzX != 0 ||
pbih->bV4Endpoints.ciexyzRed.ciexyzY != 0 ||
pbih->bV4Endpoints.ciexyzRed.ciexyzZ != 0 ||
pbih->bV4Endpoints.ciexyzGreen.ciexyzX != 0 ||
pbih->bV4Endpoints.ciexyzGreen.ciexyzY != 0 ||
pbih->bV4Endpoints.ciexyzGreen.ciexyzZ != 0 ||
pbih->bV4Endpoints.ciexyzBlue.ciexyzX != 0 ||
pbih->bV4Endpoints.ciexyzBlue.ciexyzY != 0 ||
pbih->bV4Endpoints.ciexyzBlue.ciexyzZ != 0 ||
pbih->bV4GammaRed != 0 ||
pbih->bV4GammaGreen != 0 ||
pbih->bV4GammaBlue != 0
)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected colorspace values for CSType"));
bResult = FALSE;
}
}
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CCheckBmp::CheckBitmapV5Header
//
// Routine Description:
// Checks BITMAPV5HEADER
//
// Arguments:
//
// Return Value:
//
BOOL CCheckBmp::CheckBitmapV5Header()
{
BOOL bResult = CheckBitmapV4Header();
PBITMAPV5HEADER pbih = (PBITMAPV5HEADER) m_pInfoHeader;
// bV5Intent
// should be one of the LCS_ values
switch (pbih->bV5Intent)
{
case LCS_GM_BUSINESS:
LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_BUSINESS"));
break;
case LCS_GM_GRAPHICS:
LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_GRAPHICS"));
break;
case LCS_GM_IMAGES:
LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_IMAGES"));
break;
case LCS_GM_ABS_COLORIMETRIC:
LOG_INFO(szStrVal, _T("Intent"), _T("LCS_GM_ABS_COLORIMETRIC"));
break;
default:
LOG_ERROR(TLS_SEV2, _T("Unexpected Intent value"));
bResult = FALSE;
break;
}
// bV5ProfileData, bV5ProfileSize
// check profile data
LOG_INFO(szDecVal, _T("ProfileData"), pbih->bV5ProfileData);
LOG_INFO(szDecVal, _T("ProfileSize"), pbih->bV5ProfileSize);
switch (pbih->bV5CSType)
{
case LCS_CALIBRATED_RGB:
case LCS_sRGB:
case LCS_WINDOWS_COLOR_SPACE:
if (pbih->bV5ProfileData != 0 || pbih->bV5ProfileSize != 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected profile info for CSType"));
bResult = FALSE;
}
break;
case PROFILE_LINKED:
{
PCSTR pName = (PCSTR) ((PBYTE) pbih + pbih->bV5ProfileData);
if (MultiByteToWideChar(1252, MB_ERR_INVALID_CHARS, pName, -1, 0, 0) == 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected profile name for PROFILE_LINKED"));
bResult = FALSE;
}
// continue,
}
case PROFILE_EMBEDDED:
if (pbih->bV5ProfileData == 0 || pbih->bV5ProfileSize == 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected profile info for CSType"));
bResult = FALSE;
}
m_pProfile = (PBYTE) pbih + pbih->bV5ProfileData;
m_nProfileSize = pbih->bV5ProfileSize;
break;
}
// Reserved
// should be zero
LOG_INFO(szHexVal, _T("Reserved"), pbih->bV5Reserved);
if (pbih->bV5Reserved != 0)
{
LOG_ERROR(TLS_SEV2, _T("Unexpected Reserved value"));
bResult = FALSE;
}
return bResult;
}
//////////////////////////////////////////////////////////////////////////
//
// CheckBMPMain
//
// Routine Description:
// _tmain() function in case someone runs this as a standalone program
//
// Arguments:
//
// Return Value:
//
void CheckBMPMain()
{
AllocCRTConsole();
INT argc;
CGlobalMem<PTSTR> argv(CommandLineToArgv(GetCommandLine(), &argc));
CFullPathName FileName(argv[1]);
for (
CFindFile FindFile(FileName);
FindFile.Found();
FindFile.FindNextFile()
)
{
FileName.SetFileName(FindFile.cFileName);
LOG_INFO(FileName);
CheckBmp((PCTSTR) FileName);
}
}