File:  [OS/2 SDKs] / pmsdk / samples / linefrac / lffile.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:28:31 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: pmsdk-1989, HEAD
Microsoft OS/2 SDK PM 02-24-1989

/************************************************************************
*
*   lffile.c -- File handling subroutines for LineFrac.
*
*   Created by Microsoft Corporation, 1989
*
************************************************************************/

#define INCL_WIN
#define INCL_GPI
#define INCL_DOSMEMMGR
#define INCL_DOSFILEMGR
#define INCL_BITMAPFILEFORMAT
#include <os2.h>

#include <stdio.h>

#include "opendlg.h"

#define INCL_GLOBALS
#define INCL_THREADS
#include "linefrac.h"

#define INCL_LFFILE
#define INCL_LFPS
#define INCL_LFUTIL
#include "lffuncs.h"




/*
 * this is the bitmap resource file format structure
 */
typedef struct {
    USHORT    wType;
    ULONG     dwSize;
    int       xHotspot;
    int       yHotspot;
    ULONG     dwBitsOffset;
    USHORT    bmWidth;       /* from here this is a BitmapInfo table */
    USHORT    bmHeight;
    USHORT    bmPlanes;
    USHORT    bmBitcount;
} RCBITMAP;
typedef RCBITMAP FAR *PRCBITMAP;




/************************************************************************
*
*   Global Variables
*
************************************************************************/

extern GLOBALDATA global;




/************************************************************************
*
*   LfReadFile
*
*   Calls the OpenDlg function to ask the user what file name to
*   read from.
*
************************************************************************/

VOID
LfReadFile(hwnd, pthr)
HWND hwnd;
PTHR pthr;
{
    HFILE hFile;
    DLF dlf;

    dlf.rgbAction	= DLG_OPENDLG;
    dlf.rgbFlags	= ATTRDIRLIST;
    dlf.phFile		= &hFile;
    dlf.pszExt		= (PSZ)"\\*.bmp";
    dlf.pszAppName	= "LineFrac";
    dlf.pszTitle	= "Load Bitmap";
    dlf.pszInstructions = NULL;
    dlf.szFileName[0]	= '\0';
    dlf.szOpenFile[0]	= '\0';

    switch (DlgFile(hwnd,&dlf))
    {
    case TDF_ERRMEM:
    case TDF_INVALID:
	MyMessageBox(hwnd, "Error reading file.");
	break;

    case TDF_NOOPEN:
	break;

    default:
	if (!LfReadBMP(pthr, &dlf))
	    MyMessageBox(hwnd, "Error reading file.\nIs AutoResize enabled?");
    }
}




/************************************************************************
*
*   LfReadBMP
*
*   Read a bitmap in from a BMP format file.  Prepare the DC for the
*   given thread to accept it.	The user can have the DC resized to
*   fit exactly the bitmap, or fit the bits in as best as we can.
*   If we're not resizing and the bitmap is larger than the thread's
*   DC, then load the bits flush with the lower left.
*
*   Both old-style (PRCBITMAP) and new-style (PBITMAPFILEHEADER)
*   bitmaps can be read.
*
*   Free up memory and close the file before leaving.  The file
*   will have been opened by the time this function is called,
*   and the file handle will be in the *pdlf structure.
*
************************************************************************/

