|
|
1.1 root 1: /****************************************************************************/
2: /* */
3: /* Microsoft Confidential */
4: /* */
5: /* Copyright (c) Microsoft Corp. 1987, 1991 */
6: /* All Rights Reserved */
7: /* */
8: /****************************************************************************/
9: /****************************** Module Header *******************************
10: * Module Name: rwicocur.c
11: *
12: * Routines to read and write icon and cursor files.
13: *
14: * History:
15: *
16: ****************************************************************************/
17:
18: #include "imagedit.h"
19:
20: #include <io.h>
21: #include <fcntl.h> // For NT fstat().
22: #include <sys\types.h> // For fstat() types.
23: #include <sys\stat.h> // For fstat() function.
24:
25:
26:
27: /************************************************************************
28: * LoadIconCursorFile
29: *
30: * Loads the specified icon or cursor file. It reads the images into
31: * a list, then prompts for which one to open initially.
32: *
33: * Arguments:
34: *
35: * History:
36: *
37: ************************************************************************/
38:
39: BOOL LoadIconCursorFile(
40: PSTR pszFullFileName,
41: BOOL fIcon)
42: {
43: HFILE hf;
44: INT i;
45: PIMAGEINFO pImage;
46: LPBITMAPINFO lpBitmapInfo;
47: HANDLE hDIB; // Handle to DIB bits.
48: OFSTRUCT OfStruct;
49: struct stat FileStatus;
50: ICOCURSORHDR hdr; // Header structure of icon/cursor file.
51: INT nImages;
52: PICOCURSORDESC aIcoCurDesc; // Array of ico/cur descriptors.
53: DWORD dwFilePos;
54: DWORD dwFileSize;
55: INT iType;
56:
57: if ((hf = (HFILE)OpenFile(pszFullFileName, (LPOFSTRUCT)&OfStruct, OF_READ))
58: == (HFILE)-1) {
59: Message(MSG_CANTOPEN, pszFullFileName);
60: return FALSE;
61: }
62:
63: fstat((INT)_open_osfhandle((long)(hf), (int)(O_RDONLY)), &FileStatus);
64: dwFileSize = (DWORD)FileStatus.st_size;
65:
66: ImageLinkFreeList();
67:
68: if (fIcon)
69: iType = FT_ICON;
70: else
71: iType = FT_CURSOR;
72:
73: /*
74: * Read the Icon/Cursor File header.
75: */
76: if (!MyFileRead(hf, (LPSTR)&hdr, sizeof(ICOCURSORHDR),
77: pszFullFileName, iType))
78: goto Error1;
79:
80: if (hdr.iReserved != 0) {
81: Message(MSG_BADICOCURFILE, pszFullFileName);
82: goto Error1;
83: }
84:
85: /*
86: * Get number of images in the file.
87: */
88: nImages = hdr.iResourceCount;
89:
90: if (!nImages || nImages > MAXIMAGES) {
91: Message(MSG_BADICOCURFILE, pszFullFileName);
92: goto Error1;
93: }
94:
95: if (hdr.iResourceType != 1 && hdr.iResourceType != 2) {
96: Message(MSG_BADICOCURFILE, pszFullFileName);
97: goto Error1;
98: }
99:
100: /*
101: * Allocate room for the descriptor records.
102: */
103: if (!(aIcoCurDesc = (PICOCURSORDESC)MyAlloc(
104: sizeof(ICOCURSORDESC) * nImages)))
105: goto Error1;
106:
107: /*
108: * Read in the descriptor records.
109: */
110: if (!MyFileRead(hf, (LPSTR)aIcoCurDesc, sizeof(ICOCURSORDESC) * nImages,
111: pszFullFileName, iType))
112: goto Error2;
113:
114: /*
115: * Get the current file position (after the descriptors). This
116: * should be the start of the DIB's.
117: */
118: dwFilePos = (DWORD)SetFilePointer((HANDLE)hf, 0, NULL, (DWORD)1);
119:
120: /*
121: * Validate the descriptor records.
122: */
123: for (i = 0; i < nImages; i++) {
124: /*
125: * Make sure the DIB's are sequential (not overlapping)
126: * and they all fit within the file.
127: */
128: if (aIcoCurDesc[i].DIBOffset != dwFilePos ||
129: dwFilePos + aIcoCurDesc[i].DIBSize > dwFileSize) {
130: Message(MSG_BADICOCURFILE, pszFullFileName);
131: goto Error2;
132: }
133:
134: /*
135: * Jump to the next DIB.
136: */
137: dwFilePos += aIcoCurDesc[i].DIBSize;
138: }
139:
140: for (i = 0; i < nImages; i++) {
141: pImage = ImageLinkAlloc(NULL, 0, 0,
142: aIcoCurDesc[i].iHotspotX, aIcoCurDesc[i].iHotspotY,
143: (aIcoCurDesc[i].iColorCount == (BYTE)8) ?
144: aIcoCurDesc[i].iColorCount : 0);
145:
146: if (!pImage)
147: goto Error3;
148:
149: /*
150: * Allocate space for the DIB for this image.
151: */
152: if (!(hDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
153: (DWORD)aIcoCurDesc[i].DIBSize))) {
154: Message(MSG_OUTOFMEMORY);
155: goto Error3;
156: }
157:
158: pImage->DIBSize = aIcoCurDesc[i].DIBSize;
159: pImage->DIBhandle = hDIB;
160: pImage->DIBPtr = (LPSTR)GlobalLock(hDIB);
161: }
162:
163: for (pImage = gpImageHead; pImage != NULL; pImage = pImage->pImageNext) {
164: if (!MyFileRead(hf, pImage->DIBPtr, (DWORD)pImage->DIBSize,
165: pszFullFileName, iType))
166: goto Error3;
167:
168: lpBitmapInfo = (LPBITMAPINFO)pImage->DIBPtr;
169:
170: if (!IsValidDIB(lpBitmapInfo, pImage->DIBSize, TRUE)) {
171: Message(MSG_BADICOCURFILE, pszFullFileName);
172: goto Error3;
173: }
174:
175: /*
176: * Fill the x and y size fields in image node from
177: * information in the DIB header.
178: */
179: pImage->cx = (INT)lpBitmapInfo->bmiHeader.biWidth;
180: pImage->cy = (INT)lpBitmapInfo->bmiHeader.biHeight / 2;
181: if (pImage->nColors == 0)
182: pImage->nColors = (1 << lpBitmapInfo->bmiHeader.biBitCount);
183:
184: pImage->pDevice = DeviceLinkFind(
185: fIcon ? gpIconDeviceHead : gpCursorDeviceHead,
186: pImage->nColors, pImage->cx, pImage->cy);
187: }
188:
189: _lclose((HFILE)hf);
190:
191: fFileDirty = FALSE;
192: SetFileName(pszFullFileName);
193: giType = iType;
194:
195: gnImages = nImages;
196:
197: /*
198: * Update the PropBar and the Toolbox so that they show
199: * information about the opened file. We do this now just
200: * in case the user cancels out of the Image Select Dialog.
201: */
202: PropBarUpdate();
203: ToolboxUpdate();
204:
205: /*
206: * Open up an image. If there are multiple images in the file,
207: * show the Image Select dialog. We also show the Image Select
208: * dialog if the file only has one image but it is not for a known
209: * device.
210: */
211: if (gnImages > 1 || !gpImageHead->pDevice)
212: ImageSelectDialog();
213: else
214: ImageOpen2(gpImageHead);
215:
216: return TRUE;
217:
218: Error3:
219: ImageLinkFreeList();
220:
221: Error2:
222: MyFree(aIcoCurDesc);
223:
224: Error1:
225: _lclose((HFILE)hf);
226:
227: return FALSE;
228: }
229:
230:
231:
232: /************************************************************************
233: * IsValidDIB
234: *
235: * This function determines if the given DIB is valid or not. It does
236: * this without touching memory outside the bounds of the cbDIBSize
237: * passed in or the size of a BITMAPINFOHEADER, whichever is smaller.
238: * Note that even if the DIB is valid, however, the current image
239: * editor might not be able to edit it (the size might be too big, for
240: * instance).
241: *
242: * Arguments:
243: * LPBITMAPINFO pDIB - Points to the DIB.
244: * DWORD cbDIBSize - The size of the DIB.
245: * BOOL fIcoCur - TRUE if this is an icon or cursor. This effects
246: * whether an AND mask is expected to be in the DIB.
247: *
248: * History:
249: *
250: ************************************************************************/
251:
252: BOOL IsValidDIB(
253: LPBITMAPINFO pDIB,
254: DWORD cbDIBSize,
255: BOOL fIcoCur)
256: {
257: DWORD cbANDMask;
258: DWORD cbXORMask;
259: DWORD cbColorTable;
260: DWORD nHeight;
261:
262: if (cbDIBSize < sizeof(BITMAPINFOHEADER))
263: return FALSE;
264:
265: if (pDIB->bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
266: return FALSE;
267:
268: if (pDIB->bmiHeader.biPlanes != 1)
269: return FALSE;
270:
271: if (pDIB->bmiHeader.biBitCount != 1 &&
272: pDIB->bmiHeader.biBitCount != 4 &&
273: pDIB->bmiHeader.biBitCount != 8 &&
274: pDIB->bmiHeader.biBitCount != 24)
275: return FALSE;
276:
277: if (fIcoCur) {
278: nHeight = pDIB->bmiHeader.biHeight / 2;
279: cbANDMask = (((pDIB->bmiHeader.biWidth + 31) & 0xffffffe0) >> 3) *
280: nHeight;
281: }
282: else {
283: nHeight = pDIB->bmiHeader.biHeight;
284: cbANDMask = 0;
285: }
286:
287: cbColorTable = (1 << pDIB->bmiHeader.biBitCount) * sizeof(RGBQUAD);
288: cbXORMask = ((((pDIB->bmiHeader.biWidth * pDIB->bmiHeader.biBitCount) +
289: 31) & 0xffffffe0) >> 3) * nHeight;
290:
291: /*
292: * Check the size field in the header. This must be either zero
293: * or a valid size.
294: */
295: if (pDIB->bmiHeader.biSizeImage &&
296: pDIB->bmiHeader.biSizeImage != cbXORMask + cbANDMask)
297: return FALSE;
298:
299: if (cbDIBSize != sizeof(BITMAPINFOHEADER) + cbColorTable +
300: cbXORMask + cbANDMask)
301: return FALSE;
302:
303: return TRUE;
304: }
305:
306:
307:
308: /************************************************************************
309: * SaveIconCursorFile
310: *
311: *
312: *
313: * Arguments:
314: *
315: * Returns:
316: * TRUE if successful, FALSE otherwise.
317: *
318: * History:
319: *
320: ************************************************************************/
321:
322: BOOL SaveIconCursorFile(
323: PSTR pszFullFileName,
324: INT iType)
325: {
326: ICOCURSORHDR IcoCurHdr; // Header structure of icon/cursor file.
327: ICOCURSORDESC IcoCurDesc; // Icon/cursor descriptor struct.
328: HCURSOR hcurOld; // Handle to old cursor.
329: PIMAGEINFO pImage; // Pointer to node in image list.
330: DWORD iBitsOffset; // Offset of the actual DIB bits for image.
331: HFILE hf;
332: OFSTRUCT OfStruct;
333:
334: hcurOld = SetCursor(hcurWait);
335:
336: /*
337: * Save the bits of the current image.
338: */
339: ImageSave();
340:
341: /*
342: * Open the file for writing.
343: */
344: if ((hf = (HFILE)OpenFile(pszFullFileName, &OfStruct, OF_CREATE | OF_READWRITE))
345: == (HFILE)-1) {
346: Message(MSG_CANTCREATE, pszFullFileName);
347: goto Error1;
348: }
349:
350: /*
351: * This is crucial since this helps distinguish a 3.0 icon/cursor
352: * from an old, old (2.1 format) icon/cursor, which has meaningful
353: * information in this WORD.
354: */
355: IcoCurHdr.iReserved = (WORD)0;
356:
357: if (iType == FT_ICON)
358: IcoCurHdr.iResourceType = 1; // Icon type.
359: else
360: IcoCurHdr.iResourceType = 2; // Cursor type.
361:
362: IcoCurHdr.iResourceCount = (WORD)gnImages;
363:
364: /*
365: * Write the header to disk.
366: */
367: if (!MyFileWrite(hf, (LPSTR)&IcoCurHdr, sizeof(ICOCURSORHDR),
368: pszFullFileName))
369: goto Error2;
370:
371: /*
372: * Write all the descriptors.
373: */
374: iBitsOffset = sizeof(ICOCURSORHDR) + (gnImages * sizeof(ICOCURSORDESC));
375: for (pImage = gpImageHead; pImage; pImage = pImage->pImageNext) {
376: IcoCurDesc.iWidth = (BYTE)pImage->cx;
377: IcoCurDesc.iHeight = (BYTE)pImage->cy;
378: IcoCurDesc.iColorCount = (giType == FT_ICON) ?
379: (BYTE)pImage->nColors : (BYTE)0;
380: IcoCurDesc.iUnused = 0;
381: IcoCurDesc.iHotspotX = (WORD)pImage->iHotspotX;
382: IcoCurDesc.iHotspotY = (WORD)pImage->iHotspotY;
383: IcoCurDesc.DIBSize = pImage->DIBSize;
384: IcoCurDesc.DIBOffset = iBitsOffset;
385:
386: if (!MyFileWrite(hf, (LPSTR)&IcoCurDesc, sizeof(ICOCURSORDESC),
387: pszFullFileName))
388: goto Error2;
389:
390: iBitsOffset += IcoCurDesc.DIBSize;
391: }
392:
393: /*
394: * Now write the DIB's.
395: */
396: for (pImage = gpImageHead; pImage; pImage = pImage->pImageNext) {
397: if (!MyFileWrite(hf, (LPSTR)pImage->DIBPtr,
398: (DWORD)pImage->DIBSize, pszFullFileName))
399: goto Error2;
400: }
401:
402: _lclose((HFILE)hf);
403:
404: fFileDirty = FALSE;
405: SetFileName(pszFullFileName);
406:
407: SetCursor(hcurOld);
408:
409: return TRUE;
410:
411: Error2:
412: _lclose((HFILE)hf);
413:
414: Error1:
415: SetCursor(hcurOld);
416:
417: return FALSE;
418: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.