Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
18 KiB

4 years ago
  1. /******************************Module*Header*******************************\
  2. * Module Name: ssdib.c
  3. *
  4. * Operations on .bmp files
  5. *
  6. * Copyright (c) 1995 Microsoft Corporation
  7. *
  8. \**************************************************************************/
  9. #include <windows.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include "tk.h"
  14. #include "sscommon.h"
  15. #define BFT_BITMAP 0x4d42 // 'BM' -- indicates structure is BITMAPFILEHEADER
  16. // struct BITMAPFILEHEADER {
  17. // WORD bfType
  18. // DWORD bfSize
  19. // WORD bfReserved1
  20. // WORD bfReserved2
  21. // DWORD bfOffBits
  22. // }
  23. #define OFFSET_bfType 0
  24. #define OFFSET_bfSize 2
  25. #define OFFSET_bfReserved1 6
  26. #define OFFSET_bfReserved2 8
  27. #define OFFSET_bfOffBits 10
  28. #define SIZEOF_BITMAPFILEHEADER 14
  29. // Read a WORD-aligned DWORD. Needed because BITMAPFILEHEADER has
  30. // WORD-alignment.
  31. #define READDWORD(pv) ( (DWORD)((PWORD)(pv))[0] \
  32. | ((DWORD)((PWORD)(pv))[1] << 16) ) \
  33. // Computes the number of BYTES needed to contain n number of bits.
  34. #define BITS2BYTES(n) ( ((n) + 7) >> 3 )
  35. /****************************************************************************
  36. * *
  37. * FUNCTION : DibNumColors(VOID FAR * pv) *
  38. * *
  39. * PURPOSE : Determines the number of colors in the DIB by looking at *
  40. * the BitCount filed in the info block. *
  41. * *
  42. * RETURNS : The number of colors in the DIB. *
  43. * *
  44. * Stolen from SDK ShowDIB example. *
  45. ****************************************************************************/
  46. static WORD DibNumColors(VOID FAR * pv)
  47. {
  48. WORD bits;
  49. BITMAPINFOHEADER UNALIGNED *lpbi;
  50. BITMAPCOREHEADER UNALIGNED *lpbc;
  51. lpbi = ((LPBITMAPINFOHEADER)pv);
  52. lpbc = ((LPBITMAPCOREHEADER)pv);
  53. /* With the BITMAPINFO format headers, the size of the palette
  54. * is in biClrUsed, whereas in the BITMAPCORE - style headers, it
  55. * is dependent on the bits per pixel ( = 2 raised to the power of
  56. * bits/pixel).
  57. *
  58. * Because of the way we use this call, BITMAPINFOHEADER may be out
  59. * of alignment if it follows a BITMAPFILEHEADER. So use the macro
  60. * to safely access DWORD fields.
  61. */
  62. if (READDWORD(&lpbi->biSize) != sizeof(BITMAPCOREHEADER)){
  63. if (READDWORD(&lpbi->biClrUsed) != 0)
  64. {
  65. return (WORD) READDWORD(&lpbi->biClrUsed);
  66. }
  67. bits = lpbi->biBitCount;
  68. }
  69. else
  70. bits = lpbc->bcBitCount;
  71. switch (bits){
  72. case 1:
  73. return 2;
  74. case 4:
  75. return 16;
  76. case 8:
  77. return 256;
  78. default:
  79. /* A 24 bitcount DIB has no color table */
  80. return 0;
  81. }
  82. }
  83. /******************************Public*Routine******************************\
  84. * ss_DIBImageLoad
  85. *
  86. * Hacked form of tk_DIBImageLoad(), for reading a .bmp file from a resource
  87. *
  88. * Loads a DIB file (specified as either an ANSI or Unicode filename,
  89. * depending on the bUnicode flag) and converts it into a TK image format.
  90. *
  91. * The technique used is based on CreateDIBSection and SetDIBits.
  92. * CreateDIBSection is used to create a DIB with a format easily converted
  93. * into the TK image format (packed 24BPP RGB). The only conversion
  94. * required is swapping R and B in each RGB triplet (see history below)
  95. * The resulting bitmap is selected into a memory DC.
  96. *
  97. * The DIB file is mapped into memory and SetDIBits called to initialize
  98. * the memory DC bitmap. It is during this step that GDI converts the
  99. * arbitrary DIB file format to RGB format.
  100. *
  101. * Finally, the RGB data in the DIB section is read out and repacked
  102. * as 24BPP 'BGR'.
  103. *
  104. * Returns:
  105. * BOOL. If an error occurs, a diagnostic error
  106. * message is put into the error stream and tkQuit() is called,
  107. * terminating the app.
  108. *
  109. * History:
  110. * - 11/30/95: [marcfo]
  111. * Modified from tkDIBImageLoad, to work on resource bmp file.
  112. * At first I tried accessing the bitmap resource as an RT_BITMAP, where
  113. * the resource compiler strips out file information, and leaves you simple
  114. * bitmap data. But this only worked on the Alpha architecture, x86
  115. * produced a resource with corrupted image data (?palette :)). So I ended
  116. * up just slamming the entire .bmp file in as a resource.
  117. *
  118. \**************************************************************************/
  119. BOOL ss_DIBImageLoad(PVOID pv, TEXTURE *ptex)
  120. {
  121. BOOL fSuccess = FALSE;
  122. WORD wNumColors; // Number of colors in color table
  123. BITMAPFILEHEADER *pbmf; // Ptr to file header
  124. BITMAPINFOHEADER UNALIGNED *pbmihFile;
  125. BITMAPCOREHEADER UNALIGNED *pbmchFile; // Ptr to file's core header (if it exists)
  126. PVOID pvBits; // Ptr to bitmap bits in file
  127. PBYTE pjBitsRGB; // Ptr to 24BPP RGB image in DIB section
  128. PBYTE pjTKBits = (PBYTE) NULL; // Ptr to final TK image bits
  129. PBYTE pjSrc; // Ptr to image file used for conversion
  130. PBYTE pjDst; // Ptr to TK image used for conversion
  131. // These need to be cleaned up when we exit:
  132. HDC hdcMem = (HDC) NULL; // 24BPP mem DC
  133. HBITMAP hbmRGB = (HBITMAP) NULL; // 24BPP RGB bitmap
  134. BITMAPINFO *pbmiSource = (BITMAPINFO *) NULL; // Ptr to source BITMAPINFO
  135. BITMAPINFO *pbmiRGB = (BITMAPINFO *) NULL; // Ptr to file's BITMAPINFO
  136. int i, j;
  137. int padBytes;
  138. // Otherwise, this may be a raw BITMAPINFOHEADER or BITMAPCOREHEADER
  139. // followed immediately with the color table and the bitmap bits.
  140. pbmf = (BITMAPFILEHEADER *) pv;
  141. if ( pbmf->bfType == BFT_BITMAP )
  142. {
  143. pbmihFile = (BITMAPINFOHEADER *) ((PBYTE) pbmf + SIZEOF_BITMAPFILEHEADER);
  144. // BITMAPFILEHEADER is WORD aligned, so use safe macro to read DWORD
  145. // bfOffBits field.
  146. pvBits = (PVOID *) ((PBYTE) pbmf
  147. + READDWORD((PBYTE) pbmf + OFFSET_bfOffBits));
  148. }
  149. else
  150. {
  151. pbmihFile = (BITMAPINFOHEADER *) pv;
  152. // Determination of where the bitmaps bits are needs to wait until we
  153. // know for sure whether we have a BITMAPINFOHEADER or a BITMAPCOREHEADER.
  154. }
  155. // Determine the number of colors in the DIB palette. This is non-zero
  156. // only for 8BPP or less.
  157. wNumColors = DibNumColors(pbmihFile);
  158. // Create a BITMAPINFO (with color table) for the DIB file. Because the
  159. // file may not have one (BITMAPCORE case) and potential alignment problems,
  160. // we will create a new one in memory we allocate.
  161. //
  162. // We distinguish between BITMAPINFO and BITMAPCORE cases based upon
  163. // BITMAPINFOHEADER.biSize.
  164. pbmiSource = (BITMAPINFO *)
  165. LocalAlloc(LMEM_FIXED, sizeof(BITMAPINFO)
  166. + wNumColors * sizeof(RGBQUAD));
  167. if (!pbmiSource)
  168. {
  169. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  170. goto tkDIBLoadImage_cleanup;
  171. }
  172. // Note: need to use safe READDWORD macro because pbmihFile may
  173. // have only WORD alignment if it follows a BITMAPFILEHEADER.
  174. switch (READDWORD(&pbmihFile->biSize))
  175. {
  176. case sizeof(BITMAPINFOHEADER):
  177. // Convert WORD-aligned BITMAPINFOHEADER to aligned BITMAPINFO.
  178. pbmiSource->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  179. pbmiSource->bmiHeader.biWidth = READDWORD(&pbmihFile->biWidth);
  180. pbmiSource->bmiHeader.biHeight = READDWORD(&pbmihFile->biHeight);
  181. pbmiSource->bmiHeader.biPlanes = pbmihFile->biPlanes;
  182. pbmiSource->bmiHeader.biBitCount = pbmihFile->biBitCount;
  183. pbmiSource->bmiHeader.biCompression =
  184. READDWORD(&pbmihFile->biCompression);
  185. pbmiSource->bmiHeader.biSizeImage =
  186. READDWORD(&pbmihFile->biSizeImage);
  187. pbmiSource->bmiHeader.biXPelsPerMeter =
  188. READDWORD(&pbmihFile->biXPelsPerMeter);
  189. pbmiSource->bmiHeader.biYPelsPerMeter =
  190. READDWORD(&pbmihFile->biYPelsPerMeter);
  191. pbmiSource->bmiHeader.biClrUsed =
  192. READDWORD(&pbmihFile->biClrUsed);
  193. pbmiSource->bmiHeader.biClrImportant =
  194. READDWORD(&pbmihFile->biClrImportant);
  195. // Copy color table. It immediately follows the BITMAPINFOHEADER.
  196. memcpy((PVOID) &pbmiSource->bmiColors[0], (PVOID) (pbmihFile + 1),
  197. wNumColors * sizeof(RGBQUAD));
  198. // If we haven't already determined the position of the image bits,
  199. // we may now assume that they immediately follow the color table.
  200. if (!pvBits)
  201. pvBits = (PVOID) ((PBYTE) (pbmihFile + 1)
  202. + wNumColors * sizeof(RGBQUAD));
  203. break;
  204. case sizeof(BITMAPCOREHEADER):
  205. pbmchFile = (BITMAPCOREHEADER *) pbmihFile;
  206. // Convert BITMAPCOREHEADER to BITMAPINFOHEADER.
  207. pbmiSource->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  208. pbmiSource->bmiHeader.biWidth = (DWORD) pbmchFile->bcWidth;
  209. pbmiSource->bmiHeader.biHeight = (DWORD) pbmchFile->bcHeight;
  210. pbmiSource->bmiHeader.biPlanes = pbmchFile->bcPlanes;
  211. pbmiSource->bmiHeader.biBitCount = pbmchFile->bcBitCount;
  212. pbmiSource->bmiHeader.biCompression = BI_RGB;
  213. pbmiSource->bmiHeader.biSizeImage = 0;
  214. pbmiSource->bmiHeader.biXPelsPerMeter = 0;
  215. pbmiSource->bmiHeader.biYPelsPerMeter = 0;
  216. pbmiSource->bmiHeader.biClrUsed = wNumColors;
  217. pbmiSource->bmiHeader.biClrImportant = wNumColors;
  218. // Convert RGBTRIPLE color table into RGBQUAD color table.
  219. {
  220. RGBQUAD *rgb4 = pbmiSource->bmiColors;
  221. RGBTRIPLE *rgb3 = (RGBTRIPLE *) (pbmchFile + 1);
  222. for (i = 0; i < wNumColors; i++)
  223. {
  224. rgb4->rgbRed = rgb3->rgbtRed ;
  225. rgb4->rgbGreen = rgb3->rgbtGreen;
  226. rgb4->rgbBlue = rgb3->rgbtBlue ;
  227. rgb4->rgbReserved = 0;
  228. rgb4++;
  229. rgb3++;
  230. }
  231. }
  232. // If we haven't already determined the position of the image bits,
  233. // we may now assume that they immediately follow the color table.
  234. if (!pvBits)
  235. pvBits = (PVOID) ((PBYTE) (pbmihFile + 1)
  236. + wNumColors * sizeof(RGBTRIPLE));
  237. break;
  238. default:
  239. MESSAGEBOX(GetFocus(), "Unknown DIB file format.", "Error", MB_OK);
  240. goto tkDIBLoadImage_cleanup;
  241. }
  242. // Fill in default values (for fields that can have defaults).
  243. if (pbmiSource->bmiHeader.biSizeImage == 0)
  244. pbmiSource->bmiHeader.biSizeImage =
  245. BITS2BYTES( (DWORD) pbmiSource->bmiHeader.biWidth *
  246. pbmiSource->bmiHeader.biBitCount ) *
  247. pbmiSource->bmiHeader.biHeight;
  248. if (pbmiSource->bmiHeader.biClrUsed == 0)
  249. pbmiSource->bmiHeader.biClrUsed = wNumColors;
  250. // Create memory DC.
  251. hdcMem = CreateCompatibleDC(NULL);
  252. if (!hdcMem) {
  253. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  254. goto tkDIBLoadImage_cleanup;
  255. }
  256. // Create a 24BPP RGB DIB section and select it into the memory DC.
  257. pbmiRGB = (BITMAPINFO *)
  258. LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, sizeof(BITMAPINFO) );
  259. if (!pbmiRGB)
  260. {
  261. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  262. goto tkDIBLoadImage_cleanup;
  263. }
  264. pbmiRGB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  265. pbmiRGB->bmiHeader.biWidth = pbmiSource->bmiHeader.biWidth;
  266. pbmiRGB->bmiHeader.biHeight = pbmiSource->bmiHeader.biHeight;
  267. pbmiRGB->bmiHeader.biPlanes = 1;
  268. pbmiRGB->bmiHeader.biBitCount = 24;
  269. pbmiRGB->bmiHeader.biCompression = BI_RGB;
  270. pbmiRGB->bmiHeader.biSizeImage = pbmiRGB->bmiHeader.biWidth
  271. * abs(pbmiRGB->bmiHeader.biHeight) * 3;
  272. hbmRGB = CreateDIBSection(hdcMem, pbmiRGB, DIB_RGB_COLORS,
  273. (PVOID *) &pjBitsRGB, NULL, 0);
  274. if (!hbmRGB)
  275. {
  276. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  277. goto tkDIBLoadImage_cleanup;
  278. }
  279. if (!SelectObject(hdcMem, hbmRGB))
  280. {
  281. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  282. goto tkDIBLoadImage_cleanup;
  283. }
  284. // Slam the DIB file image into the memory DC. GDI will do the work of
  285. // translating whatever format the DIB file has into RGB format.
  286. if (!SetDIBits(hdcMem, hbmRGB, 0, pbmiSource->bmiHeader.biHeight,
  287. pvBits, pbmiSource, DIB_RGB_COLORS))
  288. {
  289. MESSAGEBOX(GetFocus(), "Image file conversion error.", "Error", MB_OK);
  290. goto tkDIBLoadImage_cleanup;
  291. }
  292. GdiFlush(); // make sure that SetDIBits executes
  293. // Convert to TK image format (packed RGB format).
  294. // Allocate with malloc to be consistent with tkRGBImageLoad (i.e., app
  295. // can deallocate with free()).
  296. pjTKBits = (PBYTE) malloc(pbmiRGB->bmiHeader.biSizeImage);
  297. if (!pjTKBits)
  298. {
  299. MESSAGEBOX(GetFocus(), "Out of memory.", "Error", MB_OK);
  300. goto tkDIBLoadImage_cleanup;
  301. }
  302. pjSrc = pjBitsRGB;
  303. pjDst = pjTKBits;
  304. // src lines end on LONG boundary - so need to skip over any padding bytes
  305. padBytes = pbmiSource->bmiHeader.biWidth % sizeof(LONG);
  306. for (i = 0; i < pbmiSource->bmiHeader.biHeight; i++)
  307. {
  308. for (j = 0; j < pbmiSource->bmiHeader.biWidth; j++)
  309. {
  310. // swap R and B
  311. *pjDst++ = pjSrc[2];
  312. *pjDst++ = pjSrc[1];
  313. *pjDst++ = pjSrc[0];
  314. pjSrc += 3;
  315. }
  316. pjSrc += padBytes;
  317. }
  318. // Initialize the texture structure
  319. // If we get to here, we have suceeded!
  320. ptex->width = pbmiSource->bmiHeader.biWidth;
  321. ptex->height = pbmiSource->bmiHeader.biHeight;
  322. ptex->format = GL_RGB;
  323. ptex->components = 3;
  324. ptex->data = pjTKBits;
  325. ptex->pal_size = 0;
  326. ptex->pal = NULL;
  327. fSuccess = TRUE;
  328. // Cleanup objects.
  329. tkDIBLoadImage_cleanup:
  330. {
  331. if (hdcMem)
  332. DeleteDC(hdcMem);
  333. if (hbmRGB)
  334. DeleteObject(hbmRGB);
  335. if (pbmiRGB)
  336. LocalFree(pbmiRGB);
  337. if (pbmiSource)
  338. LocalFree(pbmiSource);
  339. }
  340. // Check for error.
  341. if (!fSuccess)
  342. {
  343. if (pjTKBits)
  344. free(pjTKBits);
  345. }
  346. return fSuccess;
  347. }
  348. /******************************Public*Routine******************************\
  349. *
  350. * bVerifyDIB
  351. *
  352. * Stripped down version of tkDIBImageLoadAW that verifies that a bitmap
  353. * file is valid and, if so, returns the bitmap dimensions.
  354. *
  355. * Returns:
  356. * TRUE if valid bitmap file; otherwise, FALSE.
  357. *
  358. \**************************************************************************/
  359. BOOL
  360. bVerifyDIB(LPTSTR pszFileName, ISIZE *pSize )
  361. {
  362. BOOL bRet = FALSE;
  363. BITMAPFILEHEADER *pbmf; // Ptr to file header
  364. BITMAPINFOHEADER *pbmihFile; // Ptr to file's info header (if it exists)
  365. BITMAPCOREHEADER *pbmchFile; // Ptr to file's core header (if it exists)
  366. // These need to be cleaned up when we exit:
  367. HANDLE hFile = INVALID_HANDLE_VALUE; // File handle
  368. HANDLE hMap = (HANDLE) NULL; // Mapping object handle
  369. PVOID pvFile = (PVOID) NULL; // Ptr to mapped file
  370. // Map the DIB file into memory.
  371. hFile = CreateFile((LPTSTR) pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
  372. if (hFile == INVALID_HANDLE_VALUE)
  373. goto bVerifyDIB_cleanup;
  374. hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  375. if (!hMap)
  376. goto bVerifyDIB_cleanup;
  377. pvFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  378. if (!pvFile)
  379. goto bVerifyDIB_cleanup;
  380. // Check the file header. If the BFT_BITMAP magic number is there,
  381. // then the file format is a BITMAPFILEHEADER followed immediately
  382. // by either a BITMAPINFOHEADER or a BITMAPCOREHEADER. The bitmap
  383. // bits, in this case, are located at the offset bfOffBits from the
  384. // BITMAPFILEHEADER.
  385. //
  386. // Otherwise, this may be a raw BITMAPINFOHEADER or BITMAPCOREHEADER
  387. // followed immediately with the color table and the bitmap bits.
  388. pbmf = (BITMAPFILEHEADER *) pvFile;
  389. if ( pbmf->bfType == BFT_BITMAP )
  390. pbmihFile = (BITMAPINFOHEADER *) ((PBYTE) pbmf + SIZEOF_BITMAPFILEHEADER);
  391. else
  392. pbmihFile = (BITMAPINFOHEADER *) pvFile;
  393. // Get the width and height from whatever header we have.
  394. //
  395. // We distinguish between BITMAPINFO and BITMAPCORE cases based upon
  396. // BITMAPINFOHEADER.biSize.
  397. // Note: need to use safe READDWORD macro because pbmihFile may
  398. // have only WORD alignment if it follows a BITMAPFILEHEADER.
  399. switch (READDWORD(&pbmihFile->biSize))
  400. {
  401. case sizeof(BITMAPINFOHEADER):
  402. if( pSize != NULL ) {
  403. pSize->width = READDWORD(&pbmihFile->biWidth);
  404. pSize->height = READDWORD(&pbmihFile->biHeight);
  405. }
  406. bRet = TRUE;
  407. break;
  408. case sizeof(BITMAPCOREHEADER):
  409. pbmchFile = (BITMAPCOREHEADER *) pbmihFile;
  410. // Convert BITMAPCOREHEADER to BITMAPINFOHEADER.
  411. if( pSize != NULL ) {
  412. pSize->width = (DWORD) pbmchFile->bcWidth;
  413. pSize->height = (DWORD) pbmchFile->bcHeight;
  414. }
  415. bRet = TRUE;
  416. break;
  417. default:
  418. break;
  419. }
  420. bVerifyDIB_cleanup:
  421. if (pvFile)
  422. UnmapViewOfFile(pvFile);
  423. if (hMap)
  424. CloseHandle(hMap);
  425. if (hFile != INVALID_HANDLE_VALUE)
  426. CloseHandle(hFile);
  427. return bRet;
  428. }