Source code of Windows XP (NT5)
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.

612 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: I C O M E R G E . C P P
  7. //
  8. // Contents: Utility functions for loading and merging icons
  9. //
  10. // Notes:
  11. //
  12. // Author: jeffspr 18 Nov 1998
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "ncdebug.h"
  18. #include "icomerge.h"
  19. #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
  20. UINT ReadICOHeader( HANDLE hFile )
  21. {
  22. WORD Input;
  23. DWORD dwBytesRead; // Read the 'reserved' WORD
  24. if( ! ReadFile( hFile, &Input, sizeof( WORD ), &dwBytesRead, NULL ) )
  25. return (UINT)-1; // Did we get a WORD?
  26. if( dwBytesRead != sizeof( WORD ) )
  27. return (UINT)-1; // Was it 'reserved' ? (ie 0)
  28. if( Input != 0 )
  29. return (UINT)-1; // Read the type WORD
  30. if( ! ReadFile( hFile, &Input, sizeof( WORD ), &dwBytesRead, NULL ) )
  31. return (UINT)-1; // Did we get a WORD?
  32. if( dwBytesRead != sizeof( WORD ) )
  33. return (UINT)-1; // Was it type 1?
  34. if( Input != 1 )
  35. return (UINT)-1; // Get the count of images
  36. if( ! ReadFile( hFile, &Input, sizeof( WORD ), &dwBytesRead, NULL ) )
  37. return (UINT)-1; // Did we get a WORD?
  38. if( dwBytesRead != sizeof( WORD ) )
  39. return (UINT)-1; // Return the count
  40. return Input;
  41. }
  42. DWORD BytesPerLine( LPBITMAPINFOHEADER lpBMIH )
  43. {
  44. return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount);
  45. }
  46. WORD DIBNumColors( PSTR lpbi )
  47. {
  48. WORD wBitCount;
  49. DWORD dwClrUsed;
  50. dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed;
  51. if (dwClrUsed)
  52. return (WORD) dwClrUsed;
  53. wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount;
  54. switch (wBitCount)
  55. {
  56. case 1:
  57. return 2;
  58. case 4:
  59. return 16;
  60. case 8:
  61. return 256;
  62. default:
  63. return 0;
  64. }
  65. return 0;
  66. }
  67. WORD PaletteSize( PSTR lpbi )
  68. {
  69. return ( DIBNumColors( lpbi ) * sizeof( RGBQUAD ) );
  70. }
  71. PSTR FindDIBBits( PSTR lpbi )
  72. {
  73. return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) );
  74. }
  75. BOOL AdjustIconImagePointers( LPICONIMAGE lpImage )
  76. { // Sanity check
  77. if( lpImage==NULL )
  78. return FALSE; // BITMAPINFO is at beginning of bits
  79. lpImage->lpbi = (LPBITMAPINFO)lpImage->lpBits; // Width - simple enough
  80. lpImage->Width = lpImage->lpbi->bmiHeader.biWidth; // Icons are stored in funky format where height is doubled - account for it
  81. lpImage->Height = (lpImage->lpbi->bmiHeader.biHeight)/2; // How many colors?
  82. lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes * lpImage->lpbi->bmiHeader.biBitCount; // XOR bits follow the header and color table
  83. lpImage->lpXOR = (unsigned char *)FindDIBBits((PSTR)lpImage->lpbi); // AND bits follow the XOR bits
  84. lpImage->lpAND = lpImage->lpXOR + (lpImage->Height*BytesPerLine((LPBITMAPINFOHEADER)(lpImage->lpbi)));
  85. return TRUE;
  86. }
  87. //+---------------------------------------------------------------------------
  88. //
  89. // Function: ReadIconFromICOFile
  90. //
  91. // Purpose: Load an icon into memory
  92. //
  93. // Arguments:
  94. // szFileName [in] ICO file to read
  95. //
  96. // Returns:
  97. //
  98. // Author: jeffspr 18 Nov 1998
  99. //
  100. // Notes:
  101. //
  102. LPICONRESOURCE ReadIconFromICOFile( PCWSTR szFileName )
  103. {
  104. LPICONRESOURCE lpIR = NULL, lpNew = NULL;
  105. HANDLE hFile = NULL;
  106. UINT i;
  107. DWORD dwBytesRead;
  108. LPICONDIRENTRY lpIDE = NULL;
  109. // Open the file
  110. if( (hFile = CreateFile( szFileName, GENERIC_READ, 0, NULL,
  111. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE )
  112. {
  113. MessageBox( NULL, L"Error Opening File for Reading", szFileName, MB_OK );
  114. return NULL;
  115. }
  116. // Allocate memory for the resource structure
  117. if( (lpIR = (LPICONRESOURCE) malloc( sizeof(ICONRESOURCE) )) == NULL )
  118. {
  119. MessageBox( NULL, L"Error Allocating Memory", szFileName, MB_OK );
  120. CloseHandle( hFile );
  121. return NULL;
  122. }
  123. // Read in the header
  124. if( (lpIR->nNumImages = ReadICOHeader( hFile )) == (UINT)-1 )
  125. {
  126. MessageBox( NULL, L"Error Reading File Header", szFileName, MB_OK );
  127. CloseHandle( hFile );
  128. free( lpIR );
  129. return NULL;
  130. }
  131. // Adjust the size of the struct to account for the images
  132. if( (lpNew = (LPICONRESOURCE) realloc( lpIR, sizeof(ICONRESOURCE) +
  133. ((lpIR->nNumImages-1) * sizeof(ICONIMAGE)) )) == NULL )
  134. {
  135. MessageBox( NULL, L"Error Allocating Memory", szFileName, MB_OK );
  136. CloseHandle( hFile );
  137. free( lpIR );
  138. return NULL;
  139. }
  140. lpIR = lpNew;
  141. // Store the original name
  142. lstrcpyW( lpIR->szOriginalICOFileName, szFileName );
  143. lstrcpyW( lpIR->szOriginalDLLFileName, L"" );
  144. // Allocate enough memory for the icon directory entries
  145. if( (lpIDE = (LPICONDIRENTRY) malloc( lpIR->nNumImages * sizeof( ICONDIRENTRY ) ) ) == NULL )
  146. {
  147. MessageBox( NULL, L"Error Allocating Memory", szFileName, MB_OK );
  148. CloseHandle( hFile );
  149. free( lpIR );
  150. return NULL;
  151. }
  152. // Read in the icon directory entries
  153. if( ! ReadFile( hFile, lpIDE, lpIR->nNumImages * sizeof( ICONDIRENTRY ), &dwBytesRead, NULL ) )
  154. {
  155. MessageBox( NULL, L"Error Reading File", szFileName, MB_OK );
  156. CloseHandle( hFile );
  157. free( lpIR );
  158. return NULL;
  159. }
  160. if( dwBytesRead != lpIR->nNumImages * sizeof( ICONDIRENTRY ) )
  161. {
  162. MessageBox( NULL, L"Error Reading File", szFileName, MB_OK );
  163. CloseHandle( hFile );
  164. free( lpIR );
  165. return NULL;
  166. }
  167. // Loop through and read in each image
  168. for( i = 0; i < lpIR->nNumImages; i++ )
  169. {
  170. // Allocate memory for the resource
  171. if( (lpIR->IconImages[i].lpBits = (LPBYTE) malloc(lpIDE[i].dwBytesInRes)) == NULL )
  172. {
  173. MessageBox( NULL, L"Error Allocating Memory", szFileName, MB_OK );
  174. CloseHandle( hFile );
  175. free( lpIR );
  176. free( lpIDE );
  177. return NULL;
  178. }
  179. lpIR->IconImages[i].dwNumBytes = lpIDE[i].dwBytesInRes;
  180. // Seek to beginning of this image
  181. if( SetFilePointer( hFile, lpIDE[i].dwImageOffset, NULL, FILE_BEGIN ) == 0xFFFFFFFF )
  182. {
  183. MessageBox( NULL, L"Error Seeking in File", szFileName, MB_OK );
  184. CloseHandle( hFile );
  185. free( lpIR );
  186. free( lpIDE );
  187. return NULL;
  188. }
  189. // Read it in
  190. if( ! ReadFile( hFile, lpIR->IconImages[i].lpBits, lpIDE[i].dwBytesInRes, &dwBytesRead, NULL ) )
  191. {
  192. MessageBox( NULL, L"Error Reading File", szFileName, MB_OK );
  193. CloseHandle( hFile );
  194. free( lpIR );
  195. free( lpIDE );
  196. return NULL;
  197. }
  198. if( dwBytesRead != lpIDE[i].dwBytesInRes )
  199. {
  200. MessageBox( NULL, L"Error Reading File", szFileName, MB_OK );
  201. CloseHandle( hFile );
  202. free( lpIDE );
  203. free( lpIR );
  204. return NULL;
  205. }
  206. // Set the internal pointers appropriately
  207. if( ! AdjustIconImagePointers( &(lpIR->IconImages[i]) ) )
  208. {
  209. MessageBox( NULL, L"Error Converting to INternal format", szFileName, MB_OK );
  210. CloseHandle( hFile );
  211. free( lpIDE );
  212. free( lpIR );
  213. return NULL;
  214. }
  215. }
  216. // Clean up
  217. free( lpIDE );
  218. CloseHandle( hFile );
  219. return lpIR;
  220. }
  221. UINT GetBits(UINT uiNumber, INT iStart, INT iBits)
  222. {
  223. return (uiNumber >> (iStart+1-iBits)) & ~(~0 << iBits);
  224. }
  225. VOID DebugPrintIconMasks(LPICONRESOURCE pIR)
  226. {
  227. UINT uiColorLoop = 0;
  228. UINT uiColors = pIR->IconImages[0].Colors;
  229. UINT uiBitCount = pIR->IconImages[0].lpbi->bmiHeader.biBitCount;
  230. printf("Num images: %d\n", pIR->nNumImages);
  231. printf("Name: %S\n", pIR->szOriginalICOFileName);
  232. #if 0
  233. UINT Width, Height, Colors; // Width, Height and bpp
  234. LPBYTE lpBits; // ptr to DIB bits
  235. DWORD dwNumBytes; // how many bytes?
  236. LPBITMAPINFO lpbi; // ptr to header
  237. LPBYTE lpXOR; // ptr to XOR image bits
  238. LPBYTE lpAND; // ptr to AND image bits
  239. #endif
  240. printf("Width: %d, Height: %d\n", pIR->IconImages[0].Width, pIR->IconImages[0].Height);
  241. printf("Color Depth: %d\n", uiBitCount);
  242. printf("Colors: %d, Bytes: %d\n", uiColors, pIR->IconImages[0].dwNumBytes);
  243. for (uiColorLoop = 0; uiColorLoop < uiColors; uiColorLoop++)
  244. {
  245. printf("Color %d, R: %d G: %d B: %d\n",
  246. uiColorLoop,
  247. pIR->IconImages[0].lpbi->bmiColors[uiColorLoop].rgbRed,
  248. pIR->IconImages[0].lpbi->bmiColors[uiColorLoop].rgbGreen,
  249. pIR->IconImages[0].lpbi->bmiColors[uiColorLoop].rgbBlue);
  250. }
  251. UINT uiNewLine = 0;
  252. UINT uiNewByte = 0;
  253. UINT uiByteLoop = 0;
  254. UINT uiPixel = 0;
  255. printf("XOR map:\n");
  256. while(uiPixel < (pIR->IconImages[0].Width * pIR->IconImages[0].Height))
  257. {
  258. BYTE bCurrentByte = pIR->IconImages[0].lpXOR[uiByteLoop];
  259. if (uiBitCount == 4)
  260. {
  261. BYTE bXOR = (bCurrentByte & 0xF0);
  262. if (bXOR > 0)
  263. printf("*");
  264. else
  265. printf(" ");
  266. if (++uiNewLine >= pIR->IconImages[0].Width)
  267. {
  268. uiNewLine = 0;
  269. printf("\n");
  270. }
  271. bXOR = (bCurrentByte & 0x0F);
  272. if (bXOR > 0)
  273. printf("*");
  274. else
  275. printf(" ");
  276. if (++uiNewLine >= pIR->IconImages[0].Width)
  277. {
  278. uiNewLine = 0;
  279. printf("\n");
  280. }
  281. uiByteLoop++;
  282. uiPixel += 2;
  283. }
  284. else
  285. {
  286. Assert(uiBitCount == 8);
  287. BYTE bXOR = pIR->IconImages[0].lpXOR[uiPixel];
  288. if (bXOR > 0)
  289. printf("*");
  290. else
  291. printf(" ");
  292. if (++uiNewLine >= pIR->IconImages[0].Width)
  293. {
  294. uiNewLine = 0;
  295. printf("\n");
  296. }
  297. uiPixel++;
  298. }
  299. }
  300. uiNewLine = 0;
  301. UINT uiANDBytes = (pIR->IconImages[0].Width * pIR->IconImages[0].Height) / 8;
  302. printf("AND map:\n");
  303. for (uiPixel = 0; uiPixel < uiANDBytes; uiPixel++)
  304. {
  305. UINT uiCurrentByte = pIR->IconImages[0].lpAND[uiPixel];
  306. UINT uiCurrentBit = 0;
  307. for (uiCurrentBit = 0; uiCurrentBit < 8; uiCurrentBit++)
  308. {
  309. if (GetBits(uiCurrentByte, 7-uiCurrentBit, 1))
  310. {
  311. printf("*");
  312. }
  313. else
  314. {
  315. printf(" ");
  316. }
  317. if (++uiNewLine >= pIR->IconImages[0].Width)
  318. {
  319. uiNewLine = 0;
  320. printf("\n");
  321. }
  322. }
  323. }
  324. }
  325. VOID OverlayIcons(LPICONRESOURCE pIRBase, LPICONRESOURCE pIROverlay)
  326. {
  327. UINT uiANDLoop = 0;
  328. UINT uiXORByte = 0;
  329. UINT uiANDBytes = (pIROverlay->IconImages[0].Width * pIROverlay->IconImages[0].Height) / 8;
  330. UINT uiNewLine = 0;
  331. UINT uiBitCountBase = pIRBase->IconImages[0].lpbi->bmiHeader.biBitCount;
  332. UINT uiBitCountOverlay = pIROverlay->IconImages[0].lpbi->bmiHeader.biBitCount;
  333. if (uiBitCountBase != uiBitCountOverlay)
  334. {
  335. AssertSz(uiBitCountBase == uiBitCountOverlay, "Non-compatible bitcounts");
  336. printf("*** ERROR *** Icon bitcounts different in OverlayIcons, base: %d, overlay: %d",
  337. uiBitCountBase, uiBitCountOverlay);
  338. goto Exit;
  339. }
  340. for (uiANDLoop = 0; uiANDLoop < uiANDBytes; uiANDLoop++)
  341. {
  342. BYTE uiCurrentByte = pIROverlay->IconImages[0].lpAND[uiANDLoop];
  343. UINT uiCurrentBit = 0;
  344. for (uiCurrentBit = 0; uiCurrentBit < 8; uiCurrentBit++)
  345. {
  346. if (!GetBits(uiCurrentByte, 7-uiCurrentBit, 1))
  347. {
  348. // printf("$");
  349. BYTE bNewANDBits = 1;
  350. BYTE bXORBaseMask = 0x00;
  351. BYTE bXOROverlayMask = 0x00;
  352. BYTE bNewXORBits = 0x00;
  353. bNewANDBits <<= (7-uiCurrentBit);
  354. bNewANDBits = ~bNewANDBits;
  355. pIRBase->IconImages[0].lpAND[uiANDLoop] &= bNewANDBits;
  356. switch(uiBitCountBase)
  357. {
  358. case 4:
  359. // If even number, use the first set of bits
  360. //
  361. if ((uiCurrentBit % 2) == 0)
  362. {
  363. bXORBaseMask = 0x0F;
  364. bXOROverlayMask = 0xF0;
  365. }
  366. else
  367. {
  368. bXORBaseMask = 0xF0;
  369. bXOROverlayMask = 0x0F;
  370. }
  371. break;
  372. case 8:
  373. bXORBaseMask = 0x00;
  374. bXOROverlayMask = 0xFF;
  375. break;
  376. default:
  377. AssertSz(FALSE, "Unsupported bitcount in OverlayIcons. What's up with that?");
  378. printf("*** ERROR *** Non-supported bitcount, bits: %d\n", uiBitCountBase);
  379. break;
  380. }
  381. bNewXORBits = (pIRBase->IconImages[0].lpXOR[uiXORByte] & bXORBaseMask) |
  382. (pIROverlay->IconImages[0].lpXOR[uiXORByte] & bXOROverlayMask);
  383. pIRBase->IconImages[0].lpXOR[uiXORByte] = bNewXORBits;
  384. }
  385. else
  386. {
  387. // printf(" ");
  388. }
  389. switch(uiBitCountBase)
  390. {
  391. case 4:
  392. if ((uiCurrentBit % 2))
  393. {
  394. uiXORByte++;
  395. }
  396. break;
  397. case 8:
  398. uiXORByte++;
  399. break;
  400. }
  401. if (++uiNewLine >= pIROverlay->IconImages[0].Width)
  402. {
  403. uiNewLine = 0;
  404. // printf("\n");
  405. }
  406. }
  407. }
  408. Exit:
  409. return;
  410. }
  411. BOOL WriteICOHeader( HANDLE hFile, UINT nNumEntries )
  412. {
  413. WORD Output;
  414. DWORD dwBytesWritten;
  415. // Write 'reserved' WORD
  416. Output = 0;
  417. if( ! WriteFile( hFile, &Output, sizeof( WORD ), &dwBytesWritten, NULL ) )
  418. return FALSE;
  419. // Did we write a WORD?
  420. if( dwBytesWritten != sizeof( WORD ) )
  421. return FALSE;
  422. // Write 'type' WORD (1)
  423. Output = 1;
  424. if( ! WriteFile( hFile, &Output, sizeof( WORD ), &dwBytesWritten, NULL ) )
  425. return FALSE;
  426. // Did we write a WORD?
  427. if( dwBytesWritten != sizeof( WORD ) )
  428. return FALSE;
  429. // Write Number of Entries
  430. Output = (WORD)nNumEntries;
  431. if( ! WriteFile( hFile, &Output, sizeof( WORD ), &dwBytesWritten, NULL ) )
  432. return FALSE;
  433. // Did we write a WORD?
  434. if( dwBytesWritten != sizeof( WORD ) )
  435. return FALSE;
  436. return TRUE;
  437. }
  438. /****************************************************************************
  439. *
  440. * FUNCTION: CalculateImageOffset
  441. *
  442. * PURPOSE: Calculates the file offset for an icon image
  443. *
  444. * PARAMS: LPICONRESOURCE lpIR - pointer to icon resource
  445. * UINT nIndex - which image?
  446. *
  447. * RETURNS: DWORD - the file offset for that image
  448. *
  449. * History:
  450. * July '95 - Created
  451. *
  452. \****************************************************************************/
  453. DWORD CalculateImageOffset( LPICONRESOURCE lpIR, UINT nIndex )
  454. {
  455. DWORD dwSize;
  456. UINT i;
  457. // Calculate the ICO header size
  458. dwSize = 3 * sizeof(WORD);
  459. // Add the ICONDIRENTRY's
  460. dwSize += lpIR->nNumImages * sizeof(ICONDIRENTRY);
  461. // Add the sizes of the previous images
  462. for(i=0;i<nIndex;i++)
  463. dwSize += lpIR->IconImages[i].dwNumBytes;
  464. // we're there - return the number
  465. return dwSize;
  466. }
  467. /****************************************************************************
  468. *
  469. * FUNCTION: WriteIconToICOFile
  470. *
  471. * PURPOSE: Writes the icon resource data to an ICO file
  472. *
  473. * PARAMS: LPICONRESOURCE lpIR - pointer to icon resource
  474. * PCWSTR szFileName - name for the ICO file
  475. *
  476. * RETURNS: BOOL - TRUE for success, FALSE for failure
  477. *
  478. * History:
  479. * July '95 - Created
  480. *
  481. \****************************************************************************/
  482. BOOL WriteIconToICOFile( LPICONRESOURCE lpIR, PCWSTR szFileName )
  483. {
  484. HANDLE hFile;
  485. UINT i;
  486. DWORD dwBytesWritten;
  487. // open the file
  488. if( (hFile = CreateFile( szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE )
  489. {
  490. MessageBox( NULL, L"Error Opening File for Writing", szFileName, MB_OK );
  491. return FALSE;
  492. }
  493. // Write the header
  494. if( ! WriteICOHeader( hFile, lpIR->nNumImages ) )
  495. {
  496. MessageBox( NULL, L"Error Writing ICO File", szFileName, MB_OK );
  497. CloseHandle( hFile );
  498. return FALSE;
  499. }
  500. // Write the ICONDIRENTRY's
  501. for( i=0; i<lpIR->nNumImages; i++ )
  502. {
  503. ICONDIRENTRY ide;
  504. // Convert internal format to ICONDIRENTRY
  505. ide.bWidth = (BYTE)lpIR->IconImages[i].Width;
  506. ide.bHeight = (BYTE)lpIR->IconImages[i].Height;
  507. ide.bReserved = 0;
  508. ide.wPlanes = lpIR->IconImages[i].lpbi->bmiHeader.biPlanes;
  509. ide.wBitCount = lpIR->IconImages[i].lpbi->bmiHeader.biBitCount;
  510. if( (ide.wPlanes * ide.wBitCount) >= 8 )
  511. ide.bColorCount = 0;
  512. else
  513. ide.bColorCount = 1 << (ide.wPlanes * ide.wBitCount);
  514. ide.dwBytesInRes = lpIR->IconImages[i].dwNumBytes;
  515. ide.dwImageOffset = CalculateImageOffset( lpIR, i );
  516. // Write the ICONDIRENTRY out to disk
  517. if( ! WriteFile( hFile, &ide, sizeof( ICONDIRENTRY ), &dwBytesWritten, NULL ) )
  518. return FALSE;
  519. // Did we write a full ICONDIRENTRY ?
  520. if( dwBytesWritten != sizeof( ICONDIRENTRY ) )
  521. return FALSE;
  522. }
  523. // Write the image bits for each image
  524. for( i=0; i<lpIR->nNumImages; i++ )
  525. {
  526. DWORD dwTemp = lpIR->IconImages[i].lpbi->bmiHeader.biSizeImage;
  527. // Set the sizeimage member to zero
  528. lpIR->IconImages[i].lpbi->bmiHeader.biSizeImage = 0;
  529. // Write the image bits to file
  530. if( ! WriteFile( hFile, lpIR->IconImages[i].lpBits, lpIR->IconImages[i].dwNumBytes, &dwBytesWritten, NULL ) )
  531. return FALSE;
  532. if( dwBytesWritten != lpIR->IconImages[i].dwNumBytes )
  533. return FALSE;
  534. // set it back
  535. lpIR->IconImages[i].lpbi->bmiHeader.biSizeImage = dwTemp;
  536. }
  537. CloseHandle( hFile );
  538. return FALSE;
  539. }