BOOL
LfReadBMP(pthr, pdlf)
PTHR pthr;
PDLF pdlf;		/* File information filled by DlgFile. */
{
    HFILE hfile;
    ULONG cScans;
    ULONG ulSize;	 /* Number of bytes occupied by bitmap bits.	     */
    USHORT cSegs;	 /* Number of 64K segments in ulSize.		     */
    USHORT cbExtra;	 /* Bytes in last segment of ulSize.		     */
    SEL sel;		 /* Base selector to file data. 		     */
    USHORT hugeshift;	 /* Segment index shift value.			     */
    USHORT cbRead1;	 /* Number of bytes to read first call to DosRead    */
    USHORT cbRead2;	 /* Number of bytes to read second call to DosRead   */
    USHORT cbRead;	 /* Number of bytes read by DosRead.		     */
    BOOL fRet = FALSE;	 /* Function return code.			     */
    int i;		 /* Generic loop index. 			     */
    FILESTATUS fsts;
    PBITMAPFILEHEADER pbfh;
    PRCBITMAP  rb;
    PBYTE pImage;


    /*******************************************************************
    * Find out how big the file is so we can read the whole thing in.
    *******************************************************************/

    hfile = *(pdlf->phFile);
    if( DosQFileInfo( hfile, 1, &fsts, sizeof(FILESTATUS)) != 0)
	goto lfread_error_close_file;

    ulSize  = fsts.cbFile;
    cSegs   = (USHORT)(ulSize/0x10000L);
    cbExtra = (USHORT)(ulSize%0x10000L);
    if (DosAllocHuge(cSegs, cbExtra, (PSEL)&sel, 0, 0))
	goto lfread_error_close_file;
    if (DosGetHugeShift(&hugeshift))
	goto lfread_error_free_bits;

    pImage = (PBYTE)MAKEP(sel, 0);
    rb	   = (PRCBITMAP)pImage;
    pbfh   = (PBITMAPFILEHEADER)pImage;


    /*******************************************************************
    * Read the bits in from the file. The DosRead function allows a
    * maximum of 64K-1 bytes read at a time.  We get around this
    * by reading two 32K chunks for each 64K segment, and reading the
    * last segment in one piece.
    *******************************************************************/

    for (i = 0; i <= cSegs; ++i)
    {
	if (i < cSegs)
	{
	    /* This segment is 64K bytes long, so split it up. */
	    cbRead1 = 0x8000;
	    cbRead2 = 0x8000;
	}
	else
	{
	    /* This segment is less than 64K bytes long, so read it all. */
	    cbRead1 = cbExtra;
	    cbRead2 = 0;
	}

	/* There's a possibility that cbExtra will be 0, so check
	 * to avoid an unnecessary system call.
	 */
	if (cbRead1 > 0)
	{
	    if (DosRead( hfile
		       , (PVOID)MAKEP(sel+(i<<hugeshift), 0)
		       , cbRead1
		       , &cbRead))
		goto lfread_error_free_bits;
	    if (cbRead1 != cbRead)
		goto lfread_error_free_bits;
	}

	/* This will always be skipped on the last partial segment. */
	if (cbRead2 > 0)
	{
	    if (DosRead( hfile
		       , (PVOID)MAKEP(sel+(i<<hugeshift), cbRead1)
		       , cbRead2
		       , &cbRead))
		goto lfread_error_free_bits;
	    if (cbRead2 != cbRead)
		goto lfread_error_free_bits;
	}
    }


    /*******************************************************************
    * At this point we have the bitmap completely in memory.  Now we
    * look at how the user wants them set into the thread's PS.  If
    * the thread has fAutoResizePS set, then make the PS fit the size
    * of the bitmap (the easy case).  If the flag is not set, then
    * figure out how to place it.
    *******************************************************************/

    if (pthr->fAutoSizePS)
    {
	if (pbfh->bmp.cbFix != sizeof(BITMAPINFOHEADER))
	{
	    global.bm.cx	= rb->bmWidth;
	    global.bm.cy	= rb->bmHeight;
	    global.bm.cPlanes	= rb->bmPlanes;
	    global.bm.cBitCount = rb->bmBitcount;
	}
	else
	{
	    global.bm.cx	= pbfh->bmp.cx;
	    global.bm.cy	= pbfh->bmp.cy;
	    global.bm.cPlanes	= pbfh->bmp.cPlanes;
	    global.bm.cBitCount = pbfh->bmp.cBitCount;
	}

	LfResizePS(pthr);
    }
    else
	goto lfread_error_free_bits;


    /*******************************************************************
    * Tell GPI to put the bits into the thread's PS. The function returns
    * the number of scan lines of the bitmap that were copied.	We want
    * all of them at once.
    *******************************************************************/

    if (pbfh->bmp.cbFix != sizeof(BITMAPINFOHEADER))
    {
        pImage += rb->dwBitsOffset;
        rb->dwBitsOffset = sizeof(BITMAPINFOHEADER);
	cScans = GpiSetBitmapBits( pthr->hps
				 , 0L
				 , (LONG)rb->bmHeight
				 , pImage
				 , (PBITMAPINFO)&(rb->dwBitsOffset));
	if (cScans != (LONG)rb->bmHeight)  /* compare with original number of scans */
	    goto lfread_error_free_bits;
    }
    else
    {
	cScans = GpiSetBitmapBits( pthr->hps
				 , 0L
				 , (LONG)pbfh->bmp.cy
				 , pImage + pbfh->offBits
				 , (PBITMAPINFO)&(pbfh->bmp));
	if (cScans != (LONG)pbfh->bmp.cy)  /* compare with original number of scans */
	    goto lfread_error_free_bits;
    }
    fRet = TRUE;     /* We made it!  The bits are in the thread's PS. */


    /*******************************************************************
    * Close the file, free the buffer space and leave.	This is a
    * common exit point from the function.  Since the same cleanup
    * operations need to be performed for such a large number of
    * possible error conditions, this is a concise way to do the right
    * thing.
    *******************************************************************/

lfread_error_free_bits:
    DosFreeSeg(sel);
lfread_error_close_file:
    DosClose(hfile);
    return fRet;
}




