|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.