|
|
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.