/************************************************************************
*
*   LfWriteFile
*
*   Calls the OpenDlg function to ask the user what file name to
*   save under.
*
************************************************************************/

VOID
LfWriteFile(hwnd, pthr)
HWND hwnd;
PTHR pthr;
{
    HFILE hFile;
    DLF dlf;
    BITMAPINFOHEADER bmih;


    SetUpDLF( &dlf
	    , DLG_SAVEDLG
	    , &hFile
	    , (PSZ)"\\*.BMP"
	    , (PSZ)"LineFrac"
	    , (PSZ)"Save Bitmap"
	    , NULL );
    dlf.szFileName[0] = '\0';
    dlf.szOpenFile[0] = '\0';

    switch (DlgFile(hwnd,&dlf))
    {
    case TDF_ERRMEM:
    case TDF_INVALID:
	MyMessageBox(hwnd, "Error opening file.");
	break;

    case TDF_NOSAVE:
	break;

    default:
	bmih.cbFix     = sizeof(BITMAPINFOHEADER);
	bmih.cx        = (USHORT) pthr->rcl.xRight;
	bmih.cy        = (USHORT) pthr->rcl.yTop;
	bmih.cPlanes   = pthr->cPlanes;
	bmih.cBitCount = pthr->cBitCount;

	if (!LfWriteBMP(pthr->hps, &bmih, &dlf))
	    MyMessageBox(hwnd, "Error writing file.");
    }
}




/************************************************************************
*
*   LfWriteBMP
*
*   Write the bitmap out to a BMP format file.	Write the file
*   header first, then the bitmap bits.  Space for the header
*   and the bits is allocated.	Huge bitmaps are supported.
*   Free up memory and close the file before leaving.  The file
*   will have been opened by the time this function is called,
*   and the file handle will be in the *pdlf structure.
*
************************************************************************/

