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