home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / linefrac / lffile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-09  |  17.0 KB  |  579 lines

  1. /************************************************************************
  2. *
  3. *   lffile.c -- File handling subroutines for LineFrac.
  4. *
  5. *   Created by Microsoft Corporation, 1989
  6. *
  7. ************************************************************************/
  8.  
  9. #define INCL_WIN
  10. #define INCL_GPI
  11. #define INCL_DOSMEMMGR
  12. #define INCL_DOSFILEMGR
  13. #define INCL_BITMAPFILEFORMAT
  14. #include <os2.h>
  15.  
  16. #include <stdio.h>
  17.  
  18. #undef  RC_INVOKED
  19. #include "opendlg.h"
  20.  
  21. #define INCL_GLOBALS
  22. #define INCL_THREADS
  23. #include "linefrac.h"
  24.  
  25. #define INCL_LFFILE
  26. #define INCL_LFPS
  27. #define INCL_LFUTIL
  28. #include "lffuncs.h"
  29.  
  30.  
  31.  
  32.  
  33. /*
  34.  * this is the bitmap resource file format structure
  35.  */
  36. typedef struct {
  37.     USHORT    wType;
  38.     ULONG     dwSize;
  39.     int       xHotspot;
  40.     int       yHotspot;
  41.     ULONG     dwBitsOffset;
  42.     USHORT    bmWidth;       /* from here this is a BitmapInfo table */
  43.     USHORT    bmHeight;
  44.     USHORT    bmPlanes;
  45.     USHORT    bmBitcount;
  46. } RCBITMAP;
  47. typedef RCBITMAP FAR *PRCBITMAP;
  48.  
  49.  
  50.  
  51.  
  52. /************************************************************************
  53. *
  54. *   Global Variables
  55. *
  56. ************************************************************************/
  57.  
  58. extern GLOBALDATA global;
  59.  
  60.  
  61.  
  62.  
  63. /************************************************************************
  64. *
  65. *   LfReadFile
  66. *
  67. *   Calls the OpenDlg function to ask the user what file name to
  68. *   read from.
  69. *
  70. ************************************************************************/
  71.  
  72. VOID
  73. LfReadFile(hwnd, pthr)
  74. HWND hwnd;
  75. PTHR pthr;
  76. {
  77.     HFILE hFile;
  78.     DLF dlf;
  79.  
  80.     dlf.rgbAction    = DLG_OPENDLG;
  81.     dlf.rgbFlags    = ATTRDIRLIST;
  82.     dlf.phFile        = &hFile;
  83.     dlf.pszExt        = (PSZ)"\\*.bmp";
  84.     dlf.pszAppName    = "LineFrac";
  85.     dlf.pszTitle    = "Load Bitmap";
  86.     dlf.pszInstructions = NULL;
  87.     dlf.szFileName[0]    = '\0';
  88.     dlf.szOpenFile[0]    = '\0';
  89.  
  90.     switch (DlgFile(hwnd,&dlf))
  91.     {
  92.     case TDF_ERRMEM:
  93.     case TDF_INVALID:
  94.     MyMessageBox(hwnd, "Error reading file.");
  95.     break;
  96.  
  97.     case TDF_NOOPEN:
  98.     break;
  99.  
  100.     default:
  101.     if (!LfReadBMP(pthr, &dlf))
  102.         MyMessageBox(hwnd, "Error reading file.\nIs AutoResize enabled?");
  103.     }
  104. }
  105.  
  106.  
  107.  
  108.  
  109. /************************************************************************
  110. *
  111. *   LfReadBMP
  112. *
  113. *   Read a bitmap in from a BMP format file.  Prepare the DC for the
  114. *   given thread to accept it.    The user can have the DC resized to
  115. *   fit exactly the bitmap, or fit the bits in as best as we can.
  116. *   If we're not resizing and the bitmap is larger than the thread's
  117. *   DC, then load the bits flush with the lower left.
  118. *
  119. *   Both old-style (PRCBITMAP) and new-style (PBITMAPFILEHEADER)
  120. *   bitmaps can be read.
  121. *
  122. *   Free up memory and close the file before leaving.  The file
  123. *   will have been opened by the time this function is called,
  124. *   and the file handle will be in the *pdlf structure.
  125. *
  126. ************************************************************************/
  127.  
  128. BOOL
  129. LfReadBMP(pthr, pdlf)
  130. PTHR pthr;
  131. PDLF pdlf;        /* File information filled by DlgFile. */
  132. {
  133.     HFILE hfile;
  134.     ULONG cScans;
  135.     ULONG ulSize;     /* Number of bytes occupied by bitmap bits.         */
  136.     USHORT cSegs;     /* Number of 64K segments in ulSize.             */
  137.     USHORT cbExtra;     /* Bytes in last segment of ulSize.             */
  138.     SEL sel;         /* Base selector to file data.              */
  139.     USHORT hugeshift;     /* Segment index shift value.                 */
  140.     USHORT cbRead1;     /* Number of bytes to read first call to DosRead    */
  141.     USHORT cbRead2;     /* Number of bytes to read second call to DosRead   */
  142.     USHORT cbRead;     /* Number of bytes read by DosRead.             */
  143.     BOOL fRet = FALSE;     /* Function return code.                 */
  144.     USHORT i;         /* Generic loop index.                  */
  145.     FILESTATUS fsts;
  146.     PBITMAPFILEHEADER pbfh;
  147.     PRCBITMAP  rb;
  148.     PBYTE pImage;
  149.  
  150.  
  151.     /*******************************************************************
  152.     * Find out how big the file is so we can read the whole thing in.
  153.     *******************************************************************/
  154.  
  155.     hfile = *(pdlf->phFile);
  156.     if( DosQFileInfo( hfile, 1, &fsts, sizeof(FILESTATUS)) != 0)
  157.     goto lfread_error_close_file;
  158.  
  159.     ulSize  = fsts.cbFile;
  160.     cSegs   = (USHORT)(ulSize/0x10000L);
  161.     cbExtra = (USHORT)(ulSize%0x10000L);
  162.     if (DosAllocHuge(cSegs, cbExtra, (PSEL)&sel, 0, 0))
  163.     goto lfread_error_close_file;
  164.     if (DosGetHugeShift(&hugeshift))
  165.     goto lfread_error_free_bits;
  166.  
  167.     pImage = (PBYTE)MAKEP(sel, 0);
  168.     rb       = (PRCBITMAP)pImage;
  169.     pbfh   = (PBITMAPFILEHEADER)pImage;
  170.  
  171.  
  172.     /*******************************************************************
  173.     * Read the bits in from the file. The DosRead function allows a
  174.     * maximum of 64K-1 bytes read at a time.  We get around this
  175.     * by reading two 32K chunks for each 64K segment, and reading the
  176.     * last segment in one piece.
  177.     *******************************************************************/
  178.  
  179.     for (i = 0; i <= cSegs; ++i)
  180.     {
  181.     if (i < cSegs)
  182.     {
  183.         /* This segment is 64K bytes long, so split it up. */
  184.         cbRead1 = 0x8000;
  185.         cbRead2 = 0x8000;
  186.     }
  187.     else
  188.     {
  189.         /* This segment is less than 64K bytes long, so read it all. */
  190.         cbRead1 = cbExtra;
  191.         cbRead2 = 0;
  192.     }
  193.  
  194.     /* There's a possibility that cbExtra will be 0, so check
  195.      * to avoid an unnecessary system call.
  196.      */
  197.     if (cbRead1 > 0)
  198.     {
  199.         if (DosRead( hfile
  200.                , (PVOID)MAKEP(sel+(i<<hugeshift), 0)
  201.                , cbRead1
  202.                , &cbRead))
  203.         goto lfread_error_free_bits;
  204.         if (cbRead1 != cbRead)
  205.         goto lfread_error_free_bits;
  206.     }
  207.  
  208.     /* This will always be skipped on the last partial segment. */
  209.     if (cbRead2 > 0)
  210.     {
  211.         if (DosRead( hfile
  212.                , (PVOID)MAKEP(sel+(i<<hugeshift), cbRead1)
  213.                , cbRead2
  214.                , &cbRead))
  215.         goto lfread_error_free_bits;
  216.         if (cbRead2 != cbRead)
  217.         goto lfread_error_free_bits;
  218.     }
  219.     }
  220.  
  221.  
  222.     /*******************************************************************
  223.     * At this point we have the bitmap completely in memory.  Now we
  224.     * look at how the user wants them set into the thread's PS.  If
  225.     * the thread has fAutoResizePS set, then make the PS fit the size
  226.     * of the bitmap (the easy case).  If the flag is not set, then
  227.     * figure out how to place it.
  228.     *******************************************************************/
  229.  
  230.     if (pthr->fAutoSizePS)
  231.     {
  232.     if (pbfh->bmp.cbFix != sizeof(BITMAPINFOHEADER))
  233.     {
  234.         global.bm.cx    = rb->bmWidth;
  235.         global.bm.cy    = rb->bmHeight;
  236.         global.bm.cPlanes    = rb->bmPlanes;
  237.         global.bm.cBitCount = rb->bmBitcount;
  238.     }
  239.     else
  240.     {
  241.         global.bm.cx    = pbfh->bmp.cx;
  242.         global.bm.cy    = pbfh->bmp.cy;
  243.         global.bm.cPlanes    = pbfh->bmp.cPlanes;
  244.         global.bm.cBitCount = pbfh->bmp.cBitCount;
  245.     }
  246.  
  247.     LfResizePS(pthr);
  248.     }
  249.     else
  250.     goto lfread_error_free_bits;
  251.  
  252.  
  253.     /*******************************************************************
  254.     * Tell GPI to put the bits into the thread's PS. The function returns
  255.     * the number of scan lines of the bitmap that were copied.    We want
  256.     * all of them at once.
  257.     *******************************************************************/
  258.  
  259.     if (pbfh->bmp.cbFix != sizeof(BITMAPINFOHEADER))
  260.     {
  261.         pImage += rb->dwBitsOffset;
  262.         rb->dwBitsOffset = sizeof(BITMAPINFOHEADER);
  263.     cScans = GpiSetBitmapBits( pthr->hps
  264.                  , 0L
  265.                  , (LONG)rb->bmHeight
  266.                  , pImage
  267.                  , (PBITMAPINFO)&(rb->dwBitsOffset));
  268.     if (cScans != (ULONG)rb->bmHeight)  /* compare with original number of scans */
  269.         goto lfread_error_free_bits;
  270.     }
  271.     else
  272.     {
  273.     cScans = GpiSetBitmapBits( pthr->hps
  274.                  , 0L
  275.                  , (LONG)pbfh->bmp.cy
  276.                  , pImage + pbfh->offBits
  277.                  , (PBITMAPINFO)&(pbfh->bmp));
  278.     if (cScans != (ULONG)pbfh->bmp.cy)  /* compare with original number of scans */
  279.         goto lfread_error_free_bits;
  280.     }
  281.     fRet = TRUE;     /* We made it!  The bits are in the thread's PS. */
  282.  
  283.  
  284.     /*******************************************************************
  285.     * Close the file, free the buffer space and leave.    This is a
  286.     * common exit point from the function.  Since the same cleanup
  287.     * operations need to be performed for such a large number of
  288.     * possible error conditions, this is a concise way to do the right
  289.     * thing.
  290.     *******************************************************************/
  291.  
  292. lfread_error_free_bits:
  293.     DosFreeSeg(sel);
  294. lfread_error_close_file:
  295.     DosClose(hfile);
  296.     return fRet;
  297. }
  298.  
  299.  
  300.  
  301.  
  302. /************************************************************************
  303. *
  304. *   LfWriteFile
  305. *
  306. *   Calls the OpenDlg function to ask the user what file name to
  307. *   save under.
  308. *
  309. ************************************************************************/
  310.  
  311. VOID
  312. LfWriteFile(hwnd, pthr)
  313. HWND hwnd;
  314. PTHR pthr;
  315. {
  316.     HFILE hFile;
  317.     DLF dlf;
  318.     BITMAPINFOHEADER bmih;
  319.  
  320.  
  321.     SetupDLF( &dlf
  322.         , DLG_SAVEDLG
  323.         , &hFile
  324.         , (PSZ)"\\*.BMP"
  325.         , (PSZ)"LineFrac"
  326.         , (PSZ)"Save Bitmap"
  327.         , NULL );
  328.     dlf.szFileName[0] = '\0';
  329.     dlf.szOpenFile[0] = '\0';
  330.  
  331.     switch (DlgFile(hwnd,&dlf))
  332.     {
  333.     case TDF_ERRMEM:
  334.     case TDF_INVALID:
  335.     MyMessageBox(hwnd, "Error opening file.");
  336.     break;
  337.  
  338.     case TDF_NOSAVE:
  339.     break;
  340.  
  341.     default:
  342.     bmih.cbFix     = sizeof(BITMAPINFOHEADER);
  343.     bmih.cx        = (USHORT) pthr->rcl.xRight;
  344.     bmih.cy        = (USHORT) pthr->rcl.yTop;
  345.     bmih.cPlanes   = pthr->cPlanes;
  346.     bmih.cBitCount = pthr->cBitCount;
  347.  
  348.     if (!LfWriteBMP(pthr->hps, &bmih, &dlf))
  349.         MyMessageBox(hwnd, "Error writing file.");
  350.     }
  351. }
  352.  
  353.  
  354.  
  355.  
  356. /************************************************************************
  357. *
  358. *   LfWriteBMP
  359. *
  360. *   Write the bitmap out to a BMP format file.    Write the file
  361. *   header first, then the bitmap bits.  Space for the header
  362. *   and the bits is allocated.    Huge bitmaps are supported.
  363. *   Free up memory and close the file before leaving.  The file
  364. *   will have been opened by the time this function is called,
  365. *   and the file handle will be in the *pdlf structure.
  366. *
  367. ************************************************************************/
  368.  
  369. BOOL
  370. LfWriteBMP(hPS, pbmih, pdlf)
  371. HPS hPS;        /* hPS from which to get bitmap bits.      */
  372. PBITMAPINFOHEADER pbmih;/* Bitmap information.              */
  373. PDLF pdlf;        /* File information filled by DlgFile. */
  374. {
  375.     HFILE hfile;
  376.     ULONG cScans;
  377.     ULONG ulSize;     /* Number of bytes occupied by bitmap bits.         */
  378.     USHORT cSegs;     /* Number of 64K segments in ulSize.             */
  379.     USHORT cbExtra;     /* Bytes in last segment of ulSize.             */
  380.     SEL selBits;     /* Base selector to bitmap bits.             */
  381.     USHORT hugeshift;     /* Segment index shift value.                 */
  382.     USHORT cbBMHdr;     /* Size of bitmap header.                 */
  383.     PBITMAPFILEHEADER pbfh; /* Pointer to private copy of bitmap info data.    */
  384.     USHORT cbWrite1;     /* Number of bytes to write first call to DosWrite  */
  385.     USHORT cbWrite2;     /* Number of bytes to write second call to DosWrite */
  386.     USHORT cbWritten;     /* Number of bytes written by DosWrite.         */
  387.     BOOL fRet = FALSE;     /* Function return code.                 */
  388.     USHORT i;         /* Generic loop index.                  */
  389.     struct
  390.     {
  391.     LONG cPlanes;
  392.     LONG cBitCount;
  393.     } bmFmt;
  394.  
  395.  
  396.     hfile = *(pdlf->phFile);
  397.  
  398.     /*******************************************************************
  399.     * If the bitmap was created with either 0 planes or 0 bits per
  400.     * pixel, then query the format to write with.  By asking for just
  401.     * one format (two LONGs, or one instance of structure of bmFmt),
  402.     * we'll get the device's favored format.
  403.     *******************************************************************/
  404.  
  405.     if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
  406.     {
  407.     if (!GpiQueryDeviceBitmapFormats(hPS, 2L, (PLONG)&bmFmt))
  408.         goto lfwrite_error_close_file;
  409.     }
  410.     else
  411.     {
  412.     bmFmt.cPlanes    = pbmih->cPlanes;
  413.     bmFmt.cBitCount = pbmih->cBitCount;
  414.     }
  415.  
  416.  
  417.     /*******************************************************************
  418.     * Determine size of bitmap header.    The header consists of a
  419.     * a fixed-size part and a variable-length color table.  The
  420.     * latter has  2^cBitCount  entries, each of which is sizeof(RGB)
  421.     * bytes long.  The exception is when cBitCount is 24, in which
  422.     * case the color table is omitted because the pixels are direct
  423.     * rgb values.
  424.     *******************************************************************/
  425.  
  426.     i = (int) bmFmt.cBitCount;
  427.     if (i == 24)
  428.     cbBMHdr = 0;
  429.     else
  430.     for (cbBMHdr = sizeof(RGB); i > 0; --i)
  431.         cbBMHdr *= 2;
  432.     cbBMHdr += sizeof(BITMAPFILEHEADER);
  433.  
  434.  
  435.     /*******************************************************************
  436.     * Copy structure from input to work buffer.  The call to
  437.     * GpiQueryBitmapBits will have write-access to this, so we won't
  438.     * let it have the user's data.
  439.     *******************************************************************/
  440.  
  441.     pbfh = 0;
  442.     if (DosAllocSeg(cbBMHdr, ((PUSHORT)&pbfh)+1, 0))
  443.     goto lfwrite_error_close_file;
  444.     pbfh->bmp = *pbmih;
  445.     if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
  446.     {
  447.     pbfh->bmp.cPlanes   = (USHORT) bmFmt.cPlanes;
  448.     pbfh->bmp.cBitCount = (USHORT) bmFmt.cBitCount;
  449.     }
  450.  
  451.  
  452.     /*******************************************************************
  453.     * Allocate space for the bitmap bits -- all of them at once.
  454.     * The extra ULONG casts are there to force all the arithmetic
  455.     * to be done in 32 bits.
  456.     *******************************************************************/
  457.  
  458.     ulSize = (
  459.            (
  460.          (
  461.            (ULONG)pbfh->bmp.cBitCount
  462.            * (ULONG)pbfh->bmp.cx
  463.            + 31L
  464.          ) / 32L
  465.            ) * (ULONG)pbfh->bmp.cPlanes * 4L
  466.          ) * (ULONG)pbfh->bmp.cy;
  467.  
  468.     cSegs   = (USHORT)(ulSize/0x10000L);
  469.     cbExtra = (USHORT)(ulSize%0x10000L);
  470.     if (DosAllocHuge(cSegs, cbExtra, (PSEL)&selBits, 0, 0))
  471.     goto lfwrite_error_free_header;
  472.     if (DosGetHugeShift(&hugeshift))
  473.     goto lfwrite_error_free_bits;
  474.  
  475.  
  476.     /*******************************************************************
  477.     * Tell GPI to give us the bits. The function returns the number
  478.     * of scan lines of the bitmap that were copied.  We want all of
  479.     * them at once.
  480.     *******************************************************************/
  481.  
  482.     cScans = GpiQueryBitmapBits( hPS
  483.                    , 0L
  484.                    , (ULONG)pbfh->bmp.cy
  485.                    , (PBYTE)MAKEP(selBits, 0)
  486.                    , (PBITMAPINFO)&pbfh->bmp);
  487.     if (cScans != pbfh->bmp.cy)  /* compare with original number of scans */
  488.     goto lfwrite_error_free_bits;
  489.  
  490.  
  491.     /*******************************************************************
  492.     * Fill in the extra header fields and write the header out to
  493.     * the file.
  494.     *******************************************************************/
  495.  
  496.     pbfh->usType    = 0x4D42;          /* 'MB' */
  497.     pbfh->cbSize    = ulSize + cbBMHdr;
  498.     pbfh->xHotspot  = pbfh->bmp.cx / 2;    /* why bother ? */
  499.     pbfh->yHotspot  = pbfh->bmp.cy / 2;
  500.     pbfh->offBits   = cbBMHdr;
  501.  
  502.     if (DosWrite( hfile
  503.         , (PVOID)pbfh
  504.         , cbBMHdr
  505.         , &cbWritten))
  506.     goto lfwrite_error_free_bits;
  507.     if (cbWritten != cbBMHdr)
  508.     goto lfwrite_error_free_bits;
  509.  
  510.  
  511.     /*******************************************************************
  512.     * Write the bits out to the file. The DosWrite function allows a
  513.     * maximum of 64K-1 bytes written at a time.  We get around this
  514.     * by writing two 32K chunks for each 64K segment, and writing the
  515.     * last segment in one piece.
  516.     *******************************************************************/
  517.  
  518.     for (i = 0; i <= cSegs; ++i)
  519.     {
  520.     if (i < cSegs)
  521.     {
  522.         /* This segment is 64K bytes long, so split it up. */
  523.         cbWrite1 = 0x8000;
  524.         cbWrite2 = 0x8000;
  525.     }
  526.     else
  527.     {
  528.         /* This segment is less than 64K bytes long, so write it all. */
  529.         cbWrite1 = cbExtra;
  530.         cbWrite2 = 0;
  531.     }
  532.  
  533.     /* There's a possibility that cbExtra will be 0, so check
  534.      * to avoid an unnecessary system call.
  535.      */
  536.     if (cbWrite1 > 0)
  537.     {
  538.         if (DosWrite( hfile
  539.             , (PVOID)MAKEP(selBits+(i<<hugeshift), 0)
  540.             , cbWrite1
  541.             , &cbWritten))
  542.         goto lfwrite_error_free_bits;
  543.         if (cbWrite1 != cbWritten)
  544.         goto lfwrite_error_free_bits;
  545.     }
  546.  
  547.     /* This will always be skipped on the last partial segment. */
  548.     if (cbWrite2 > 0)
  549.     {
  550.         if (DosWrite( hfile
  551.             , (PVOID)MAKEP(selBits+(i<<hugeshift), cbWrite1)
  552.             , cbWrite2
  553.             , &cbWritten))
  554.         goto lfwrite_error_free_bits;
  555.         if (cbWrite2 != cbWritten)
  556.         goto lfwrite_error_free_bits;
  557.     }
  558.     }
  559.  
  560.     fRet = TRUE;     /* We made it!  The bits are on the disk. */
  561.  
  562.  
  563.     /*******************************************************************
  564.     * Close the file, free the buffer space and leave.    This is a
  565.     * common exit point from the function.  Since the same cleanup
  566.     * operations need to be performed for such a large number of
  567.     * possible error conditions, this is concise way to do the right
  568.     * thing.
  569.     *******************************************************************/
  570.  
  571. lfwrite_error_free_bits:
  572.     DosFreeSeg(selBits);
  573. lfwrite_error_free_header:
  574.     DosFreeSeg(*((PUSHORT)&pbfh+1));
  575. lfwrite_error_close_file:
  576.     DosClose(hfile);
  577.     return fRet;
  578. }
  579.