CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

DIBFILE.CPP (22104B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 //*******************************************************************
     17 //
     18 //  file.c
     19 //
     20 //  Source file for Device-Independent Bitmap (DIB) API.  Provides
     21 //  the following functions:
     22 //
     23 //  SaveDIB()           - Saves the specified dib in a file
     24 //  LoadDIB()           - Loads a DIB from a file
     25 //  DestroyDIB()        - Deletes DIB when finished using it
     26 //
     27 // Development Team: Mark Bader
     28 //                   Patrick Schreiber
     29 //                   Garrett McAuliffe
     30 //                   Eric Flo
     31 //                   Tony Claflin
     32 //
     33 // Written by Microsoft Product Support Services, Developer Support.
     34 // COPYRIGHT:
     35 //
     36 //   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
     37 //
     38 //   You have a royalty-free right to use, modify, reproduce and
     39 //   distribute the Sample Files (and/or any modified version) in
     40 //   any way you find useful, provided that you agree that
     41 //   Microsoft has no warranty obligations or liability for any
     42 //   Sample Application Files which are modified.
     43 //
     44 //*******************************************************************
     45 #if (0) // ST - 5/8/2019
     46 
     47 #include <windows.h>
     48 #include <string.h>
     49 #include <stdio.h>
     50 #include <math.h>
     51 #include <io.h>
     52 #include <direct.h>
     53 #include <stdlib.h>
     54 #include "dibutil.h"
     55 #include "dibapi.h"
     56 
     57 //#include "WolDebug.h"
     58 
     59 /*
     60  * Dib Header Marker - used in writing DIBs to files
     61  */
     62 #define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')
     63 
     64 /*********************************************************************
     65  *
     66  * Local Function Prototypes
     67  *
     68  *********************************************************************/
     69 
     70 
     71 HANDLE ReadDIBFile(int);
     72 BOOL MyRead(int, LPSTR, DWORD);
     73 BOOL SaveDIBFile(void);
     74 BOOL WriteDIB(LPSTR, HANDLE);
     75 DWORD PASCAL MyWrite(int, VOID FAR *, DWORD);
     76 
     77 /*************************************************************************
     78  *
     79  * LoadDIB()
     80  *
     81  * Loads the specified DIB from a file, allocates memory for it,
     82  * and reads the disk file into the memory.
     83  *
     84  *
     85  * Parameters:
     86  *
     87  * LPSTR lpFileName - specifies the file to load a DIB from
     88  *
     89  * Returns: A handle to a DIB, or NULL if unsuccessful.
     90  *
     91  * NOTE: The DIB API were not written to handle OS/2 DIBs; This
     92  * function will reject any file that is not a Windows DIB.
     93  *
     94  * History:   Date      Author       Reason
     95  *            9/15/91   Mark Bader   Based on DIBVIEW
     96  *
     97  *************************************************************************/
     98 
     99 
    100 HDIB FAR LoadDIB(LPSTR lpFileName)
    101 {
    102    HDIB hDIB;
    103    int hFile;
    104    OFSTRUCT ofs;
    105 
    106    /*
    107     * Set the cursor to a hourglass, in case the loading operation
    108     * takes more than a sec, the user will know what's going on.
    109     */
    110 
    111    SetCursor(LoadCursor(NULL, IDC_WAIT));
    112    if ((hFile = OpenFile(lpFileName, &ofs, OF_READ)) != -1)
    113    {
    114       hDIB = ReadDIBFile(hFile);
    115       _lclose(hFile);
    116       SetCursor(LoadCursor(NULL, IDC_ARROW));
    117       return hDIB;
    118    }
    119    else
    120    {
    121 //      DIBError(ERR_FILENOTFOUND);
    122       SetCursor(LoadCursor(NULL, IDC_ARROW));
    123       return NULL;
    124    }
    125 }
    126 
    127 
    128 /*************************************************************************
    129  *
    130  * SaveDIB()
    131  *
    132  * Saves the specified DIB into the specified file name on disk.  No
    133  * error checking is done, so if the file already exists, it will be
    134  * written over.
    135  *
    136  * Parameters:
    137  *
    138  * HDIB hDib - Handle to the dib to save
    139  *
    140  * LPSTR lpFileName - pointer to full pathname to save DIB under
    141  *
    142  * Return value: 0 if successful, or one of:
    143  *        ERR_INVALIDHANDLE
    144  *        ERR_OPEN
    145  *        ERR_LOCK
    146  *
    147  * History:
    148  *
    149  * NOTE: The DIB API were not written to handle OS/2 DIBs, so this
    150  * function will not save a file if it is not a Windows DIB.
    151  *
    152  * History:   Date      Author       Reason
    153  *            9/15/91   Mark Bader   Taken from DIBVIEW (which was taken
    154  *                                      from SHOWDIB)
    155  *            1/30/92   Mark Bader   Fixed problem of writing too many 
    156  *                                      bytes to the file
    157  *            6/24/92   Mark Bader   Added check for OS/2 DIB
    158  *
    159  *************************************************************************/
    160 
    161 
    162 WORD FAR SaveDIB(HDIB hDib, LPSTR lpFileName)
    163 {
    164    BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
    165    LPBITMAPINFOHEADER lpBI;   // Pointer to DIB info structure
    166    int fh;     // file handle for opened file
    167    OFSTRUCT of;     // OpenFile structure
    168    DWORD dwDIBSize;
    169    DWORD dwError;   // Error return from MyWrite
    170 
    171    if (!hDib)
    172       return ERR_INVALIDHANDLE;
    173    fh = OpenFile(lpFileName, &of, OF_CREATE | OF_READWRITE);
    174    if (fh == -1)
    175       return ERR_OPEN;
    176 
    177    /*
    178     * Get a pointer to the DIB memory, the first of which contains
    179     * a BITMAPINFO structure
    180     */
    181    lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
    182    if (!lpBI)
    183       return ERR_LOCK;
    184 
    185    // Check to see if we're dealing with an OS/2 DIB.  If so, don't
    186    // save it because our functions aren't written to deal with these
    187    // DIBs.
    188 
    189    if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
    190    {
    191      GlobalUnlock(hDib);
    192      return ERR_NOT_DIB;
    193    }
    194 
    195    /*
    196     * Fill in the fields of the file header
    197     */
    198 
    199    /* Fill in file type (first 2 bytes must be "BM" for a bitmap) */
    200    bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"
    201 
    202    // Calculating the size of the DIB is a bit tricky (if we want to
    203    // do it right).  The easiest way to do this is to call GlobalSize()
    204    // on our global handle, but since the size of our global memory may have
    205    // been padded a few bytes, we may end up writing out a few too
    206    // many bytes to the file (which may cause problems with some apps,
    207    // like HC 3.0).
    208    //
    209    // So, instead let's calculate the size manually.
    210    //
    211    // To do this, find size of header plus size of color table.  Since the
    212    // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
    213    // the size of the structure, let's use this.
    214 
    215    dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI);  // Partial Calculation
    216 
    217    // Now calculate the size of the image
    218 
    219    if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) {
    220 
    221       // It's an RLE bitmap, we can't calculate size, so trust the
    222       // biSizeImage field
    223 
    224       dwDIBSize += lpBI->biSizeImage;
    225       }
    226    else {
    227       DWORD dwBmBitsSize;  // Size of Bitmap Bits only
    228 
    229       // It's not RLE, so size is Width (DWORD aligned) * Height
    230 
    231       dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
    232 
    233       dwDIBSize += dwBmBitsSize;
    234       
    235       // Now, since we have calculated the correct size, why don't we
    236       // fill in the biSizeImage field (this will fix any .BMP files which 
    237       // have this field incorrect).
    238 
    239       lpBI->biSizeImage = dwBmBitsSize;
    240       }
    241 
    242 
    243    // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
    244                    
    245    bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
    246    bmfHdr.bfReserved1 = 0;
    247    bmfHdr.bfReserved2 = 0;
    248 
    249    /*
    250     * Now, calculate the offset the actual bitmap bits will be in
    251     * the file -- It's the Bitmap file header plus the DIB header,
    252     * plus the size of the color table.
    253     */
    254    bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
    255                       PaletteSize((LPSTR)lpBI);
    256 
    257    /* Write the file header */
    258    _lwrite(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
    259 
    260    /*
    261     * Write the DIB header and the bits -- use local version of
    262     * MyWrite, so we can write more than 32767 bytes of data
    263     */
    264    dwError = MyWrite(fh, (LPSTR)lpBI, dwDIBSize);
    265    GlobalUnlock(hDib);
    266    _lclose(fh);
    267 
    268    if (dwError == 0)
    269      return ERR_OPEN; // oops, something happened in the write
    270    else
    271      return 0; // Success code
    272 }
    273 
    274 
    275 /*************************************************************************
    276  *
    277  * DestroyDIB ()
    278  *
    279  * Purpose:  Frees memory associated with a DIB
    280  *
    281  * Returns:  Nothing
    282  *
    283  * History:   Date      Author       Reason
    284  *            9/15/91   Mark Bader   Created
    285  *
    286  *************************************************************************/
    287 
    288 
    289 WORD FAR DestroyDIB(HDIB hDib)
    290 {
    291    GlobalFree(hDib);
    292    return 0;
    293 }
    294 
    295 
    296 //************************************************************************
    297 //
    298 // Auxiliary Functions which the above procedures use
    299 //
    300 //************************************************************************
    301 
    302 
    303 /*************************************************************************
    304  *
    305  * Function:  ReadDIBFile (int)
    306  *
    307  *  Purpose:  Reads in the specified DIB file into a global chunk of
    308  *            memory.
    309  *
    310  *  Returns:  A handle to a dib (hDIB) if successful.
    311  *            NULL if an error occurs.
    312  *
    313  * Comments:  BITMAPFILEHEADER is stripped off of the DIB.  Everything
    314  *            from the end of the BITMAPFILEHEADER structure on is
    315  *            returned in the global memory handle.
    316  *
    317  *
    318  * NOTE: The DIB API were not written to handle OS/2 DIBs, so this
    319  * function will reject any file that is not a Windows DIB.
    320  *
    321  * History:   Date      Author       Reason
    322  *            9/15/91   Mark Bader   Based on DIBVIEW
    323  *            6/25/92   Mark Bader   Added check for OS/2 DIB
    324  *            7/21/92   Mark Bader   Added code to deal with bfOffBits
    325  *                                     field in BITMAPFILEHEADER      
    326  *            9/11/92   Mark Bader   Fixed Realloc Code to free original mem
    327  *
    328  *************************************************************************/
    329 
    330 HANDLE ReadDIBFile(int hFile)
    331 {
    332    BITMAPFILEHEADER bmfHeader;
    333    DWORD dwBitsSize;
    334    UINT nNumColors;   // Number of colors in table
    335    HANDLE hDIB;        
    336    HANDLE hDIBtmp;    // Used for GlobalRealloc() //MPB
    337    LPBITMAPINFOHEADER lpbi;
    338    DWORD offBits;
    339 
    340    /*
    341     * get length of DIB in bytes for use when reading
    342     */
    343 
    344    dwBitsSize = filelength(hFile);
    345 
    346    // Allocate memory for header & color table.	We'll enlarge this
    347    // memory as needed.
    348 
    349    hDIB = GlobalAlloc(GMEM_MOVEABLE,
    350        (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
    351    
    352    if (!hDIB) return NULL;
    353 
    354    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
    355    if (!lpbi) 
    356    {
    357      GlobalFree(hDIB);
    358      return NULL;
    359    }
    360 
    361    // read the BITMAPFILEHEADER from our file
    362 
    363    if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
    364      goto ErrExit;
    365 
    366    if (bmfHeader.bfType != 0x4d42)	/* 'BM' */
    367      goto ErrExit;
    368 
    369    // read the BITMAPINFOHEADER
    370 
    371    if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
    372      goto ErrExit;
    373 
    374    // Check to see that it's a Windows DIB -- an OS/2 DIB would cause
    375    // strange problems with the rest of the DIB API since the fields
    376    // in the header are different and the color table entries are
    377    // smaller.
    378    //
    379    // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
    380 
    381    if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
    382      goto ErrExit;
    383 
    384    // Now determine the size of the color table and read it.  Since the
    385    // bitmap bits are offset in the file by bfOffBits, we need to do some
    386    // special processing here to make sure the bits directly follow
    387    // the color table (because that's the format we are susposed to pass
    388    // back)
    389    nNumColors = (UINT)lpbi->biClrUsed;
    390    if (!nNumColors)
    391     {
    392       // no color table for 24-bit, default size otherwise
    393       if (lpbi->biBitCount != 24)
    394         nNumColors = 1 << lpbi->biBitCount; /* standard size table */
    395     }
    396 
    397    // fill in some default values if they are zero
    398    if (lpbi->biClrUsed == 0)
    399      lpbi->biClrUsed = nNumColors;
    400 
    401    if (lpbi->biSizeImage == 0)
    402    {
    403      lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
    404 			 * lpbi->biHeight;
    405    }
    406 
    407    // get a proper-sized buffer for header, color table and bits
    408    GlobalUnlock(hDIB);
    409    hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize +
    410                         nNumColors * sizeof(RGBQUAD) +
    411                         lpbi->biSizeImage, 0);
    412 
    413    if (!hDIBtmp) // can't resize buffer for loading
    414      goto ErrExitNoUnlock; //MPB
    415    else
    416      hDIB = hDIBtmp;
    417 
    418    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
    419 
    420    // read the color table
    421    _lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
    422 
    423    // offset to the bits from start of DIB header
    424    offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
    425 
    426    // If the bfOffBits field is non-zero, then the bits might *not* be
    427    // directly following the color table in the file.  Use the value in
    428    // bfOffBits to seek the bits.
    429 
    430    if (bmfHeader.bfOffBits != 0L)
    431       _llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
    432    
    433    if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
    434      goto OKExit;
    435 
    436 
    437 ErrExit:
    438     GlobalUnlock(hDIB);    
    439 ErrExitNoUnlock:    
    440     GlobalFree(hDIB);
    441     return NULL;
    442 
    443 OKExit:
    444     GlobalUnlock(hDIB);
    445     return hDIB;
    446 }
    447 
    448 /*************************************************************************
    449 
    450   Function:  MyRead (int, LPSTR, DWORD)
    451 
    452    Purpose:  Routine to read files greater than 64K in size.
    453 
    454    Returns:  TRUE if successful.
    455              FALSE if an error occurs.
    456 
    457   
    458   History:   Date      Author       Reason
    459              9/15/91   Mark Bader   Based on DIBVIEW
    460  
    461 *************************************************************************/
    462 
    463 
    464 BOOL MyRead(int hFile, LPSTR lpBuffer, DWORD dwSize)
    465 {
    466    char huge *lpInBuf = (char huge *)lpBuffer;
    467    int nBytes;
    468 
    469    /*
    470     * Read in the data in 32767 byte chunks (or a smaller amount if it's
    471     * the last chunk of data read)
    472     */
    473 
    474    while (dwSize)
    475    {
    476       nBytes = (int)(dwSize > (DWORD)32767 ? 32767 : LOWORD (dwSize));
    477       if (_lread(hFile, (LPSTR)lpInBuf, nBytes) != (WORD)nBytes)
    478          return FALSE;
    479       dwSize -= nBytes;
    480       lpInBuf += nBytes;
    481    }
    482    return TRUE;
    483 }
    484 
    485 
    486 /****************************************************************************
    487 
    488  FUNCTION   : MyWrite(int fh, VOID FAR *pv, DWORD ul)
    489 
    490  PURPOSE    : Writes data in steps of 32k till all the data is written.
    491               Normal _lwrite uses a WORD as 3rd parameter, so it is
    492               limited to 32767 bytes, but this procedure is not.
    493 
    494  RETURNS    : 0 - If write did not proceed correctly.
    495               number of bytes written otherwise.
    496  
    497   History:   Date      Author       Reason
    498              9/15/91   Mark Bader   Based on DIBVIEW
    499 
    500  ****************************************************************************/
    501 
    502 
    503 DWORD PASCAL MyWrite(int iFileHandle, VOID FAR *lpBuffer, DWORD dwBytes)
    504 {
    505    DWORD dwBytesTmp = dwBytes;       // Save # of bytes for return value
    506    BYTE huge *hpBuffer = (BYTE huge *)lpBuffer;   // make a huge pointer to the data
    507 
    508    /*
    509     * Write out the data in 32767 byte chunks.
    510     */
    511 
    512    while (dwBytes > 32767)
    513    {
    514       if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)32767) != 32767)
    515          return 0;
    516       dwBytes -= 32767;
    517       hpBuffer += 32767;
    518    }
    519 
    520    /* Write out the last chunk (which is < 32767 bytes) */
    521    if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)dwBytes) != (WORD)dwBytes)
    522       return 0;
    523    return dwBytesTmp;
    524 }
    525 
    526 //	ajw added
    527 //	Added to allow "loading" from a location in memory.
    528 //	A modification of ReadDIBFile(), above.
    529 //***********************************************************************************************
    530 HDIB LoadDIB_FromMemory( const unsigned char* pData, DWORD dwBitsSize )
    531 {
    532 	BITMAPFILEHEADER bmfHeader;
    533 	UINT nNumColors;   // Number of colors in table
    534 	HANDLE hDIB;        
    535 	HANDLE hDIBtmp;    // Used for GlobalRealloc() //MPB
    536 	LPBITMAPINFOHEADER lpbi;
    537 	DWORD offBits;
    538 
    539 	const unsigned char* const pDataStart = pData;
    540 	const unsigned char* pDataEnd = pData + dwBitsSize;		//	One char past end of "file".
    541 
    542 	// Allocate memory for header & color table.	We'll enlarge this
    543 	// memory as needed.
    544 
    545 //	debugprint( "LoadDIB_FromMemory, GlobalAlloc\n" );
    546 	hDIB = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
    547 //	debugprint( "hDIB from GlobalALloc is %i\n", hDIB );
    548 
    549 	if (!hDIB)
    550 	{
    551 //		debugprint( "LoadDIB_FromMemory error: failed alloc\n" );
    552 		return NULL;
    553 	}
    554 
    555 //	debugprint( "LoadDIB_FromMemory, lpbi Lock\n" );
    556 	lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
    557 //	debugprint( "lpbi is %i\n", lpbi );
    558 	if (!lpbi) 
    559 	{
    560 //		debugprint( "LoadDIB_FromMemory error: failed lock\n" );
    561 		GlobalFree(hDIB);
    562 		return NULL;
    563 	}
    564 
    565 	// read the BITMAPFILEHEADER from our file
    566 //	if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
    567 //		goto ErrExit;
    568 	if( pData + sizeof( BITMAPFILEHEADER ) >= pDataEnd )
    569 	{
    570 //		debugprint( "LoadDIB_FromMemory error: bad size\n" );
    571 		goto ErrExit;
    572 	}
    573 //	debugprint( "LoadDIB_FromMemory, memcpy BITMAPFILEHEADER %i bytes\n", sizeof( BITMAPFILEHEADER ) );
    574 	memcpy( &bmfHeader, pData, sizeof( BITMAPFILEHEADER ) );
    575 	pData += sizeof( BITMAPFILEHEADER );
    576 
    577 	if (bmfHeader.bfType != 0x4d42)	/* 'BM' */
    578 	{
    579 //		debugprint( "LoadDIB_FromMemory error: no BM\n" );
    580 		goto ErrExit;
    581 	}
    582 
    583 	// read the BITMAPINFOHEADER
    584 //	if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
    585 //		goto ErrExit;
    586 	if( pData + sizeof( BITMAPINFOHEADER ) >= pDataEnd )
    587 	{
    588 //		debugprint( "LoadDIB_FromMemory error: bad size 2\n" );
    589 		goto ErrExit;
    590 	}
    591 //	debugprint( "LoadDIB_FromMemory, memcpy BITMAPINFOHEADER %i bytes\n", sizeof( BITMAPINFOHEADER ) );
    592 	memcpy( lpbi, pData, sizeof( BITMAPINFOHEADER ) );
    593 	pData += sizeof( BITMAPINFOHEADER );
    594 
    595 	// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
    596 	// strange problems with the rest of the DIB API since the fields
    597 	// in the header are different and the color table entries are
    598 	// smaller.
    599 	//
    600 	// If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
    601 
    602 	if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
    603 	{
    604 //		debugprint( "LoadDIB_FromMemory error: lpbi->biSize bad\n" );
    605 		goto ErrExit;
    606 	}
    607 
    608 	if( lpbi->biCompression != BI_RGB )
    609 	{
    610 //		debugprint( "LoadDIB_FromMemory error: Image is compressed\n" );
    611 		goto ErrExit;
    612 	}
    613 
    614 	// Now determine the size of the color table and read it.  Since the
    615 	// bitmap bits are offset in the file by bfOffBits, we need to do some
    616 	// special processing here to make sure the bits directly follow
    617 	// the color table (because that's the format we are susposed to pass
    618 	// back)
    619 	nNumColors = (UINT)lpbi->biClrUsed;
    620 	if (!nNumColors)
    621 	{
    622 		// no color table for 24-bit, default size otherwise
    623 		if (lpbi->biBitCount != 24)
    624 			nNumColors = 1 << lpbi->biBitCount; /* standard size table */
    625 	}
    626 
    627 	// fill in some default values if they are zero
    628 	if (lpbi->biClrUsed == 0)
    629 		lpbi->biClrUsed = nNumColors;
    630 
    631 //	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 );
    632 	if (lpbi->biSizeImage == 0)
    633 	{
    634 		lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) * lpbi->biHeight;
    635 	}
    636 
    637 	// get a proper-sized buffer for header, color table and bits
    638 	GlobalUnlock(hDIB);
    639 //	debugprint( "LoadDIB_FromMemory, GlobalReAlloc: lpbi->biSize=%i, nNumColors=%i, lpbi->biSizeImage=%i\n", lpbi->biSize, nNumColors,lpbi->biSizeImage );
    640 	hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize + nNumColors * sizeof(RGBQUAD) + lpbi->biSizeImage, 0);
    641 
    642 	if (!hDIBtmp) // can't resize buffer for loading
    643 	{
    644 //		debugprint( "LoadDIB_FromMemory error: realloc failed\n" );
    645 		goto ErrExitNoUnlock; //MPB
    646 	}
    647 	else
    648 		hDIB = hDIBtmp;
    649 
    650 	lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
    651 
    652 	// read the color table
    653 //	_lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
    654 //	debugprint( "LoadDIB_FromMemory, memcpy color table %i colors, so %i bytes\n", nNumColors, nNumColors * sizeof(RGBQUAD) );
    655 	memcpy( (LPSTR)(lpbi) + lpbi->biSize, pData, nNumColors * sizeof(RGBQUAD) );
    656 	pData += nNumColors * sizeof(RGBQUAD);
    657 
    658 	// offset to the bits from start of DIB header
    659 	offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
    660 
    661 	// If the bfOffBits field is non-zero, then the bits might *not* be
    662 	// directly following the color table in the file.  Use the value in
    663 	// bfOffBits to seek the bits.
    664 
    665 	if (bmfHeader.bfOffBits != 0L)
    666 //		_llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
    667 		pData = pDataStart + bmfHeader.bfOffBits;
    668 
    669 //	debugprint( "bmfHeader.bfOffBits is %i\n", bmfHeader.bfOffBits );
    670 
    671 //	if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
    672 //		goto OKExit;
    673 //	debugprint( "Checking that pData(%i) + biSizeImage(%i), which is %i, is equal to pDataEnd(%i)\n", 
    674 //					pData, lpbi->biSizeImage, pData + lpbi->biSizeImage, pDataEnd );
    675 //	if( pData + lpbi->biSizeImage != pDataEnd )			condition relaxed
    676 //	{
    677 //		debugprint( "LoadDIB_FromMemory error: bad size 3\n" );
    678 //		goto ErrExit;
    679 //	}
    680 
    681 //	debugprint( "LoadDIB_FromMemory, memcpy the bits, %i bytes. Image is w %i, h.%i\n", 
    682 //								lpbi->biSizeImage, lpbi->biWidth, lpbi->biHeight );
    683 //	debugprint( "Writing to lpbi (%i) + offBits (%i)\n", lpbi, offBits );
    684 
    685 	memcpy( (LPSTR)lpbi + offBits, pData, lpbi->biSizeImage );
    686 //	pData += lpbi->biSizeImage;
    687 //	if( pData != pDataEnd )		//	Should end up one byte past end of data. - condition relaxed
    688 //		debugprint( "LoadDIB_FromMemory: ERROR! Ended up at %i instead of %i\n", pData, pDataEnd );
    689 	goto OKExit;
    690 
    691 ErrExit:
    692 	GlobalUnlock(hDIB);
    693 ErrExitNoUnlock:    
    694 	GlobalFree(hDIB);
    695 //	debugprint( "LoadDIB_FromMemory Error!\n" );
    696 	return NULL;
    697 
    698 OKExit:
    699 	GlobalUnlock(hDIB);
    700 	return hDIB;
    701 }
    702 #endif