702 lines
22 KiB
C++
702 lines
22 KiB
C++
|
//
|
||
|
// Copyright 2020 Electronic Arts Inc.
|
||
|
//
|
||
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
|
||
|
// software: you can redistribute it and/or modify it under the terms of
|
||
|
// the GNU General Public License as published by the Free Software Foundation,
|
||
|
// either version 3 of the License, or (at your option) any later version.
|
||
|
|
||
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
|
||
|
// in the hope that it will be useful, but with permitted additional restrictions
|
||
|
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
|
||
|
// distributed with this program. You should have received a copy of the
|
||
|
// GNU General Public License along with permitted additional restrictions
|
||
|
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
|
||
|
|
||
|
//*******************************************************************
|
||
|
//
|
||
|
// file.c
|
||
|
//
|
||
|
// Source file for Device-Independent Bitmap (DIB) API. Provides
|
||
|
// the following functions:
|
||
|
//
|
||
|
// SaveDIB() - Saves the specified dib in a file
|
||
|
// LoadDIB() - Loads a DIB from a file
|
||
|
// DestroyDIB() - Deletes DIB when finished using it
|
||
|
//
|
||
|
// Development Team: Mark Bader
|
||
|
// Patrick Schreiber
|
||
|
// Garrett McAuliffe
|
||
|
// Eric Flo
|
||
|
// Tony Claflin
|
||
|
//
|
||
|
// Written by Microsoft Product Support Services, Developer Support.
|
||
|
// COPYRIGHT:
|
||
|
//
|
||
|
// (C) Copyright Microsoft Corp. 1993. All rights reserved.
|
||
|
//
|
||
|
// You have a royalty-free right to use, modify, reproduce and
|
||
|
// distribute the Sample Files (and/or any modified version) in
|
||
|
// any way you find useful, provided that you agree that
|
||
|
// Microsoft has no warranty obligations or liability for any
|
||
|
// Sample Application Files which are modified.
|
||
|
//
|
||
|
//*******************************************************************
|
||
|
#if (0) // ST - 5/8/2019
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <math.h>
|
||
|
#include <io.h>
|
||
|
#include <direct.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "dibutil.h"
|
||
|
#include "dibapi.h"
|
||
|
|
||
|
//#include "WolDebug.h"
|
||
|
|
||
|
/*
|
||
|
* Dib Header Marker - used in writing DIBs to files
|
||
|
*/
|
||
|
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
|
||
|
|
||
|
/*********************************************************************
|
||
|
*
|
||
|
* Local Function Prototypes
|
||
|
*
|
||
|
*********************************************************************/
|
||
|
|
||
|
|
||
|
HANDLE ReadDIBFile(int);
|
||
|
BOOL MyRead(int, LPSTR, DWORD);
|
||
|
BOOL SaveDIBFile(void);
|
||
|
BOOL WriteDIB(LPSTR, HANDLE);
|
||
|
DWORD PASCAL MyWrite(int, VOID FAR *, DWORD);
|
||
|
|
||
|
/*************************************************************************
|
||
|
*
|
||
|
* LoadDIB()
|
||
|
*
|
||
|
* Loads the specified DIB from a file, allocates memory for it,
|
||
|
* and reads the disk file into the memory.
|
||
|
*
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* LPSTR lpFileName - specifies the file to load a DIB from
|
||
|
*
|
||
|
* Returns: A handle to a DIB, or NULL if unsuccessful.
|
||
|
*
|
||
|
* NOTE: The DIB API were not written to handle OS/2 DIBs; This
|
||
|
* function will reject any file that is not a Windows DIB.
|
||
|
*
|
||
|
* History: Date Author Reason
|
||
|
* 9/15/91 Mark Bader Based on DIBVIEW
|
||
|
*
|
||
|
*************************************************************************/
|
||
|
|
||
|
|
||
|
HDIB FAR LoadDIB(LPSTR lpFileName)
|
||
|
{
|
||
|
HDIB hDIB;
|
||
|
int hFile;
|
||
|
OFSTRUCT ofs;
|
||
|
|
||
|
/*
|
||
|
* Set the cursor to a hourglass, in case the loading operation
|
||
|
* takes more than a sec, the user will know what's going on.
|
||
|
*/
|
||
|
|
||
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
||
|
if ((hFile = OpenFile(lpFileName, &ofs, OF_READ)) != -1)
|
||
|
{
|
||
|
hDIB = ReadDIBFile(hFile);
|
||
|
_lclose(hFile);
|
||
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||
|
return hDIB;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// DIBError(ERR_FILENOTFOUND);
|
||
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
*
|
||
|
* SaveDIB()
|
||
|
*
|
||
|
* Saves the specified DIB into the specified file name on disk. No
|
||
|
* error checking is done, so if the file already exists, it will be
|
||
|
* written over.
|
||
|
*
|
||
|
* Parameters:
|
||
|
*
|
||
|
* HDIB hDib - Handle to the dib to save
|
||
|
*
|
||
|
* LPSTR lpFileName - pointer to full pathname to save DIB under
|
||
|
*
|
||
|
* Return value: 0 if successful, or one of:
|
||
|
* ERR_INVALIDHANDLE
|
||
|
* ERR_OPEN
|
||
|
* ERR_LOCK
|
||
|
*
|
||
|
* History:
|
||
|
*
|
||
|
* NOTE: The DIB API were not written to handle OS/2 DIBs, so this
|
||
|
* function will not save a file if it is not a Windows DIB.
|
||
|
*
|
||
|
* History: Date Author Reason
|
||
|
* 9/15/91 Mark Bader Taken from DIBVIEW (which was taken
|
||
|
* from SHOWDIB)
|
||
|
* 1/30/92 Mark Bader Fixed problem of writing too many
|
||
|
* bytes to the file
|
||
|
* 6/24/92 Mark Bader Added check for OS/2 DIB
|
||
|
*
|
||
|
*************************************************************************/
|
||
|
|
||
|
|
||
|
WORD FAR SaveDIB(HDIB hDib, LPSTR lpFileName)
|
||
|
{
|
||
|
BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
|
||
|
LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
|
||
|
int fh; // file handle for opened file
|
||
|
OFSTRUCT of; // OpenFile structure
|
||
|
DWORD dwDIBSize;
|
||
|
DWORD dwError; // Error return from MyWrite
|
||
|
|
||
|
if (!hDib)
|
||
|
return ERR_INVALIDHANDLE;
|
||
|
fh = OpenFile(lpFileName, &of, OF_CREATE | OF_READWRITE);
|
||
|
if (fh == -1)
|
||
|
return ERR_OPEN;
|
||
|
|
||
|
/*
|
||
|
* Get a pointer to the DIB memory, the first of which contains
|
||
|
* a BITMAPINFO structure
|
||
|
*/
|
||
|
lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
|
||
|
if (!lpBI)
|
||
|
return ERR_LOCK;
|
||
|
|
||
|
// Check to see if we're dealing with an OS/2 DIB. If so, don't
|
||
|
// save it because our functions aren't written to deal with these
|
||
|
// DIBs.
|
||
|
|
||
|
if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
|
||
|
{
|
||
|
GlobalUnlock(hDib);
|
||
|
return ERR_NOT_DIB;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Fill in the fields of the file header
|
||
|
*/
|
||
|
|
||
|
/* Fill in file type (first 2 bytes must be "BM" for a bitmap) */
|
||
|
bmfHdr.bfType = DIB_HEADER_MARKER; // "BM"
|
||
|
|
||
|
// Calculating the size of the DIB is a bit tricky (if we want to
|
||
|
// do it right). The easiest way to do this is to call GlobalSize()
|
||
|
// on our global handle, but since the size of our global memory may have
|
||
|
// been padded a few bytes, we may end up writing out a few too
|
||
|
// many bytes to the file (which may cause problems with some apps,
|
||
|
// like HC 3.0).
|
||
|
//
|
||
|
// So, instead let's calculate the size manually.
|
||
|
//
|
||
|
// To do this, find size of header plus size of color table. Since the
|
||
|
// first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
|
||
|
// the size of the structure, let's use this.
|
||
|
|
||
|
dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI); // Partial Calculation
|
||
|
|
||
|
// Now calculate the size of the image
|
||
|
|
||
|
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) {
|
||
|
|
||
|
// It's an RLE bitmap, we can't calculate size, so trust the
|
||
|
// biSizeImage field
|
||
|
|
||
|
dwDIBSize += lpBI->biSizeImage;
|
||
|
}
|
||
|
else {
|
||
|
DWORD dwBmBitsSize; // Size of Bitmap Bits only
|
||
|
|
||
|
// It's not RLE, so size is Width (DWORD aligned) * Height
|
||
|
|
||
|
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
|
||
|
|
||
|
dwDIBSize += dwBmBitsSize;
|
||
|
|
||
|
// Now, since we have calculated the correct size, why don't we
|
||
|
// fill in the biSizeImage field (this will fix any .BMP files which
|
||
|
// have this field incorrect).
|
||
|
|
||
|
lpBI->biSizeImage = dwBmBitsSize;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
|
||
|
|
||
|
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
|
||
|
bmfHdr.bfReserved1 = 0;
|
||
|
bmfHdr.bfReserved2 = 0;
|
||
|
|
||
|
/*
|
||
|
* Now, calculate the offset the actual bitmap bits will be in
|
||
|
* the file -- It's the Bitmap file header plus the DIB header,
|
||
|
* plus the size of the color table.
|
||
|
*/
|
||
|
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
|
||
|
PaletteSize((LPSTR)lpBI);
|
||
|
|
||
|
/* Write the file header */
|
||
|
_lwrite(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
|
||
|
|
||
|
/*
|
||
|
* Write the DIB header and the bits -- use local version of
|
||
|
* MyWrite, so we can write more than 32767 bytes of data
|
||
|
*/
|
||
|
dwError = MyWrite(fh, (LPSTR)lpBI, dwDIBSize);
|
||
|
GlobalUnlock(hDib);
|
||
|
_lclose(fh);
|
||
|
|
||
|
if (dwError == 0)
|
||
|
return ERR_OPEN; // oops, something happened in the write
|
||
|
else
|
||
|
return 0; // Success code
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
*
|
||
|
* DestroyDIB ()
|
||
|
*
|
||
|
* Purpose: Frees memory associated with a DIB
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
* History: Date Author Reason
|
||
|
* 9/15/91 Mark Bader Created
|
||
|
*
|
||
|
*************************************************************************/
|
||
|
|
||
|
|
||
|
WORD FAR DestroyDIB(HDIB hDib)
|
||
|
{
|
||
|
GlobalFree(hDib);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//************************************************************************
|
||
|
//
|
||
|
// Auxiliary Functions which the above procedures use
|
||
|
//
|
||
|
//************************************************************************
|
||
|
|
||
|
|
||
|
/*************************************************************************
|
||
|
*
|
||
|
* Function: ReadDIBFile (int)
|
||
|
*
|
||
|
* Purpose: Reads in the specified DIB file into a global chunk of
|
||
|
* memory.
|
||
|
*
|
||
|
* Returns: A handle to a dib (hDIB) if successful.
|
||
|
* NULL if an error occurs.
|
||
|
*
|
||
|
* Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything
|
||
|
* from the end of the BITMAPFILEHEADER structure on is
|
||
|
* returned in the global memory handle.
|
||
|
*
|
||
|
*
|
||
|
* NOTE: The DIB API were not written to handle OS/2 DIBs, so this
|
||
|
* function will reject any file that is not a Windows DIB.
|
||
|
*
|
||
|
* History: Date Author Reason
|
||
|
* 9/15/91 Mark Bader Based on DIBVIEW
|
||
|
* 6/25/92 Mark Bader Added check for OS/2 DIB
|
||
|
* 7/21/92 Mark Bader Added code to deal with bfOffBits
|
||
|
* field in BITMAPFILEHEADER
|
||
|
* 9/11/92 Mark Bader Fixed Realloc Code to free original mem
|
||
|
*
|
||
|
*************************************************************************/
|
||
|
|
||
|
HANDLE ReadDIBFile(int hFile)
|
||
|
{
|
||
|
BITMAPFILEHEADER bmfHeader;
|
||
|
DWORD dwBitsSize;
|
||
|
UINT nNumColors; // Number of colors in table
|
||
|
HANDLE hDIB;
|
||
|
HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB
|
||
|
LPBITMAPINFOHEADER lpbi;
|
||
|
DWORD offBits;
|
||
|
|
||
|
/*
|
||
|
* get length of DIB in bytes for use when reading
|
||
|
*/
|
||
|
|
||
|
dwBitsSize = filelength(hFile);
|
||
|
|
||
|
// Allocate memory for header & color table. We'll enlarge this
|
||
|
// memory as needed.
|
||
|
|
||
|
hDIB = GlobalAlloc(GMEM_MOVEABLE,
|
||
|
(DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
|
||
|
|
||
|
if (!hDIB) return NULL;
|
||
|
|
||
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
||
|
if (!lpbi)
|
||
|
{
|
||
|
GlobalFree(hDIB);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// read the BITMAPFILEHEADER from our file
|
||
|
|
||
|
if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
|
||
|
goto ErrExit;
|
||
|
|
||
|
if (bmfHeader.bfType != 0x4d42) /* 'BM' */
|
||
|
goto ErrExit;
|
||
|
|
||
|
// read the BITMAPINFOHEADER
|
||
|
|
||
|
if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
|
||
|
goto ErrExit;
|
||
|
|
||
|
// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
|
||
|
// strange problems with the rest of the DIB API since the fields
|
||
|
// in the header are different and the color table entries are
|
||
|
// smaller.
|
||
|
//
|
||
|
// If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
|
||
|
|
||
|
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
|
||
|
goto ErrExit;
|
||
|
|
||
|
// Now determine the size of the color table and read it. Since the
|
||
|
// bitmap bits are offset in the file by bfOffBits, we need to do some
|
||
|
// special processing here to make sure the bits directly follow
|
||
|
// the color table (because that's the format we are susposed to pass
|
||
|
// back)
|
||
|
nNumColors = (UINT)lpbi->biClrUsed;
|
||
|
if (!nNumColors)
|
||
|
{
|
||
|
// no color table for 24-bit, default size otherwise
|
||
|
if (lpbi->biBitCount != 24)
|
||
|
nNumColors = 1 << lpbi->biBitCount; /* standard size table */
|
||
|
}
|
||
|
|
||
|
// fill in some default values if they are zero
|
||
|
if (lpbi->biClrUsed == 0)
|
||
|
lpbi->biClrUsed = nNumColors;
|
||
|
|
||
|
if (lpbi->biSizeImage == 0)
|
||
|
{
|
||
|
lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
|
||
|
* lpbi->biHeight;
|
||
|
}
|
||
|
|
||
|
// get a proper-sized buffer for header, color table and bits
|
||
|
GlobalUnlock(hDIB);
|
||
|
hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize +
|
||
|
nNumColors * sizeof(RGBQUAD) +
|
||
|
lpbi->biSizeImage, 0);
|
||
|
|
||
|
if (!hDIBtmp) // can't resize buffer for loading
|
||
|
goto ErrExitNoUnlock; //MPB
|
||
|
else
|
||
|
hDIB = hDIBtmp;
|
||
|
|
||
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
||
|
|
||
|
// read the color table
|
||
|
_lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
|
||
|
|
||
|
// offset to the bits from start of DIB header
|
||
|
offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
|
||
|
|
||
|
// If the bfOffBits field is non-zero, then the bits might *not* be
|
||
|
// directly following the color table in the file. Use the value in
|
||
|
// bfOffBits to seek the bits.
|
||
|
|
||
|
if (bmfHeader.bfOffBits != 0L)
|
||
|
_llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
|
||
|
|
||
|
if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
|
||
|
goto OKExit;
|
||
|
|
||
|
|
||
|
ErrExit:
|
||
|
GlobalUnlock(hDIB);
|
||
|
ErrExitNoUnlock:
|
||
|
GlobalFree(hDIB);
|
||
|
return NULL;
|
||
|
|
||
|
OKExit:
|
||
|
GlobalUnlock(hDIB);
|
||
|
return hDIB;
|
||
|
}
|
||
|
|
||
|
/*************************************************************************
|
||
|
|
||
|
Function: MyRead (int, LPSTR, DWORD)
|
||
|
|
||
|
Purpose: Routine to read files greater than 64K in size.
|
||
|
|
||
|
Returns: TRUE if successful.
|
||
|
FALSE if an error occurs.
|
||
|
|
||
|
|
||
|
History: Date Author Reason
|
||
|
9/15/91 Mark Bader Based on DIBVIEW
|
||
|
|
||
|
*************************************************************************/
|
||
|
|
||
|
|
||
|
BOOL MyRead(int hFile, LPSTR lpBuffer, DWORD dwSize)
|
||
|
{
|
||
|
char huge *lpInBuf = (char huge *)lpBuffer;
|
||
|
int nBytes;
|
||
|
|
||
|
/*
|
||
|
* Read in the data in 32767 byte chunks (or a smaller amount if it's
|
||
|
* the last chunk of data read)
|
||
|
*/
|
||
|
|
||
|
while (dwSize)
|
||
|
{
|
||
|
nBytes = (int)(dwSize > (DWORD)32767 ? 32767 : LOWORD (dwSize));
|
||
|
if (_lread(hFile, (LPSTR)lpInBuf, nBytes) != (WORD)nBytes)
|
||
|
return FALSE;
|
||
|
dwSize -= nBytes;
|
||
|
lpInBuf += nBytes;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
FUNCTION : MyWrite(int fh, VOID FAR *pv, DWORD ul)
|
||
|
|
||
|
PURPOSE : Writes data in steps of 32k till all the data is written.
|
||
|
Normal _lwrite uses a WORD as 3rd parameter, so it is
|
||
|
limited to 32767 bytes, but this procedure is not.
|
||
|
|
||
|
RETURNS : 0 - If write did not proceed correctly.
|
||
|
number of bytes written otherwise.
|
||
|
|
||
|
History: Date Author Reason
|
||
|
9/15/91 Mark Bader Based on DIBVIEW
|
||
|
|
||
|
****************************************************************************/
|
||
|
|
||
|
|
||
|
DWORD PASCAL MyWrite(int iFileHandle, VOID FAR *lpBuffer, DWORD dwBytes)
|
||
|
{
|
||
|
DWORD dwBytesTmp = dwBytes; // Save # of bytes for return value
|
||
|
BYTE huge *hpBuffer = (BYTE huge *)lpBuffer; // make a huge pointer to the data
|
||
|
|
||
|
/*
|
||
|
* Write out the data in 32767 byte chunks.
|
||
|
*/
|
||
|
|
||
|
while (dwBytes > 32767)
|
||
|
{
|
||
|
if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)32767) != 32767)
|
||
|
return 0;
|
||
|
dwBytes -= 32767;
|
||
|
hpBuffer += 32767;
|
||
|
}
|
||
|
|
||
|
/* Write out the last chunk (which is < 32767 bytes) */
|
||
|
if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)dwBytes) != (WORD)dwBytes)
|
||
|
return 0;
|
||
|
return dwBytesTmp;
|
||
|
}
|
||
|
|
||
|
// ajw added
|
||
|
// Added to allow "loading" from a location in memory.
|
||
|
// A modification of ReadDIBFile(), above.
|
||
|
//***********************************************************************************************
|
||
|
HDIB LoadDIB_FromMemory( const unsigned char* pData, DWORD dwBitsSize )
|
||
|
{
|
||
|
BITMAPFILEHEADER bmfHeader;
|
||
|
UINT nNumColors; // Number of colors in table
|
||
|
HANDLE hDIB;
|
||
|
HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB
|
||
|
LPBITMAPINFOHEADER lpbi;
|
||
|
DWORD offBits;
|
||
|
|
||
|
const unsigned char* const pDataStart = pData;
|
||
|
const unsigned char* pDataEnd = pData + dwBitsSize; // One char past end of "file".
|
||
|
|
||
|
// Allocate memory for header & color table. We'll enlarge this
|
||
|
// memory as needed.
|
||
|
|
||
|
// debugprint( "LoadDIB_FromMemory, GlobalAlloc\n" );
|
||
|
hDIB = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
|
||
|
// debugprint( "hDIB from GlobalALloc is %i\n", hDIB );
|
||
|
|
||
|
if (!hDIB)
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: failed alloc\n" );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// debugprint( "LoadDIB_FromMemory, lpbi Lock\n" );
|
||
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
||
|
// debugprint( "lpbi is %i\n", lpbi );
|
||
|
if (!lpbi)
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: failed lock\n" );
|
||
|
GlobalFree(hDIB);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// read the BITMAPFILEHEADER from our file
|
||
|
// if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
|
||
|
// goto ErrExit;
|
||
|
if( pData + sizeof( BITMAPFILEHEADER ) >= pDataEnd )
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: bad size\n" );
|
||
|
goto ErrExit;
|
||
|
}
|
||
|
// debugprint( "LoadDIB_FromMemory, memcpy BITMAPFILEHEADER %i bytes\n", sizeof( BITMAPFILEHEADER ) );
|
||
|
memcpy( &bmfHeader, pData, sizeof( BITMAPFILEHEADER ) );
|
||
|
pData += sizeof( BITMAPFILEHEADER );
|
||
|
|
||
|
if (bmfHeader.bfType != 0x4d42) /* 'BM' */
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: no BM\n" );
|
||
|
goto ErrExit;
|
||
|
}
|
||
|
|
||
|
// read the BITMAPINFOHEADER
|
||
|
// if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
|
||
|
// goto ErrExit;
|
||
|
if( pData + sizeof( BITMAPINFOHEADER ) >= pDataEnd )
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: bad size 2\n" );
|
||
|
goto ErrExit;
|
||
|
}
|
||
|
// debugprint( "LoadDIB_FromMemory, memcpy BITMAPINFOHEADER %i bytes\n", sizeof( BITMAPINFOHEADER ) );
|
||
|
memcpy( lpbi, pData, sizeof( BITMAPINFOHEADER ) );
|
||
|
pData += sizeof( BITMAPINFOHEADER );
|
||
|
|
||
|
// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
|
||
|
// strange problems with the rest of the DIB API since the fields
|
||
|
// in the header are different and the color table entries are
|
||
|
// smaller.
|
||
|
//
|
||
|
// If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
|
||
|
|
||
|
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: lpbi->biSize bad\n" );
|
||
|
goto ErrExit;
|
||
|
}
|
||
|
|
||
|
if( lpbi->biCompression != BI_RGB )
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: Image is compressed\n" );
|
||
|
goto ErrExit;
|
||
|
}
|
||
|
|
||
|
// Now determine the size of the color table and read it. Since the
|
||
|
// bitmap bits are offset in the file by bfOffBits, we need to do some
|
||
|
// special processing here to make sure the bits directly follow
|
||
|
// the color table (because that's the format we are susposed to pass
|
||
|
// back)
|
||
|
nNumColors = (UINT)lpbi->biClrUsed;
|
||
|
if (!nNumColors)
|
||
|
{
|
||
|
// no color table for 24-bit, default size otherwise
|
||
|
if (lpbi->biBitCount != 24)
|
||
|
nNumColors = 1 << lpbi->biBitCount; /* standard size table */
|
||
|
}
|
||
|
|
||
|
// fill in some default values if they are zero
|
||
|
if (lpbi->biClrUsed == 0)
|
||
|
lpbi->biClrUsed = nNumColors;
|
||
|
|
||
|
// debugprint( "biSizeImage is %i. I would say it was %i, because the bpp is %i.\n", lpbi->biSizeImage, ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) * lpbi->biHeight, lpbi->biBitCount );
|
||
|
if (lpbi->biSizeImage == 0)
|
||
|
{
|
||
|
lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) * lpbi->biHeight;
|
||
|
}
|
||
|
|
||
|
// get a proper-sized buffer for header, color table and bits
|
||
|
GlobalUnlock(hDIB);
|
||
|
// debugprint( "LoadDIB_FromMemory, GlobalReAlloc: lpbi->biSize=%i, nNumColors=%i, lpbi->biSizeImage=%i\n", lpbi->biSize, nNumColors,lpbi->biSizeImage );
|
||
|
hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize + nNumColors * sizeof(RGBQUAD) + lpbi->biSizeImage, 0);
|
||
|
|
||
|
if (!hDIBtmp) // can't resize buffer for loading
|
||
|
{
|
||
|
// debugprint( "LoadDIB_FromMemory error: realloc failed\n" );
|
||
|
goto ErrExitNoUnlock; //MPB
|
||
|
}
|
||
|
else
|
||
|
hDIB = hDIBtmp;
|
||
|
|
||
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
||
|
|
||
|
// read the color table
|
||
|
// _lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
|
||
|
// debugprint( "LoadDIB_FromMemory, memcpy color table %i colors, so %i bytes\n", nNumColors, nNumColors * sizeof(RGBQUAD) );
|
||
|
memcpy( (LPSTR)(lpbi) + lpbi->biSize, pData, nNumColors * sizeof(RGBQUAD) );
|
||
|
pData += nNumColors * sizeof(RGBQUAD);
|
||
|
|
||
|
// offset to the bits from start of DIB header
|
||
|
offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
|
||
|
|
||
|
// If the bfOffBits field is non-zero, then the bits might *not* be
|
||
|
// directly following the color table in the file. Use the value in
|
||
|
// bfOffBits to seek the bits.
|
||
|
|
||
|
if (bmfHeader.bfOffBits != 0L)
|
||
|
// _llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
|
||
|
pData = pDataStart + bmfHeader.bfOffBits;
|
||
|
|
||
|
// debugprint( "bmfHeader.bfOffBits is %i\n", bmfHeader.bfOffBits );
|
||
|
|
||
|
// if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
|
||
|
// goto OKExit;
|
||
|
// debugprint( "Checking that pData(%i) + biSizeImage(%i), which is %i, is equal to pDataEnd(%i)\n",
|
||
|
// pData, lpbi->biSizeImage, pData + lpbi->biSizeImage, pDataEnd );
|
||
|
// if( pData + lpbi->biSizeImage != pDataEnd ) condition relaxed
|
||
|
// {
|
||
|
// debugprint( "LoadDIB_FromMemory error: bad size 3\n" );
|
||
|
// goto ErrExit;
|
||
|
// }
|
||
|
|
||
|
// debugprint( "LoadDIB_FromMemory, memcpy the bits, %i bytes. Image is w %i, h.%i\n",
|
||
|
// lpbi->biSizeImage, lpbi->biWidth, lpbi->biHeight );
|
||
|
// debugprint( "Writing to lpbi (%i) + offBits (%i)\n", lpbi, offBits );
|
||
|
|
||
|
memcpy( (LPSTR)lpbi + offBits, pData, lpbi->biSizeImage );
|
||
|
// pData += lpbi->biSizeImage;
|
||
|
// if( pData != pDataEnd ) // Should end up one byte past end of data. - condition relaxed
|
||
|
// debugprint( "LoadDIB_FromMemory: ERROR! Ended up at %i instead of %i\n", pData, pDataEnd );
|
||
|
goto OKExit;
|
||
|
|
||
|
ErrExit:
|
||
|
GlobalUnlock(hDIB);
|
||
|
ErrExitNoUnlock:
|
||
|
GlobalFree(hDIB);
|
||
|
// debugprint( "LoadDIB_FromMemory Error!\n" );
|
||
|
return NULL;
|
||
|
|
||
|
OKExit:
|
||
|
GlobalUnlock(hDIB);
|
||
|
return hDIB;
|
||
|
}
|
||
|
#endif
|