BOOL
LfWriteBMP(hPS, pbmih, pdlf)
HPS hPS;		/* hPS from which to get bitmap bits.	  */
PBITMAPINFOHEADER pbmih;/* Bitmap information.			  */
PDLF pdlf;		/* File information filled by DlgFile. */
{
    HFILE hfile;
    ULONG cScans;
    ULONG ulSize;	 /* Number of bytes occupied by bitmap bits.	     */
    USHORT cSegs;	 /* Number of 64K segments in ulSize.		     */
    USHORT cbExtra;	 /* Bytes in last segment of ulSize.		     */
    SEL selBits;	 /* Base selector to bitmap bits.		     */
    USHORT hugeshift;	 /* Segment index shift value.			     */
    USHORT cbBMHdr;	 /* Size of bitmap header.			     */
    PBITMAPFILEHEADER pbfh; /* Pointer to private copy of bitmap info data.	*/
    USHORT cbWrite1;	 /* Number of bytes to write first call to DosWrite  */
    USHORT cbWrite2;	 /* Number of bytes to write second call to DosWrite */
    USHORT cbWritten;	 /* Number of bytes written by DosWrite.	     */
    BOOL fRet = FALSE;	 /* Function return code.			     */
    int i;		 /* Generic loop index. 			     */
    struct
    {
	LONG cPlanes;
	LONG cBitCount;
    } bmFmt;


    hfile = *(pdlf->phFile);

    /*******************************************************************
    * If the bitmap was created with either 0 planes or 0 bits per
    * pixel, then query the format to write with.  By asking for just
    * one format (two LONGs, or one instance of structure of bmFmt),
    * we'll get the device's favored format.
    *******************************************************************/

    if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
    {
	if (!GpiQueryDeviceBitmapFormats(hPS, 2L, (PLONG)&bmFmt))
	    goto lfwrite_error_close_file;
    }
    else
    {
	bmFmt.cPlanes	= pbmih->cPlanes;
	bmFmt.cBitCount = pbmih->cBitCount;
    }


    /*******************************************************************
    * Determine size of bitmap header.	The header consists of a
    * a fixed-size part and a variable-length color table.  The
    * latter has  2^cBitCount  entries, each of which is sizeof(RGB)
    * bytes long.  The exception is when cBitCount is 24, in which
    * case the color table is omitted because the pixels are direct
    * rgb values.
    *******************************************************************/

    i = (int) bmFmt.cBitCount;
    if (i == 24)
	cbBMHdr = 0;
    else
	for (cbBMHdr = sizeof(RGB); i > 0; --i)
	    cbBMHdr *= 2;
    cbBMHdr += sizeof(BITMAPFILEHEADER);


    /*******************************************************************
    * Copy structure from input to work buffer.  The call to
    * GpiQueryBitmapBits will have write-access to this, so we won't
    * let it have the user's data.
    *******************************************************************/

    pbfh = 0;
    if (DosAllocSeg(cbBMHdr, ((PUSHORT)&pbfh)+1, 0))
	goto lfwrite_error_close_file;
    pbfh->bmp = *pbmih;
    if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
    {
	pbfh->bmp.cPlanes   = (USHORT) bmFmt.cPlanes;
	pbfh->bmp.cBitCount = (USHORT) bmFmt.cBitCount;
    }


    /*******************************************************************
    * Allocate space for the bitmap bits -- all of them at once.
    * The extra ULONG casts are there to force all the arithmetic
    * to be done in 32 bits.
    *******************************************************************/

    ulSize = (
	       (
		 (
		   (ULONG)pbfh->bmp.cBitCount
		   * (ULONG)pbfh->bmp.cx
		   + 31L
		 ) / 32L
	       ) * (ULONG)pbfh->bmp.cPlanes * 4L
	     ) * (ULONG)pbfh->bmp.cy;

    cSegs   = (USHORT)(ulSize/0x10000L);
    cbExtra = (USHORT)(ulSize%0x10000L);
    if (DosAllocHuge(cSegs, cbExtra, (PSEL)&selBits, 0, 0))
	goto lfwrite_error_free_header;
    if (DosGetHugeShift(&hugeshift))
	goto lfwrite_error_free_bits;


    /*******************************************************************
    * Tell GPI to give us the bits. The function returns the number
    * of scan lines of the bitmap that were copied.  We want all of
    * them at once.
    *******************************************************************/

    cScans = GpiQueryBitmapBits( hPS
			       , 0L
			       , (ULONG)pbfh->bmp.cy
			       , (PBYTE)MAKEP(selBits, 0)
			       , (PBITMAPINFO)&pbfh->bmp);
    if (cScans != pbfh->bmp.cy)  /* compare with original number of scans */
	goto lfwrite_error_free_bits;


    /*******************************************************************
    * Fill in the extra header fields and write the header out to
    * the file.
    *******************************************************************/

    pbfh->usType    = 0x4D42;		  /* 'MB' */
    pbfh->cbSize    = ulSize + cbBMHdr;
    pbfh->xHotspot  = pbfh->bmp.cx / 2;    /* why bother ? */
    pbfh->yHotspot  = pbfh->bmp.cy / 2;
    pbfh->offBits   = cbBMHdr;

    if (DosWrite( hfile
		, (PVOID)pbfh
		, cbBMHdr
		, &cbWritten))
	goto lfwrite_error_free_bits;
    if (cbWritten != cbBMHdr)
	goto lfwrite_error_free_bits;


    /*******************************************************************
    * Write the bits out to the file. The DosWrite function allows a
    * maximum of 64K-1 bytes written at a time.  We get around this
    * by writing two 32K chunks for each 64K segment, and writing the
    * last segment in one piece.
    *******************************************************************/

    for (i = 0; i <= cSegs; ++i)
    {
	if (i < cSegs)
	{
	    /* This segment is 64K bytes long, so split it up. */
	    cbWrite1 = 0x8000;
	    cbWrite2 = 0x8000;
	}
	else
	{
	    /* This segment is less than 64K bytes long, so write it all. */
	    cbWrite1 = cbExtra;
	    cbWrite2 = 0;
	}

	/* There's a possibility that cbExtra will be 0, so check
	 * to avoid an unnecessary system call.
	 */
	if (cbWrite1 > 0)
	{
	    if (DosWrite( hfile
			, (PVOID)MAKEP(selBits+(i<<hugeshift), 0)
			, cbWrite1
			, &cbWritten))
		goto lfwrite_error_free_bits;
	    if (cbWrite1 != cbWritten)
		goto lfwrite_error_free_bits;
	}

	/* This will always be skipped on the last partial segment. */
	if (cbWrite2 > 0)
	{
	    if (DosWrite( hfile
			, (PVOID)MAKEP(selBits+(i<<hugeshift), cbWrite1)
			, cbWrite2
			, &cbWritten))
		goto lfwrite_error_free_bits;
	    if (cbWrite2 != cbWritten)
		goto lfwrite_error_free_bits;
	}
    }

    fRet = TRUE;     /* We made it!  The bits are on the disk. */


    /*******************************************************************
    * Close the file, free the buffer space and leave.	This is a
    * common exit point from the function.  Since the same cleanup
    * operations need to be performed for such a large number of
    * possible error conditions, this is concise way to do the right
    * thing.
    *******************************************************************/

lfwrite_error_free_bits:
    DosFreeSeg(selBits);
lfwrite_error_free_header:
    DosFreeSeg(*((PUSHORT)&pbfh+1));
lfwrite_error_close_file:
    DosClose(hfile);
    return fRet;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.