source: trunk/dll/loadbmp.c@ 1102

Last change on this file since 1102 was 1082, checked in by Gregg Young, 17 years ago

Changes so FM2 will use TMP/TEMP directory for all temp files; Replaced save_dir2 with global variable so BldFullPathName could easily replace code that performed the same function; Added #ifdef FORTIFY to free_ function that are only used when fortified.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
RevLine 
[351]1
2/***********************************************************************
3
4 $Id: loadbmp.c 1082 2008-07-19 22:37:36Z gyoung $
5
6 Load bitmaps
7
8 Copyright (c) 1993-98 M. Kimes
[1082]9 Copyright (c) 2006, 2008 Steven H. Levine
[351]10
11 22 Jul 06 SHL Check more run time errors
[549]12 16 Jan 07 SHL Check more run time errors
13 16 Jan 07 SHL Sync variable names for sanity
14 16 Jan 07 SHL Open bitmap file binary - no wonder the code does not work
15 16 Jan 07 SHL Beautify with indent -i2
[1001]16 18 Apr 08 SHL LoadBitmapFromFile ensure pf initialized if no hPS
[1082]17 19 Jul 08 GKY Replace save_dir2(dir) with pFM2SaveDirectory
18
[351]19***********************************************************************/
20
[2]21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <share.h>
[351]25
[907]26#define INCL_DOS
27#define INCL_WIN
28#define INCL_GPI
29#define INCL_LONGLONG // dircnrs.h
30
31#include "errutil.h" // Dos_Error...
[2]32#include "fm3dll.h"
33
[351]34static PSZ pszSrcFile = __FILE__;
35
[549]36HBITMAP LoadBitmapFromFileNum(USHORT id)
[351]37{
[549]38 char s[CCHMAXPATH];
[2]39
[1082]40 //save_dir2(s);
41 strcpy(s, pFM2SaveDirectory);
[549]42 sprintf(s + strlen(s), "\\%u.BMP", id);
[2]43 return LoadBitmapFromFile(s);
44}
45
[549]46HBITMAP LoadBitmapFromFile(CHAR * pszFileName)
[351]47{
[549]48 HBITMAP hBmp = (HBITMAP) 0;
49 FILE *pf;
50 ULONG rc;
51 USHORT usType;
52 PBITMAPARRAYFILEHEADER2 pbmafh2 = NULL; // Must init for xfree
[551]53 PBITMAPFILEHEADER2 pbmfh2; // No color table
54 PBITMAPINFOHEADER2 pbmih2; // No color table
55 PBITMAPINFO2 pbmi2; // Includes color table
56 BOOL is2x; // Format 1.x or 2.x
[549]57 ULONG ulColors;
58 ULONG ulRGBOffset;
[551]59 PBYTE pData = NULL; // Must init for xfree
[549]60 ULONG ulDataSize;
61 SIZEL sizel;
62 HPS hPS = WinGetPS(HWND_DESKTOP);
[2]63
[549]64 if (!hPS) {
[551]65 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__, "WinGetPS");
[1001]66 pf = NULL;
[2]67 goto ExitLoadBMP;
[549]68 }
[2]69
[549]70 pf = _fsopen(pszFileName, "rb", SH_DENYWR);
71 if (!pf) {
72 // OK for file to not exist - enable following for debug as needed
73 // Runtime_Error(pszSrcFile, __LINE__, "_fsopen %s", pszFileName);
[2]74 goto ExitLoadBMP;
[549]75 }
[2]76
[549]77 // Read image type
78 // fixme to just read type2 header - this is silly and wastes time
79 rc = fread(&usType, 1, sizeof(usType), pf);
80 if (rc != sizeof(usType)) {
81 Runtime_Error(pszSrcFile, __LINE__, "fread");
[2]82 goto ExitLoadBMP;
[549]83 }
84
85 /* Read bitmap info header
86 Allocate enough to hold a complete 2.x bitmap array file header
87 fixme to support > 256 colors?
[551]88 */
[549]89 pbmafh2 =
90 xmalloc(sizeof(*pbmafh2) + 256 * sizeof(RGB2), pszSrcFile, __LINE__);
91 if (!pbmafh2)
92 goto ExitLoadBMP;
93 /* Assign pointers to the file header and bitmap info header etc.
94 Both the 1.x and 2.x structures are assigned to simplify code
95 fixme to clean this up - aliased pointers are evil
[551]96 */
[549]97 pbmfh2 = &pbmafh2->bfh2;
98 pbmih2 = &pbmfh2->bmp2;
[551]99 pbmi2 = (PBITMAPINFO2) pbmih2;
[549]100
[2]101 switch (usType) {
[549]102 case BFT_BMAP:
103 case BFT_ICON:
104 case BFT_POINTER:
105 case BFT_COLORICON:
106 case BFT_COLORPOINTER:
107 {
108 /* Assume image is a 2.0 image and read as a 2.x header
[551]109 OK for 1.x file - read will not fail unless file is corrupted
110 */
[549]111 rc = fseek(pf, 0, SEEK_SET);
112 if (rc) {
113 Runtime_Error(pszSrcFile, __LINE__, "fseek 0");
114 goto ExitLoadBMP;
115 }
[2]116
[549]117 rc = fread(pbmfh2, 1, sizeof(*pbmfh2), pf);
118 if (rc != sizeof(*pbmfh2)) {
119 Runtime_Error(pszSrcFile, __LINE__, "fread");
120 goto ExitLoadBMP;
[2]121 }
122
[549]123 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER); // 1.x or 2.x bitmap
124 /* We will read the color table later
[551]125 Color table follows header but
126 location depends on the type of the bitmap (old vs new)
127 1.x header is fixed size
128 2.x header is variable sized, so offset must be calculated
129 cbFix contains actual size of BITMAPINFOHEADER2 in file
130 */
[549]131 ulRGBOffset = is2x ? sizeof(*pbmfh2) - sizeof(*pbmih2) + pbmih2->cbFix :
[551]132 sizeof(BITMAPFILEHEADER);
[549]133 }
134 break;
[2]135
[549]136 case BFT_BITMAPARRAY:
137 {
138 /* Now we are dealing with a bitmap array which is a collection of bitmaps
[551]139 Each bitmap has its own file header
140 */
[2]141
[549]142 ULONG ulCurOffset;
143 ULONG clScreenWidth;
144 ULONG clScreenHeight;
145 ULONG ulDeviceColors;
146 ULONG ulSizeDiff;
147 ULONG ulOffsetPicked = 0;
148 ULONG ulColorsPicked;
149 ULONG ulSizeDiffPicked;
150 HDC hdc;
[2]151
[549]152 /* Scan the array and chose the bitmap best suited
[551]153 for the current display size and color capacities
154 */
[549]155 hdc = GpiQueryDevice(hPS);
156 if (!hdc) {
157 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__,
158 "GpiQueryDevice");
159 goto ExitLoadBMP;
160 }
[551]161 DevQueryCaps(hdc, CAPS_COLORS, 1, (PLONG) & ulDeviceColors);
162 DevQueryCaps(hdc, CAPS_WIDTH, 1, (PLONG) & clScreenWidth);
163 DevQueryCaps(hdc, CAPS_HEIGHT, 1, (PLONG) & clScreenHeight);
[549]164 pbmafh2->offNext = 0;
165 do {
166 ulCurOffset = pbmafh2->offNext;
167 rc = fseek(pf, pbmafh2->offNext, SEEK_SET);
168 if (rc) {
169 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", pbmafh2->offNext);
170 goto ExitLoadBMP;
171 }
172 rc = fread(pbmafh2, 1, sizeof(*pbmafh2), pf);
173 if (rc != sizeof(*pbmafh2)) {
174 Runtime_Error(pszSrcFile, __LINE__, "fread");
175 goto ExitLoadBMP;
176 }
177 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER);
178 if (is2x) {
179 ulColors = 1 << (pbmafh2->bfh2.bmp2.cBitCount *
180 pbmafh2->bfh2.bmp2.cPlanes);
181 }
182 else {
[551]183 ulColors =
184 1 << (((PBITMAPARRAYFILEHEADER) pbmafh2)->bfh.bmp.cBitCount *
185 ((PBITMAPARRAYFILEHEADER) pbmafh2)->bfh.bmp.cPlanes);
[549]186 }
187 if (pbmafh2->cxDisplay == 0 && pbmafh2->cyDisplay == 0) {
188 // This is a device independant bitmap - process it as a VGA
189 pbmafh2->cxDisplay = 640;
190 pbmafh2->cyDisplay = 480;
191 }
192 ulSizeDiff = abs(pbmafh2->cxDisplay - clScreenWidth) +
[551]193 abs(pbmafh2->cyDisplay - clScreenHeight);
[549]194 if (ulDeviceColors == ulColors && ulSizeDiff == 0) {
195 // We found the perfect match
196 ulOffsetPicked = ulCurOffset;
197 break; // Stop scan
198 }
199 if (ulOffsetPicked == 0 || // First time thru
200 ulSizeDiff < ulSizeDiffPicked || // Better fit than any previous
201 (ulColors > ulColorsPicked && ulColors < ulDeviceColors) || // More colors than prev & less than device
[551]202 (ulColors < ulColorsPicked && ulColors > ulDeviceColors)) {
[549]203 ulOffsetPicked = ulCurOffset; // Make this our current pick
204 ulColorsPicked = ulColors;
205 ulSizeDiffPicked = ulSizeDiff;
206 }
207 } while (pbmafh2->offNext != 0);
[2]208
[549]209 // Retrieve the selected bitmap
210 rc = fseek(pf, ulOffsetPicked, SEEK_SET);
211 if (rc) {
212 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", ulOffsetPicked);
213 goto ExitLoadBMP;
[2]214 }
[549]215 rc = fread(pbmafh2, 1, sizeof(*pbmafh2), pf);
216 if (rc != sizeof(*pbmafh2)) {
217 Runtime_Error(pszSrcFile, __LINE__, "fread");
218 goto ExitLoadBMP;
219 }
[2]220
[549]221 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER);
222 /* As before, we calculate offset in file stream to color table
[551]223 This code must match single bitmap logic
224 */
[549]225 ulRGBOffset = ulOffsetPicked;
[551]226 ulRGBOffset +=
227 is2x ? sizeof(*pbmafh2) - sizeof(*pbmih2) +
228 pbmih2->cbFix : sizeof(BITMAPARRAYFILEHEADER);
[549]229 }
230 break;
[2]231
[549]232 default:
233 Runtime_Error(pszSrcFile, __LINE__, "Bad type %u", usType);
[2]234 goto ExitLoadBMP;
[549]235 } // endswitch
[2]236
[549]237 // Position to color table
238 rc = fseek(pf, ulRGBOffset, SEEK_SET);
239 if (rc) {
240 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", ulRGBOffset);
241 goto ExitLoadBMP;
242 }
[2]243
[549]244 // Read color table
245 if (is2x) {
246 /* For a 2.0 bitmap, read the color table as is
247 The bitmap info structure is header + color table
248 If we have 24 bits per pel, there is usually no color table, unless
249 pbmih2->cclrUsed or pbmih2->cclrImportant are non zero
250 fixme to test this
[551]251 */
[549]252 if (pbmih2->cBitCount < 24) {
253 ULONG ulRGBBytes;
[551]254
[549]255 ulColors = 1L << pbmih2->cBitCount;
[2]256
[549]257 if (ulColors > 256) {
[551]258 Runtime_Error(pszSrcFile, __LINE__, "RGB exceeds 256 colors: %lu",
259 ulColors);
[549]260 goto ExitLoadBMP;
261 }
262 ulRGBBytes = ulColors * sizeof(RGB2);
263 rc = fread(&pbmi2->argbColor[0], 1, ulRGBBytes, pf);
264 if (rc != ulRGBBytes) {
265 Runtime_Error(pszSrcFile, __LINE__, "fread");
266 goto ExitLoadBMP;
267 }
268 } // endif
269 // Get pointer to bitmap info (header and color table)
[551]270 pbmi2 = (PBITMAPINFO2) pbmih2;
[2]271 }
272 else {
[549]273 /* This is a 1.x format bitmap
274 Since the current standard format is the 2.0
275 convert the header and color table to 2.x format
[551]276 */
[549]277 ULONG ul;
278 RGB rgb;
[551]279 PBITMAPINFOHEADER pbmih = &((PBITMAPARRAYFILEHEADER) pbmafh2)->bfh.bmp;
[2]280
[549]281 if (pbmih->cBitCount < 24) {
282 ulColors = 1 << pbmih->cBitCount;
283 if (ulColors > 256) {
[551]284 Runtime_Error(pszSrcFile, __LINE__, "RGB exceeds 256 colors: %lu",
285 ulColors);
[549]286 goto ExitLoadBMP;
287 }
288 // Read in 1.x color table and reformat for 2.x
289 for (ul = 0; ul < ulColors; ul++) {
290 fread(&rgb, 1, sizeof(rgb), pf);
291 pbmi2->argbColor[ul].bRed = rgb.bRed;
292 pbmi2->argbColor[ul].bGreen = rgb.bGreen;
293 pbmi2->argbColor[ul].bBlue = rgb.bBlue;
294 pbmi2->argbColor[ul].fcOptions = 0; // initialize 2.x extra byte to 0
[551]295 } // for
[549]296 }
[2]297
[549]298 // Convert the old style to the new header format
299 pbmi2->cbFix = sizeof(BITMAPINFOHEADER2);
300 pbmi2->cBitCount = pbmih->cBitCount;
301 pbmi2->cPlanes = pbmih->cPlanes;
302 pbmi2->cy = pbmih->cy;
303 pbmi2->cx = pbmih->cx;
[2]304 // set rest to zero
[551]305 memset((PCHAR) pbmi2 + 16, 0, sizeof(BITMAPINFOHEADER2) - 16);
306 } // if 1.x
[2]307
[549]308 /* The 2.0 bitmap info structure set up
309 Position to start of the bitmap data
[551]310 */
[549]311 rc = fseek(pf, pbmfh2->offBits, SEEK_SET);
312 if (rc) {
313 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", pbmfh2->offBits);
[2]314 goto ExitLoadBMP;
[549]315 }
[2]316
[549]317 /* Read the bitmap data
318 The read size is derived using the magic formula
319 Each bitmap scan line is aligned on a doubleword boundary
320 The size of the scan line is the number of pels times the bpp
321 After aligning it, we divide by 4 to get the number of bytes, and
322 multiply by the number of scan lines and the number of pel planes
[551]323 */
[549]324 if (pbmi2->ulCompression)
[2]325 ulDataSize = pbmi2->cbImage;
326 else
327 ulDataSize = (((pbmi2->cBitCount * pbmi2->cx) + 31) / 32) * 4 *
[549]328 pbmi2->cy * pbmi2->cPlanes;
329 pData = xmalloc(ulDataSize, pszSrcFile, __LINE__);
330 if (!pData)
[2]331 goto ExitLoadBMP;
[549]332 rc = fread(pData, 1, ulDataSize, pf);
333 if (rc != ulDataSize) {
334 Runtime_Error(pszSrcFile, __LINE__, "fread");
[2]335 goto ExitLoadBMP;
[549]336 }
[2]337
[549]338 // Create the GPI bitmap image
[2]339 sizel.cx = pbmi2->cx;
340 sizel.cy = pbmi2->cy;
341
[549]342 hBmp = GpiCreateBitmap(hPS, (PBITMAPINFOHEADER2) pbmi2, CBM_INIT,
343 pData, pbmi2);
344 if (!hBmp)
345 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__,
346 "GpiCreateBitmap");
[2]347
348ExitLoadBMP:
[351]349
[1009]350 xfree(pData, pszSrcFile, __LINE__);
351 xfree(pbmafh2, pszSrcFile, __LINE__);
[549]352 if (pf)
353 fclose(pf);
354 if (hPS)
355 WinReleasePS(hPS);
[351]356 return hBmp;
[2]357}
[793]358
359#pragma alloc_text(LOADBITMAP,LoadBitmapFromFile,LoadBitmapFromFileNum)
Note: See TracBrowser for help on using the repository browser.