home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / imagedit / rwicocur.c < prev    next >
Text File  |  1996-06-12  |  14KB  |  417 lines

  1.     /****************************************************************************/
  2.     /*                                                                          */
  3.     /*                 Copyright (C) 1987-1996 Microsoft Corp.                */
  4.     /*                           All Rights Reserved                            */
  5.     /*                                                                          */
  6.     /****************************************************************************/
  7.     /****************************** Module Header *******************************
  8.     * Module Name: rwicocur.c
  9.     *
  10.     * Routines to read and write icon and cursor files.
  11.     *
  12.     * History:
  13.     *
  14.     ****************************************************************************/
  15.     
  16.     #include "imagedit.h"
  17.     
  18.     #include <io.h>
  19.     #include <fcntl.h>                          // For NT fstat().
  20.     #include <sys\types.h>                      // For fstat() types.
  21.     #include <sys\stat.h>                       // For fstat() function.
  22.     
  23.     
  24.     
  25.     /************************************************************************
  26.     * LoadIconCursorFile
  27.     *
  28.     * Loads the specified icon or cursor file.  It reads the images into
  29.     * a list, then prompts for which one to open initially.
  30.     *
  31.     * Arguments:
  32.     *
  33.     * History:
  34.     *
  35.     ************************************************************************/
  36.     
  37.     BOOL LoadIconCursorFile(
  38.         PSTR pszFullFileName,
  39.         BOOL fIcon)
  40.     {
  41.         HFILE hf;
  42.         INT i;
  43.         PIMAGEINFO pImage;
  44.         LPBITMAPINFO lpBitmapInfo;
  45.         HANDLE hDIB;                    // Handle to DIB bits.
  46.         OFSTRUCT OfStruct;
  47.         struct stat FileStatus;
  48.         ICOCURSORHDR hdr;               // Header structure of icon/cursor file.
  49.         INT nImages;
  50.         PICOCURSORDESC aIcoCurDesc;     // Array of ico/cur descriptors.
  51.         DWORD dwFilePos;
  52.         DWORD dwFileSize;
  53.         INT iType;
  54.     
  55.         if ((hf = (HFILE)OpenFile(pszFullFileName, (LPOFSTRUCT)&OfStruct, OF_READ))
  56.                 == (HFILE)-1) {
  57.             Message(MSG_CANTOPEN, pszFullFileName);
  58.             return FALSE;
  59.         }
  60.     
  61.         fstat((INT)_open_osfhandle((long)(hf), (int)(O_RDONLY)), &FileStatus);
  62.         dwFileSize = (DWORD)FileStatus.st_size;
  63.     
  64.         ImageLinkFreeList();
  65.     
  66.         if (fIcon)
  67.             iType = FT_ICON;
  68.         else
  69.             iType = FT_CURSOR;
  70.     
  71.         /*
  72.          * Read the Icon/Cursor File header.
  73.          */
  74.         if (!MyFileRead(hf, (LPSTR)&hdr, sizeof(ICOCURSORHDR),
  75.                 pszFullFileName, iType))
  76.             goto Error1;
  77.     
  78.         if (hdr.iReserved != 0) {
  79.             Message(MSG_BADICOCURFILE, pszFullFileName);
  80.             goto Error1;
  81.         }
  82.     
  83.         /*
  84.          * Get number of images in the file.
  85.          */
  86.         nImages = hdr.iResourceCount;
  87.     
  88.         if (!nImages || nImages > MAXIMAGES) {
  89.             Message(MSG_BADICOCURFILE, pszFullFileName);
  90.             goto Error1;
  91.         }
  92.     
  93.         if (hdr.iResourceType != 1 && hdr.iResourceType != 2) {
  94.             Message(MSG_BADICOCURFILE, pszFullFileName);
  95.             goto Error1;
  96.         }
  97.     
  98.         /*
  99.          * Allocate room for the descriptor records.
  100.          */
  101.         if (!(aIcoCurDesc = (PICOCURSORDESC)MyAlloc(
  102.                 sizeof(ICOCURSORDESC) * nImages)))
  103.             goto Error1;
  104.     
  105.         /*
  106.          * Read in the descriptor records.
  107.          */
  108.         if (!MyFileRead(hf, (LPSTR)aIcoCurDesc, sizeof(ICOCURSORDESC) * nImages,
  109.                 pszFullFileName, iType))
  110.             goto Error2;
  111.     
  112.         /*
  113.          * Get the current file position (after the descriptors).  This
  114.          * should be the start of the DIB's.
  115.          */
  116.         dwFilePos = (DWORD)SetFilePointer((HANDLE)hf, 0, NULL, (DWORD)1);
  117.     
  118.         /*
  119.          * Validate the descriptor records.
  120.          */
  121.         for (i = 0; i < nImages; i++) {
  122.             /*
  123.              * Make sure the DIB's are sequential (not overlapping)
  124.              * and they all fit within the file.
  125.              */
  126.             if (aIcoCurDesc[i].DIBOffset != dwFilePos ||
  127.                     dwFilePos + aIcoCurDesc[i].DIBSize > dwFileSize) {
  128.                 Message(MSG_BADICOCURFILE, pszFullFileName);
  129.                 goto Error2;
  130.             }
  131.     
  132.             /*
  133.              * Jump to the next DIB.
  134.              */
  135.             dwFilePos += aIcoCurDesc[i].DIBSize;
  136.         }
  137.     
  138.         for (i = 0; i < nImages; i++) {
  139.             pImage = ImageLinkAlloc(NULL, 0, 0,
  140.                     aIcoCurDesc[i].iHotspotX, aIcoCurDesc[i].iHotspotY,
  141.                     (aIcoCurDesc[i].iColorCount == (BYTE)8) ?
  142.                     aIcoCurDesc[i].iColorCount : 0);
  143.     
  144.             if (!pImage)
  145.                 goto Error3;
  146.     
  147.             /*
  148.              * Allocate space for the DIB for this image.
  149.              */
  150.             if (!(hDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
  151.                     (DWORD)aIcoCurDesc[i].DIBSize))) {
  152.                 Message(MSG_OUTOFMEMORY);
  153.                 goto Error3;
  154.             }
  155.     
  156.             pImage->DIBSize = aIcoCurDesc[i].DIBSize;
  157.             pImage->DIBhandle = hDIB;
  158.             pImage->DIBPtr = (LPSTR)GlobalLock(hDIB);
  159.         }
  160.     
  161.         for (pImage = gpImageHead; pImage != NULL; pImage = pImage->pImageNext) {
  162.             if (!MyFileRead(hf, pImage->DIBPtr, (DWORD)pImage->DIBSize,
  163.                     pszFullFileName, iType))
  164.                 goto Error3;
  165.     
  166.             lpBitmapInfo = (LPBITMAPINFO)pImage->DIBPtr;
  167.     
  168.             if (!IsValidDIB(lpBitmapInfo, pImage->DIBSize, TRUE)) {
  169.                 Message(MSG_BADICOCURFILE, pszFullFileName);
  170.                 goto Error3;
  171.             }
  172.     
  173.             /*
  174.              * Fill the x and y size fields in image node from
  175.              * information in the DIB header.
  176.              */
  177.             pImage->cx = (INT)lpBitmapInfo->bmiHeader.biWidth;
  178.             pImage->cy = (INT)lpBitmapInfo->bmiHeader.biHeight / 2;
  179.             if (pImage->nColors == 0)
  180.                 pImage->nColors = (1 << lpBitmapInfo->bmiHeader.biBitCount);
  181.     
  182.             pImage->pDevice = DeviceLinkFind(
  183.                     fIcon ? gpIconDeviceHead : gpCursorDeviceHead,
  184.                     pImage->nColors, pImage->cx, pImage->cy);
  185.         }
  186.     
  187.         _lclose((HFILE)hf);
  188.     
  189.         fFileDirty = FALSE;
  190.         SetFileName(pszFullFileName);
  191.         giType = iType;
  192.     
  193.         gnImages = nImages;
  194.     
  195.         /*
  196.          * Update the PropBar and the Toolbox so that they show
  197.          * information about the opened file.  We do this now just
  198.          * in case the user cancels out of the Image Select Dialog.
  199.          */
  200.         PropBarUpdate();
  201.         ToolboxUpdate();
  202.     
  203.         /*
  204.          * Open up an image.  If there are multiple images in the file,
  205.          * show the Image Select dialog.  We also show the Image Select
  206.          * dialog if the file only has one image but it is not for a known
  207.          * device.
  208.          */
  209.         if (gnImages > 1 || !gpImageHead->pDevice)
  210.             ImageSelectDialog();
  211.         else
  212.             ImageOpen2(gpImageHead);
  213.     
  214.         return TRUE;
  215.     
  216.     Error3:
  217.         ImageLinkFreeList();
  218.     
  219.     Error2:
  220.         MyFree(aIcoCurDesc);
  221.     
  222.     Error1:
  223.         _lclose((HFILE)hf);
  224.     
  225.         return FALSE;
  226.     }
  227.     
  228.     
  229.     
  230.     /************************************************************************
  231.     * IsValidDIB
  232.     *
  233.     * This function determines if the given DIB is valid or not.  It does
  234.     * this without touching memory outside the bounds of the cbDIBSize
  235.     * passed in or the size of a BITMAPINFOHEADER, whichever is smaller.
  236.     * Note that even if the DIB is valid, however, the current image
  237.     * editor might not be able to edit it (the size might be too big, for
  238.     * instance).
  239.     *
  240.     * Arguments:
  241.     *   LPBITMAPINFO pDIB - Points to the DIB.
  242.     *   DWORD cbDIBSize   - The size of the DIB.
  243.     *   BOOL fIcoCur      - TRUE if this is an icon or cursor.  This effects
  244.     *                       whether an AND mask is expected to be in the DIB.
  245.     *
  246.     * History:
  247.     *
  248.     ************************************************************************/
  249.     
  250.     BOOL IsValidDIB(
  251.         LPBITMAPINFO pDIB,
  252.         DWORD cbDIBSize,
  253.         BOOL fIcoCur)
  254.     {
  255.         DWORD cbANDMask;
  256.         DWORD cbXORMask;
  257.         DWORD cbColorTable;
  258.         DWORD nHeight;
  259.     
  260.         if (cbDIBSize < sizeof(BITMAPINFOHEADER))
  261.             return FALSE;
  262.     
  263.         if (pDIB->bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
  264.             return FALSE;
  265.     
  266.         if (pDIB->bmiHeader.biPlanes != 1)
  267.             return FALSE;
  268.     
  269.         if (pDIB->bmiHeader.biBitCount != 1 &&
  270.                 pDIB->bmiHeader.biBitCount != 4 &&
  271.                 pDIB->bmiHeader.biBitCount != 8 &&
  272.                 pDIB->bmiHeader.biBitCount != 24)
  273.             return FALSE;
  274.     
  275.         if (fIcoCur) {
  276.             nHeight = pDIB->bmiHeader.biHeight / 2;
  277.             cbANDMask = (((pDIB->bmiHeader.biWidth + 31) & 0xffffffe0) >> 3) *
  278.                     nHeight;
  279.         }
  280.         else {
  281.             nHeight = pDIB->bmiHeader.biHeight;
  282.             cbANDMask = 0;
  283.         }
  284.     
  285.         cbColorTable = (1 << pDIB->bmiHeader.biBitCount) * sizeof(RGBQUAD);
  286.         cbXORMask = ((((pDIB->bmiHeader.biWidth * pDIB->bmiHeader.biBitCount) +
  287.                 31) & 0xffffffe0) >> 3) * nHeight;
  288.     
  289.         /*
  290.          * Check the size field in the header.  This must be either zero
  291.          * or a valid size.
  292.          */
  293.         if (pDIB->bmiHeader.biSizeImage &&
  294.                 pDIB->bmiHeader.biSizeImage != cbXORMask + cbANDMask)
  295.             return FALSE;
  296.     
  297.         if (cbDIBSize != sizeof(BITMAPINFOHEADER) + cbColorTable +
  298.                 cbXORMask + cbANDMask)
  299.             return FALSE;
  300.     
  301.         return TRUE;
  302.     }
  303.     
  304.     
  305.     
  306.     /************************************************************************
  307.     * SaveIconCursorFile
  308.     *
  309.     *
  310.     *
  311.     * Arguments:
  312.     *
  313.     * Returns:
  314.     *   TRUE if successful, FALSE otherwise.
  315.     *
  316.     * History:
  317.     *
  318.     ************************************************************************/
  319.     
  320.     BOOL SaveIconCursorFile(
  321.         PSTR pszFullFileName,
  322.         INT iType)
  323.     {
  324.         ICOCURSORHDR IcoCurHdr;     // Header structure of icon/cursor file.
  325.         ICOCURSORDESC IcoCurDesc;   // Icon/cursor descriptor struct.
  326.         HCURSOR hcurOld;            // Handle to old cursor.
  327.         PIMAGEINFO pImage;          // Pointer to node in image list.
  328.         DWORD iBitsOffset;          // Offset of the actual DIB bits for image.
  329.         HFILE hf;
  330.         OFSTRUCT OfStruct;
  331.     
  332.         hcurOld = SetCursor(hcurWait);
  333.     
  334.         /*
  335.          * Save the bits of the current image.
  336.          */
  337.         ImageSave();
  338.     
  339.         /*
  340.          * Open the file for writing.
  341.          */
  342.         if ((hf = (HFILE)OpenFile(pszFullFileName, &OfStruct, OF_CREATE | OF_READWRITE))
  343.                 == (HFILE)-1) {
  344.             Message(MSG_CANTCREATE, pszFullFileName);
  345.             goto Error1;
  346.         }
  347.     
  348.         /*
  349.          * This is crucial since this helps distinguish a 3.0 icon/cursor
  350.          * from an old, old (2.1 format) icon/cursor, which has meaningful
  351.          * information in this WORD.
  352.          */
  353.         IcoCurHdr.iReserved = (WORD)0;
  354.     
  355.         if (iType == FT_ICON)
  356.             IcoCurHdr.iResourceType = 1;        // Icon type.
  357.         else
  358.             IcoCurHdr.iResourceType = 2;        // Cursor type.
  359.     
  360.         IcoCurHdr.iResourceCount = (WORD)gnImages;
  361.     
  362.         /*
  363.          * Write the header to disk.
  364.          */
  365.         if (!MyFileWrite(hf, (LPSTR)&IcoCurHdr, sizeof(ICOCURSORHDR),
  366.                 pszFullFileName))
  367.             goto Error2;
  368.     
  369.         /*
  370.          * Write all the descriptors.
  371.          */
  372.         iBitsOffset = sizeof(ICOCURSORHDR) + (gnImages * sizeof(ICOCURSORDESC));
  373.         for (pImage = gpImageHead; pImage; pImage = pImage->pImageNext) {
  374.             IcoCurDesc.iWidth = (BYTE)pImage->cx;
  375.             IcoCurDesc.iHeight = (BYTE)pImage->cy;
  376.             IcoCurDesc.iColorCount = (giType == FT_ICON) ?
  377.                     (BYTE)pImage->nColors : (BYTE)0;
  378.             IcoCurDesc.iUnused = 0;
  379.             IcoCurDesc.iHotspotX = (WORD)pImage->iHotspotX;
  380.             IcoCurDesc.iHotspotY = (WORD)pImage->iHotspotY;
  381.             IcoCurDesc.DIBSize = pImage->DIBSize;
  382.             IcoCurDesc.DIBOffset = iBitsOffset;
  383.     
  384.             if (!MyFileWrite(hf, (LPSTR)&IcoCurDesc, sizeof(ICOCURSORDESC),
  385.                     pszFullFileName))
  386.                 goto Error2;
  387.     
  388.             iBitsOffset += IcoCurDesc.DIBSize;
  389.         }
  390.     
  391.         /*
  392.          * Now write the DIB's.
  393.          */
  394.         for (pImage = gpImageHead; pImage; pImage = pImage->pImageNext) {
  395.             if (!MyFileWrite(hf, (LPSTR)pImage->DIBPtr,
  396.                     (DWORD)pImage->DIBSize, pszFullFileName))
  397.                 goto Error2;
  398.         }
  399.     
  400.         _lclose((HFILE)hf);
  401.     
  402.         fFileDirty = FALSE;
  403.         SetFileName(pszFullFileName);
  404.     
  405.         SetCursor(hcurOld);
  406.     
  407.         return TRUE;
  408.     
  409.     Error2:
  410.         _lclose((HFILE)hf);
  411.     
  412.     Error1:
  413.         SetCursor(hcurOld);
  414.     
  415.         return FALSE;
  416.     }
  417.