    /****************************************************************************/
    /*                                                                          */
    /*                 Copyright (C) 1987-1996 Microsoft Corp.                */
    /*                           All Rights Reserved                            */
    /*                                                                          */
    /****************************************************************************/
    /****************************** Module Header *******************************
    * Module Name: rwbmp.c
    *
    * Routines for reading and writing bitmap files.
    *
    * History:
    *
    ****************************************************************************/
    
    #include "imagedit.h"
    
    #include <stdio.h>
    #include <io.h>
    #include <fcntl.h>                          // For NT fstat().
    #include <sys\types.h>                      // For fstat() types.
    #include <sys\stat.h>                       // For fstat() function.
    
    
    
    /************************************************************************
    * LoadBitmapFile
    *
    * Loads the specified bitmap file.  With ImagEdit, this must be a
    * Windows 3.0 DIB.
    *
    * Arguments:
    *   PSTR pszFullFileName - Name of the bitmap file to load.
    *
    * Returns:
    *   TRUE if successful, FALSE otherwise.
    *
    * History:
    *
    ************************************************************************/
    
    BOOL LoadBitmapFile(
        PSTR pszFullFileName)
    {
        HFILE hf;
        OFSTRUCT OfStruct;
        struct stat FileStatus;
        DWORD dwFileSize;
        DWORD dwDIBSize;
        BITMAPFILEHEADER bfh;
        BITMAPINFOHEADER bih;
        PIMAGEINFO pImage;
        INT nColors;
        HANDLE hDIB;
        PDEVICE pDevice;
    
        if ((hf = (HFILE)OpenFile(pszFullFileName, (LPOFSTRUCT)&OfStruct, OF_READ))
                == (HFILE)-1) {
            Message(MSG_CANTOPEN, pszFullFileName);
            return FALSE;
        }
    
        fstat((INT)_open_osfhandle((long)(hf), (int)(O_RDONLY)), &FileStatus);
        dwFileSize = (DWORD)FileStatus.st_size;
    
        ImageLinkFreeList();
    
        /*
         * Read the Bitmap File Header.
         */
        if (!MyFileRead(hf, (LPSTR)&bfh, sizeof(BITMAPFILEHEADER),
                pszFullFileName, FT_BITMAP))
            goto Error1;
    
        /*
         * Check for the "BM" at the start of the file, and the file size
         * in the header must match the real file size.
         */
        if (bfh.bfType != 0x4D42 || bfh.bfSize != dwFileSize) {
            Message(MSG_BADBMPFILE, pszFullFileName);
            goto Error1;
        }
    
        /*
         * Read the Bitmap Info Header.
         */
        if (!MyFileRead(hf, (LPSTR)&bih, sizeof(BITMAPINFOHEADER),
                pszFullFileName, FT_BITMAP))
            goto Error1;
    
        /*
         * The DIB size should be the size of the file less the bitmap
         * file header.
         */
        dwDIBSize = dwFileSize - sizeof(BITMAPFILEHEADER);
    
        if (!IsValidDIB((LPBITMAPINFO)&bih, dwDIBSize, FALSE)) {
            Message(MSG_BADBMPFILE, pszFullFileName);
            goto Error1;
        }
    
        /*
         * There is a limit to the size of image we will edit.  For icons
         * and cursors, the field that carries the dimensions is a byte,
         * so the size cannot be greater than 256.  This is also what
         * we limit bitmaps to.
         */
        if (bih.biWidth > MAXIMAGEDIM || bih.biHeight > MAXIMAGEDIM) {
            Message(MSG_BADBMPSIZE, MAXIMAGEDIM, MAXIMAGEDIM);
            goto Error1;
        }
    
        switch (bih.biBitCount) {
            case 1:
                nColors = 2;
                break;
    
            case 4:
                nColors = 16;
                break;
    
            default:
                Message(MSG_NOTSUPPORT);
                goto Error1;
        }
    
        if (!(pDevice = DeviceLinkAlloc(FT_BITMAP, NULL, nColors,
                (INT)bih.biWidth, (INT)bih.biHeight))) {
            goto Error1;
        }
    
        if (!(pImage = ImageLinkAlloc(pDevice,
                (INT)bih.biWidth, (INT)bih.biHeight, 0, 0, nColors)))
            goto Error1;
    
        /*
         * Allocate space for the DIB for this image.
         */
        if (!(hDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize))) {
            Message(MSG_OUTOFMEMORY);
            goto Error2;
        }
    
        pImage->DIBSize = dwDIBSize;
        pImage->DIBhandle = hDIB;
        pImage->DIBPtr = (LPSTR)GlobalLock(hDIB);
    
        /*
         * Jump back to the start of the DIB.
         */
        SetFilePointer((HANDLE)hf, sizeof(BITMAPFILEHEADER), NULL, (DWORD)0);
    
        /*
         * Read the entire DIB (including info and color table) into
         * the allocated memory for it.
         */
        if (!MyFileRead(hf, pImage->DIBPtr, (DWORD)pImage->DIBSize,
                pszFullFileName, FT_BITMAP))
            goto Error2;
    
        _lclose((HFILE)hf);
    
        fFileDirty = FALSE;
        SetFileName(pszFullFileName);
        giType = FT_BITMAP;
    
        /*
         * Bitmaps only have one "image" in the file.
         */
        gnImages = 1;
    
        ImageOpen2(pImage);
    
        return TRUE;
    
    Error2:
        ImageLinkFreeList();
    
    Error1:
        _lclose((HFILE)hf);
    
        return FALSE;
    }
    
    
    
    /************************************************************************
    * SaveBitmapFile
    *
    *
    *
    * Arguments:
    *
    * Returns:
    *   TRUE if successful, FALSE otherwise.
    *
    * History:
    *
    ************************************************************************/
    
    BOOL SaveBitmapFile(
        PSTR pszFullFileName)
    {
        HCURSOR hcurOld;
        BITMAPFILEHEADER bfh;
        HFILE hf;
        OFSTRUCT OfStruct;
    
        hcurOld = SetCursor(hcurWait);
    
        /*
         * Save the bits of the current image.
         */
        ImageSave();
    
        /*
         * Open the file for writing.
         */
        if ((hf = (HFILE)OpenFile(pszFullFileName, &OfStruct, OF_CREATE | OF_READWRITE))
                == (HFILE)-1) {
            Message(MSG_CANTCREATE, pszFullFileName);
            goto Error1;
        }
    
        bfh.bfType = 0x4D42;
        bfh.bfSize = sizeof(BITMAPFILEHEADER) + gpImageCur->DIBSize;
        bfh.bfReserved1 = 0;
        bfh.bfReserved2 = 0;
        bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
                (gpImageCur->nColors * sizeof(RGBQUAD));
    
        /*
         * Write the header to disk.
         */
        if (!MyFileWrite(hf, (LPSTR)&bfh, sizeof(BITMAPFILEHEADER),
                pszFullFileName))
            goto Error2;
    
        /*
         * Now write the DIB (a bitmap file only has one).
         */
        if (!MyFileWrite(hf, (LPSTR)gpImageCur->DIBPtr,
                (DWORD)gpImageCur->DIBSize, pszFullFileName))
            goto Error2;
    
        _lclose((HFILE)hf);
    
        fFileDirty = FALSE;
        SetFileName(pszFullFileName);
    
        SetCursor(hcurOld);
    
        return TRUE;
    
    Error2:
        _lclose((HFILE)hf);
    
    Error1:
        SetCursor(hcurOld);
    
        return FALSE;
    }
