1*c2c66affSColin Finck /*
2*c2c66affSColin Finck * Program Manager
3*c2c66affSColin Finck *
4*c2c66affSColin Finck * Copyright 1996 Ulrich Schmid
5*c2c66affSColin Finck * 1997 Peter Schlaile
6*c2c66affSColin Finck *
7*c2c66affSColin Finck * This library is free software; you can redistribute it and/or
8*c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
9*c2c66affSColin Finck * License as published by the Free Software Foundation; either
10*c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
11*c2c66affSColin Finck *
12*c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
13*c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15*c2c66affSColin Finck * Lesser General Public License for more details.
16*c2c66affSColin Finck *
17*c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
18*c2c66affSColin Finck * License along with this library; if not, write to the Free Software
19*c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20*c2c66affSColin Finck */
21*c2c66affSColin Finck
22*c2c66affSColin Finck #include "progman.h"
23*c2c66affSColin Finck
24*c2c66affSColin Finck #if 0
25*c2c66affSColin Finck #define MALLOCHUNK 1000
26*c2c66affSColin Finck
27*c2c66affSColin Finck #define GET_USHORT(buffer, i)\
28*c2c66affSColin Finck (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
29*c2c66affSColin Finck #define GET_SHORT(buffer, i)\
30*c2c66affSColin Finck (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
31*c2c66affSColin Finck #define PUT_SHORT(buffer, i, s)\
32*c2c66affSColin Finck (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
33*c2c66affSColin Finck
34*c2c66affSColin Finck static BOOL GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*);
35*c2c66affSColin Finck static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL);
36*c2c66affSColin Finck static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT,
37*c2c66affSColin Finck LPCSTR, HLOCAL,LPCSTR);
38*c2c66affSColin Finck static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group);
39*c2c66affSColin Finck #endif
40*c2c66affSColin Finck
41*c2c66affSColin Finck /***********************************************************************
42*c2c66affSColin Finck *
43*c2c66affSColin Finck * GRPFILE_ModifyFileName
44*c2c66affSColin Finck *
45*c2c66affSColin Finck * Change extension `.grp' to `.gr'
46*c2c66affSColin Finck */
47*c2c66affSColin Finck
48*c2c66affSColin Finck #if 0
49*c2c66affSColin Finck static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
50*c2c66affSColin Finck INT nSize, BOOL bModify)
51*c2c66affSColin Finck {
52*c2c66affSColin Finck lstrcpynA(lpszNewName, lpszOrigName, nSize);
53*c2c66affSColin Finck lpszNewName[nSize-1] = '\0';
54*c2c66affSColin Finck if (!bModify) return;
55*c2c66affSColin Finck if (!lstrcmpiA(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
56*c2c66affSColin Finck lpszNewName[strlen(lpszNewName) - 1] = '\0';
57*c2c66affSColin Finck }
58*c2c66affSColin Finck #endif
59*c2c66affSColin Finck
60*c2c66affSColin Finck /***********************************************************************
61*c2c66affSColin Finck *
62*c2c66affSColin Finck * GRPFILE_ReadGroupFile
63*c2c66affSColin Finck */
64*c2c66affSColin Finck
GRPFILE_ReadGroupFile(LPCWSTR lpszPath,BOOL bIsCommonGroup)65*c2c66affSColin Finck DWORD GRPFILE_ReadGroupFile(LPCWSTR lpszPath, BOOL bIsCommonGroup)
66*c2c66affSColin Finck {
67*c2c66affSColin Finck #if 0
68*c2c66affSColin Finck CHAR szPath_gr[MAX_PATHNAME_LEN];
69*c2c66affSColin Finck BOOL bFileNameModified = FALSE;
70*c2c66affSColin Finck OFSTRUCT dummy;
71*c2c66affSColin Finck HLOCAL hBuffer, hGroup;
72*c2c66affSColin Finck INT size;
73*c2c66affSColin Finck
74*c2c66affSColin Finck /* if `.gr' file exists use that */
75*c2c66affSColin Finck GRPFILE_ModifyFileName(szPath_gr, lpszPath, MAX_PATHNAME_LEN, TRUE);
76*c2c66affSColin Finck if (OpenFile(szPath_gr, &dummy, OF_EXIST) != HFILE_ERROR)
77*c2c66affSColin Finck {
78*c2c66affSColin Finck lpszPath = szPath_gr;
79*c2c66affSColin Finck bFileNameModified = TRUE;
80*c2c66affSColin Finck }
81*c2c66affSColin Finck
82*c2c66affSColin Finck /* Read the whole file into a buffer */
83*c2c66affSColin Finck if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
84*c2c66affSColin Finck {
85*c2c66affSColin Finck MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
86*c2c66affSColin Finck return(0);
87*c2c66affSColin Finck }
88*c2c66affSColin Finck
89*c2c66affSColin Finck /* Interpret buffer */
90*c2c66affSColin Finck hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
91*c2c66affSColin Finck lpszPath, bFileNameModified);
92*c2c66affSColin Finck if (!hGroup)
93*c2c66affSColin Finck MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
94*c2c66affSColin Finck
95*c2c66affSColin Finck LocalFree(hBuffer);
96*c2c66affSColin Finck
97*c2c66affSColin Finck return(hGroup);
98*c2c66affSColin Finck
99*c2c66affSColin Finck #else
100*c2c66affSColin Finck return ERROR_SUCCESS;
101*c2c66affSColin Finck #endif
102*c2c66affSColin Finck }
103*c2c66affSColin Finck
104*c2c66affSColin Finck /***********************************************************************
105*c2c66affSColin Finck *
106*c2c66affSColin Finck * GRPFILE_ReadFileToBuffer
107*c2c66affSColin Finck */
108*c2c66affSColin Finck
109*c2c66affSColin Finck #if 0
110*c2c66affSColin Finck static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
111*c2c66affSColin Finck INT *piSize)
112*c2c66affSColin Finck {
113*c2c66affSColin Finck UINT len, size;
114*c2c66affSColin Finck LPSTR buffer;
115*c2c66affSColin Finck HLOCAL hBuffer, hNewBuffer;
116*c2c66affSColin Finck HFILE file;
117*c2c66affSColin Finck
118*c2c66affSColin Finck file=_lopen(path, OF_READ);
119*c2c66affSColin Finck if (file == HFILE_ERROR) return FALSE;
120*c2c66affSColin Finck
121*c2c66affSColin Finck size = 0;
122*c2c66affSColin Finck hBuffer = LocalAlloc(LMEM_FIXED, MALLOCHUNK + 1);
123*c2c66affSColin Finck if (!hBuffer) return FALSE;
124*c2c66affSColin Finck buffer = LocalLock(hBuffer);
125*c2c66affSColin Finck
126*c2c66affSColin Finck while ((len = _lread(file, buffer + size, MALLOCHUNK))
127*c2c66affSColin Finck == MALLOCHUNK)
128*c2c66affSColin Finck {
129*c2c66affSColin Finck size += len;
130*c2c66affSColin Finck hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
131*c2c66affSColin Finck LMEM_MOVEABLE);
132*c2c66affSColin Finck if (!hNewBuffer)
133*c2c66affSColin Finck {
134*c2c66affSColin Finck LocalFree(hBuffer);
135*c2c66affSColin Finck return FALSE;
136*c2c66affSColin Finck }
137*c2c66affSColin Finck hBuffer = hNewBuffer;
138*c2c66affSColin Finck buffer = LocalLock(hBuffer);
139*c2c66affSColin Finck }
140*c2c66affSColin Finck
141*c2c66affSColin Finck _lclose(file);
142*c2c66affSColin Finck
143*c2c66affSColin Finck if (len == (UINT)HFILE_ERROR)
144*c2c66affSColin Finck {
145*c2c66affSColin Finck LocalFree(hBuffer);
146*c2c66affSColin Finck return FALSE;
147*c2c66affSColin Finck }
148*c2c66affSColin Finck
149*c2c66affSColin Finck size += len;
150*c2c66affSColin Finck buffer[size] = 0;
151*c2c66affSColin Finck
152*c2c66affSColin Finck *phBuffer = hBuffer;
153*c2c66affSColin Finck *piSize = size;
154*c2c66affSColin Finck return TRUE;
155*c2c66affSColin Finck }
156*c2c66affSColin Finck #endif
157*c2c66affSColin Finck
158*c2c66affSColin Finck /***********************************************************************
159*c2c66affSColin Finck * GRPFILE_ScanGroup
160*c2c66affSColin Finck */
161*c2c66affSColin Finck
162*c2c66affSColin Finck #if 0
163*c2c66affSColin Finck static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
164*c2c66affSColin Finck LPCSTR lpszGrpFile,
165*c2c66affSColin Finck BOOL bModifiedFileName)
166*c2c66affSColin Finck {
167*c2c66affSColin Finck HLOCAL hGroup;
168*c2c66affSColin Finck INT i, seqnum;
169*c2c66affSColin Finck LPCSTR extension;
170*c2c66affSColin Finck LPCSTR lpszName;
171*c2c66affSColin Finck INT x, y, width, height, iconx, icony, nCmdShow;
172*c2c66affSColin Finck INT number_of_programs;
173*c2c66affSColin Finck BOOL bOverwriteFileOk;
174*c2c66affSColin Finck
175*c2c66affSColin Finck if (buffer[0] != 'P' || buffer[1] != 'M') return(0);
176*c2c66affSColin Finck if (buffer[2] == 'C' && buffer[3] == 'C')
177*c2c66affSColin Finck /* original with checksum */
178*c2c66affSColin Finck bOverwriteFileOk = FALSE;
179*c2c66affSColin Finck else if (buffer[2] == 'X' && buffer[3] == 'X')
180*c2c66affSColin Finck /* modified without checksum */
181*c2c66affSColin Finck bOverwriteFileOk = TRUE;
182*c2c66affSColin Finck else return(0);
183*c2c66affSColin Finck
184*c2c66affSColin Finck /* checksum = GET_USHORT(buffer, 4) (ignored) */
185*c2c66affSColin Finck
186*c2c66affSColin Finck extension = buffer + GET_USHORT(buffer, 6);
187*c2c66affSColin Finck if (extension == buffer + size) extension = 0;
188*c2c66affSColin Finck else if (extension + 6 > buffer + size) return(0);
189*c2c66affSColin Finck
190*c2c66affSColin Finck nCmdShow = GET_USHORT(buffer, 8);
191*c2c66affSColin Finck x = GET_SHORT(buffer, 10);
192*c2c66affSColin Finck y = GET_SHORT(buffer, 12);
193*c2c66affSColin Finck width = GET_USHORT(buffer, 14);
194*c2c66affSColin Finck height = GET_USHORT(buffer, 16);
195*c2c66affSColin Finck iconx = GET_SHORT(buffer, 18);
196*c2c66affSColin Finck icony = GET_SHORT(buffer, 20);
197*c2c66affSColin Finck lpszName = buffer + GET_USHORT(buffer, 22);
198*c2c66affSColin Finck if (lpszName >= buffer + size) return(0);
199*c2c66affSColin Finck
200*c2c66affSColin Finck /* unknown bytes 24 - 31 ignored */
201*c2c66affSColin Finck /*
202*c2c66affSColin Finck Unknown bytes should be:
203*c2c66affSColin Finck wLogPixelsX = GET_SHORT(buffer, 24);
204*c2c66affSColin Finck wLogPixelsY = GET_SHORT(buffer, 26);
205*c2c66affSColin Finck byBitsPerPixel = byte at 28;
206*c2c66affSColin Finck byPlanes = byte at 29;
207*c2c66affSColin Finck wReserved = GET_SHORT(buffer, 30);
208*c2c66affSColin Finck */
209*c2c66affSColin Finck
210*c2c66affSColin Finck hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
211*c2c66affSColin Finck width, height, iconx, icony,
212*c2c66affSColin Finck bModifiedFileName, bOverwriteFileOk,
213*c2c66affSColin Finck TRUE);
214*c2c66affSColin Finck if (!hGroup) return(0);
215*c2c66affSColin Finck
216*c2c66affSColin Finck number_of_programs = GET_USHORT(buffer, 32);
217*c2c66affSColin Finck if (2 * number_of_programs + 34 > size) return(0);
218*c2c66affSColin Finck for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++)
219*c2c66affSColin Finck {
220*c2c66affSColin Finck LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i);
221*c2c66affSColin Finck if (program_ptr + 24 > buffer + size) return(0);
222*c2c66affSColin Finck if (!GET_USHORT(buffer, 34 + 2*i)) continue;
223*c2c66affSColin Finck if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum,
224*c2c66affSColin Finck extension, hGroup, lpszGrpFile))
225*c2c66affSColin Finck {
226*c2c66affSColin Finck GROUP_DeleteGroup(hGroup);
227*c2c66affSColin Finck return(0);
228*c2c66affSColin Finck }
229*c2c66affSColin Finck }
230*c2c66affSColin Finck
231*c2c66affSColin Finck /* FIXME shouldn't be necessary */
232*c2c66affSColin Finck GROUP_ShowGroupWindow(hGroup);
233*c2c66affSColin Finck
234*c2c66affSColin Finck return hGroup;
235*c2c66affSColin Finck }
236*c2c66affSColin Finck #endif
237*c2c66affSColin Finck
238*c2c66affSColin Finck /***********************************************************************
239*c2c66affSColin Finck * GRPFILE_ScanProgram
240*c2c66affSColin Finck */
241*c2c66affSColin Finck
242*c2c66affSColin Finck #if 0
243*c2c66affSColin Finck static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
244*c2c66affSColin Finck LPCSTR program_ptr, INT seqnum,
245*c2c66affSColin Finck LPCSTR extension, HLOCAL hGroup,
246*c2c66affSColin Finck LPCSTR lpszGrpFile)
247*c2c66affSColin Finck {
248*c2c66affSColin Finck INT icontype;
249*c2c66affSColin Finck HICON hIcon;
250*c2c66affSColin Finck LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir;
251*c2c66affSColin Finck LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr;
252*c2c66affSColin Finck INT x, y, nIconIndex, iconANDsize, iconXORsize;
253*c2c66affSColin Finck INT nHotKey, nCmdShow;
254*c2c66affSColin Finck UINT width, height, planes, bpp;
255*c2c66affSColin Finck
256*c2c66affSColin Finck x = GET_SHORT(program_ptr, 0);
257*c2c66affSColin Finck y = GET_SHORT(program_ptr, 2);
258*c2c66affSColin Finck nIconIndex = GET_USHORT(program_ptr, 4);
259*c2c66affSColin Finck
260*c2c66affSColin Finck /* FIXME is this correct ?? */
261*c2c66affSColin Finck icontype = GET_USHORT(program_ptr, 6);
262*c2c66affSColin Finck switch (icontype)
263*c2c66affSColin Finck {
264*c2c66affSColin Finck default:
265*c2c66affSColin Finck MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
266*c2c66affSColin Finck IDS_WARNING, MB_OK);
267*c2c66affSColin Finck case 0x048c:
268*c2c66affSColin Finck iconXORsize = GET_USHORT(program_ptr, 8);
269*c2c66affSColin Finck iconANDsize = GET_USHORT(program_ptr, 10) / 8;
270*c2c66affSColin Finck iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
271*c2c66affSColin Finck iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14);
272*c2c66affSColin Finck iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 16);
273*c2c66affSColin Finck width = GET_USHORT(iconinfo_ptr, 4);
274*c2c66affSColin Finck height = GET_USHORT(iconinfo_ptr, 6);
275*c2c66affSColin Finck planes = GET_USHORT(iconinfo_ptr, 10);
276*c2c66affSColin Finck bpp = GET_USHORT(iconinfo_ptr, 11);
277*c2c66affSColin Finck break;
278*c2c66affSColin Finck case 0x000c:
279*c2c66affSColin Finck iconANDsize = GET_USHORT(program_ptr, 8);
280*c2c66affSColin Finck iconXORsize = GET_USHORT(program_ptr, 10);
281*c2c66affSColin Finck iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
282*c2c66affSColin Finck iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14);
283*c2c66affSColin Finck iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16);
284*c2c66affSColin Finck width = GET_USHORT(iconinfo_ptr, 4);
285*c2c66affSColin Finck height = GET_USHORT(iconinfo_ptr, 6);
286*c2c66affSColin Finck planes = GET_USHORT(iconinfo_ptr, 10);
287*c2c66affSColin Finck bpp = GET_USHORT(iconinfo_ptr, 11);
288*c2c66affSColin Finck }
289*c2c66affSColin Finck
290*c2c66affSColin Finck if (iconANDbits_ptr + iconANDsize > buffer + size ||
291*c2c66affSColin Finck iconXORbits_ptr + iconXORsize > buffer + size) return(0);
292*c2c66affSColin Finck
293*c2c66affSColin Finck hIcon = CreateIcon(Globals.hInstance, width, height, planes, bpp, (PBYTE)iconANDbits_ptr, (PBYTE)iconXORbits_ptr);
294*c2c66affSColin Finck
295*c2c66affSColin Finck lpszName = buffer + GET_USHORT(program_ptr, 18);
296*c2c66affSColin Finck lpszCmdLine = buffer + GET_USHORT(program_ptr, 20);
297*c2c66affSColin Finck lpszIconFile = buffer + GET_USHORT(program_ptr, 22);
298*c2c66affSColin Finck if (iconinfo_ptr + 6 > buffer + size ||
299*c2c66affSColin Finck lpszName > buffer + size ||
300*c2c66affSColin Finck lpszCmdLine > buffer + size ||
301*c2c66affSColin Finck lpszIconFile > buffer + size) return(0);
302*c2c66affSColin Finck
303*c2c66affSColin Finck /* Scan Extensions */
304*c2c66affSColin Finck lpszWorkDir = "";
305*c2c66affSColin Finck nHotKey = 0;
306*c2c66affSColin Finck nCmdShow = SW_SHOWNORMAL;
307*c2c66affSColin Finck if (extension)
308*c2c66affSColin Finck {
309*c2c66affSColin Finck LPCSTR ptr = extension;
310*c2c66affSColin Finck while (ptr + 6 <= buffer + size)
311*c2c66affSColin Finck {
312*c2c66affSColin Finck UINT type = GET_USHORT(ptr, 0);
313*c2c66affSColin Finck UINT number = GET_USHORT(ptr, 2);
314*c2c66affSColin Finck UINT skip = GET_USHORT(ptr, 4);
315*c2c66affSColin Finck
316*c2c66affSColin Finck if (number == seqnum)
317*c2c66affSColin Finck {
318*c2c66affSColin Finck switch (type)
319*c2c66affSColin Finck {
320*c2c66affSColin Finck case 0x8000:
321*c2c66affSColin Finck if (ptr + 10 > buffer + size) return(0);
322*c2c66affSColin Finck if (ptr[6] != 'P' || ptr[7] != 'M' ||
323*c2c66affSColin Finck ptr[8] != 'C' || ptr[9] != 'C') return(0);
324*c2c66affSColin Finck break;
325*c2c66affSColin Finck case 0x8101:
326*c2c66affSColin Finck lpszWorkDir = ptr + 6;
327*c2c66affSColin Finck break;
328*c2c66affSColin Finck case 0x8102:
329*c2c66affSColin Finck if (ptr + 8 > buffer + size) return(0);
330*c2c66affSColin Finck nHotKey = GET_USHORT(ptr, 6);
331*c2c66affSColin Finck break;
332*c2c66affSColin Finck case 0x8103:
333*c2c66affSColin Finck if (ptr + 8 > buffer + size) return(0);
334*c2c66affSColin Finck nCmdShow = GET_USHORT(ptr, 6);
335*c2c66affSColin Finck break;
336*c2c66affSColin Finck default:
337*c2c66affSColin Finck MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
338*c2c66affSColin Finck lpszGrpFile, IDS_WARNING, MB_OK);
339*c2c66affSColin Finck }
340*c2c66affSColin Finck }
341*c2c66affSColin Finck if (!skip) break;
342*c2c66affSColin Finck ptr += skip;
343*c2c66affSColin Finck }
344*c2c66affSColin Finck }
345*c2c66affSColin Finck
346*c2c66affSColin Finck return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
347*c2c66affSColin Finck lpszCmdLine, lpszIconFile,
348*c2c66affSColin Finck nIconIndex, lpszWorkDir,
349*c2c66affSColin Finck nHotKey, nCmdShow));
350*c2c66affSColin Finck }
351*c2c66affSColin Finck #endif
352*c2c66affSColin Finck
353*c2c66affSColin Finck /***********************************************************************
354*c2c66affSColin Finck *
355*c2c66affSColin Finck * GRPFILE_WriteGroupFile
356*c2c66affSColin Finck */
357*c2c66affSColin Finck
GRPFILE_WriteGroupFile(PROGGROUP * hGroup)358*c2c66affSColin Finck BOOL GRPFILE_WriteGroupFile(PROGGROUP* hGroup)
359*c2c66affSColin Finck {
360*c2c66affSColin Finck #if 0
361*c2c66affSColin Finck CHAR szPath[MAX_PATHNAME_LEN];
362*c2c66affSColin Finck PROGGROUP *group = LocalLock(hGroup);
363*c2c66affSColin Finck OFSTRUCT dummy;
364*c2c66affSColin Finck HFILE file;
365*c2c66affSColin Finck BOOL ret;
366*c2c66affSColin Finck
367*c2c66affSColin Finck GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
368*c2c66affSColin Finck MAX_PATHNAME_LEN,
369*c2c66affSColin Finck group->bFileNameModified);
370*c2c66affSColin Finck
371*c2c66affSColin Finck /* Try not to overwrite original files */
372*c2c66affSColin Finck
373*c2c66affSColin Finck /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
374*c2c66affSColin Finck if (!group->bOverwriteFileOk &&
375*c2c66affSColin Finck OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
376*c2c66affSColin Finck {
377*c2c66affSColin Finck /* Original file exists, try `.gr' extension */
378*c2c66affSColin Finck GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
379*c2c66affSColin Finck MAX_PATHNAME_LEN, TRUE);
380*c2c66affSColin Finck if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
381*c2c66affSColin Finck {
382*c2c66affSColin Finck /* File exists. Do not overwrite */
383*c2c66affSColin Finck MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
384*c2c66affSColin Finck IDS_INFO, MB_OK);
385*c2c66affSColin Finck return FALSE;
386*c2c66affSColin Finck }
387*c2c66affSColin Finck /* Inform about the modified file name */
388*c2c66affSColin Finck if (IDCANCEL ==
389*c2c66affSColin Finck MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
390*c2c66affSColin Finck MB_OKCANCEL | MB_ICONINFORMATION))
391*c2c66affSColin Finck return FALSE;
392*c2c66affSColin Finck }
393*c2c66affSColin Finck
394*c2c66affSColin Finck {
395*c2c66affSColin Finck /* Warn about the (possible) incompatibility */
396*c2c66affSColin Finck CHAR msg[MAX_PATHNAME_LEN + 200];
397*c2c66affSColin Finck wsprintfA(msg,
398*c2c66affSColin Finck "Group files written by this DRAFT Program Manager "
399*c2c66affSColin Finck "possibly cannot be read by the Microsoft Program Manager!!\n"
400*c2c66affSColin Finck "Are you sure to write %s?", szPath);
401*c2c66affSColin Finck if (IDOK != MessageBoxA(Globals.hMainWnd, msg, "WARNING",
402*c2c66affSColin Finck MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE;
403*c2c66affSColin Finck }
404*c2c66affSColin Finck
405*c2c66affSColin Finck /* Open file */
406*c2c66affSColin Finck file = _lcreat(szPath, 0);
407*c2c66affSColin Finck if (file != HFILE_ERROR)
408*c2c66affSColin Finck {
409*c2c66affSColin Finck ret = GRPFILE_DoWriteGroupFile(file, group);
410*c2c66affSColin Finck _lclose(file);
411*c2c66affSColin Finck }
412*c2c66affSColin Finck else ret = FALSE;
413*c2c66affSColin Finck
414*c2c66affSColin Finck if (!ret)
415*c2c66affSColin Finck MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
416*c2c66affSColin Finck
417*c2c66affSColin Finck return(ret);
418*c2c66affSColin Finck
419*c2c66affSColin Finck #else
420*c2c66affSColin Finck return TRUE;
421*c2c66affSColin Finck #endif
422*c2c66affSColin Finck }
423*c2c66affSColin Finck
424*c2c66affSColin Finck #if 0
425*c2c66affSColin Finck
426*c2c66affSColin Finck /***********************************************************************
427*c2c66affSColin Finck *
428*c2c66affSColin Finck * GRPFILE_CalculateSizes
429*c2c66affSColin Finck */
430*c2c66affSColin Finck
431*c2c66affSColin Finck static VOID GRPFILE_CalculateSizes(PROGRAM *program, INT *Progs, INT *Icons,
432*c2c66affSColin Finck UINT *sizeAnd, UINT *sizeXor)
433*c2c66affSColin Finck {
434*c2c66affSColin Finck ICONINFO info;
435*c2c66affSColin Finck BITMAP bmp;
436*c2c66affSColin Finck
437*c2c66affSColin Finck GetIconInfo( program->hIcon, &info );
438*c2c66affSColin Finck GetObjectW( info.hbmMask, sizeof(bmp), &bmp );
439*c2c66affSColin Finck *sizeAnd = bmp.bmHeight * ((bmp.bmWidth + 15) / 16 * 2);
440*c2c66affSColin Finck GetObjectW( info.hbmColor, sizeof(bmp), &bmp );
441*c2c66affSColin Finck *sizeXor = bmp.bmHeight * bmp.bmWidthBytes;
442*c2c66affSColin Finck DeleteObject( info.hbmMask );
443*c2c66affSColin Finck DeleteObject( info.hbmColor );
444*c2c66affSColin Finck
445*c2c66affSColin Finck *Progs += 24;
446*c2c66affSColin Finck *Progs += strlen(LocalLock(program->hName)) + 1;
447*c2c66affSColin Finck *Progs += strlen(LocalLock(program->hCmdLine)) + 1;
448*c2c66affSColin Finck *Progs += strlen(LocalLock(program->hIconFile)) + 1;
449*c2c66affSColin Finck
450*c2c66affSColin Finck *Icons += 12; /* IconInfo */
451*c2c66affSColin Finck *Icons += *sizeAnd;
452*c2c66affSColin Finck *Icons += *sizeXor;
453*c2c66affSColin Finck }
454*c2c66affSColin Finck
455*c2c66affSColin Finck /***********************************************************************/
456*c2c66affSColin Finck UINT16 GRPFILE_checksum;
457*c2c66affSColin Finck BOOL GRPFILE_checksum_half_word;
458*c2c66affSColin Finck BYTE GRPFILE_checksum_last_byte;
459*c2c66affSColin Finck /***********************************************************************
460*c2c66affSColin Finck *
461*c2c66affSColin Finck * GRPFILE_InitChecksum
462*c2c66affSColin Finck */
463*c2c66affSColin Finck
464*c2c66affSColin Finck static void GRPFILE_InitChecksum(void)
465*c2c66affSColin Finck {
466*c2c66affSColin Finck GRPFILE_checksum = 0;
467*c2c66affSColin Finck GRPFILE_checksum_half_word = 0;
468*c2c66affSColin Finck }
469*c2c66affSColin Finck
470*c2c66affSColin Finck /***********************************************************************
471*c2c66affSColin Finck *
472*c2c66affSColin Finck * GRPFILE_GetChecksum
473*c2c66affSColin Finck */
474*c2c66affSColin Finck
475*c2c66affSColin Finck static UINT16 GRPFILE_GetChecksum(void)
476*c2c66affSColin Finck {
477*c2c66affSColin Finck return GRPFILE_checksum;
478*c2c66affSColin Finck }
479*c2c66affSColin Finck
480*c2c66affSColin Finck /***********************************************************************
481*c2c66affSColin Finck *
482*c2c66affSColin Finck * GRPFILE_WriteWithChecksum
483*c2c66affSColin Finck *
484*c2c66affSColin Finck * Looks crazier than it is:
485*c2c66affSColin Finck *
486*c2c66affSColin Finck * chksum = 0;
487*c2c66affSColin Finck * chksum = cksum - 1. word;
488*c2c66affSColin Finck * chksum = cksum - 2. word;
489*c2c66affSColin Finck * ...
490*c2c66affSColin Finck *
491*c2c66affSColin Finck * if (filelen is even)
492*c2c66affSColin Finck * great I'm finished
493*c2c66affSColin Finck * else
494*c2c66affSColin Finck * ignore last byte
495*c2c66affSColin Finck */
496*c2c66affSColin Finck
497*c2c66affSColin Finck static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
498*c2c66affSColin Finck {
499*c2c66affSColin Finck UINT i;
500*c2c66affSColin Finck if (GRPFILE_checksum_half_word) {
501*c2c66affSColin Finck GRPFILE_checksum -= GRPFILE_checksum_last_byte;
502*c2c66affSColin Finck }
503*c2c66affSColin Finck for (i=0; i < size; i++) {
504*c2c66affSColin Finck if (GRPFILE_checksum_half_word) {
505*c2c66affSColin Finck GRPFILE_checksum -= str[i] << 8;
506*c2c66affSColin Finck } else {
507*c2c66affSColin Finck GRPFILE_checksum -= str[i];
508*c2c66affSColin Finck }
509*c2c66affSColin Finck GRPFILE_checksum_half_word ^= 1;
510*c2c66affSColin Finck }
511*c2c66affSColin Finck
512*c2c66affSColin Finck if (GRPFILE_checksum_half_word) {
513*c2c66affSColin Finck GRPFILE_checksum_last_byte = str[size-1];
514*c2c66affSColin Finck GRPFILE_checksum += GRPFILE_checksum_last_byte;
515*c2c66affSColin Finck }
516*c2c66affSColin Finck
517*c2c66affSColin Finck return _lwrite(file, str, size);
518*c2c66affSColin Finck }
519*c2c66affSColin Finck
520*c2c66affSColin Finck
521*c2c66affSColin Finck /***********************************************************************
522*c2c66affSColin Finck *
523*c2c66affSColin Finck * GRPFILE_DoWriteGroupFile
524*c2c66affSColin Finck */
525*c2c66affSColin Finck
526*c2c66affSColin Finck static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group)
527*c2c66affSColin Finck {
528*c2c66affSColin Finck CHAR buffer[34];
529*c2c66affSColin Finck HLOCAL hProgram;
530*c2c66affSColin Finck INT NumProg, Title, Progs, Icons, Extension;
531*c2c66affSColin Finck INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
532*c2c66affSColin Finck
533*c2c66affSColin Finck UINT sizeAnd, sizeXor;
534*c2c66affSColin Finck
535*c2c66affSColin Finck BOOL need_extension;
536*c2c66affSColin Finck LPCSTR lpszTitle = LocalLock(group->hName);
537*c2c66affSColin Finck
538*c2c66affSColin Finck UINT16 checksum;
539*c2c66affSColin Finck
540*c2c66affSColin Finck GRPFILE_InitChecksum();
541*c2c66affSColin Finck
542*c2c66affSColin Finck /* Calculate offsets */
543*c2c66affSColin Finck NumProg = 0;
544*c2c66affSColin Finck Icons = 0;
545*c2c66affSColin Finck Extension = 0;
546*c2c66affSColin Finck need_extension = FALSE;
547*c2c66affSColin Finck hProgram = group->hPrograms;
548*c2c66affSColin Finck while(hProgram)
549*c2c66affSColin Finck {
550*c2c66affSColin Finck PROGRAM *program = LocalLock(hProgram);
551*c2c66affSColin Finck LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
552*c2c66affSColin Finck
553*c2c66affSColin Finck NumProg++;
554*c2c66affSColin Finck GRPFILE_CalculateSizes(program, &Icons, &Extension, &sizeAnd, &sizeXor);
555*c2c66affSColin Finck
556*c2c66affSColin Finck /* Set a flag if an extension is needed */
557*c2c66affSColin Finck if (lpszWorkDir[0] || program->nHotKey ||
558*c2c66affSColin Finck program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
559*c2c66affSColin Finck
560*c2c66affSColin Finck hProgram = program->hNext;
561*c2c66affSColin Finck }
562*c2c66affSColin Finck Title = 34 + NumProg * 2;
563*c2c66affSColin Finck Progs = Title + strlen(lpszTitle) + 1;
564*c2c66affSColin Finck Icons += Progs;
565*c2c66affSColin Finck Extension += Icons;
566*c2c66affSColin Finck
567*c2c66affSColin Finck /* Header */
568*c2c66affSColin Finck buffer[0] = 'P';
569*c2c66affSColin Finck buffer[1] = 'M';
570*c2c66affSColin Finck buffer[2] = 'C';
571*c2c66affSColin Finck buffer[3] = 'C';
572*c2c66affSColin Finck
573*c2c66affSColin Finck PUT_SHORT(buffer, 4, 0); /* Checksum zero for now, written later */
574*c2c66affSColin Finck PUT_SHORT(buffer, 6, Extension);
575*c2c66affSColin Finck /* Update group->nCmdShow */
576*c2c66affSColin Finck if (IsIconic(group->hWnd)) nCmdShow = SW_SHOWMINIMIZED;
577*c2c66affSColin Finck else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED;
578*c2c66affSColin Finck else nCmdShow = SW_SHOWNORMAL;
579*c2c66affSColin Finck PUT_SHORT(buffer, 8, nCmdShow);
580*c2c66affSColin Finck PUT_SHORT(buffer, 10, group->x);
581*c2c66affSColin Finck PUT_SHORT(buffer, 12, group->y);
582*c2c66affSColin Finck PUT_SHORT(buffer, 14, group->width);
583*c2c66affSColin Finck PUT_SHORT(buffer, 16, group->height);
584*c2c66affSColin Finck PUT_SHORT(buffer, 18, group->iconx);
585*c2c66affSColin Finck PUT_SHORT(buffer, 20, group->icony);
586*c2c66affSColin Finck PUT_SHORT(buffer, 22, Title);
587*c2c66affSColin Finck PUT_SHORT(buffer, 24, 0x0020); /* unknown */
588*c2c66affSColin Finck PUT_SHORT(buffer, 26, 0x0020); /* unknown */
589*c2c66affSColin Finck PUT_SHORT(buffer, 28, 0x0108); /* unknown */
590*c2c66affSColin Finck PUT_SHORT(buffer, 30, 0x0000); /* unknown */
591*c2c66affSColin Finck PUT_SHORT(buffer, 32, NumProg);
592*c2c66affSColin Finck
593*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
594*c2c66affSColin Finck
595*c2c66affSColin Finck /* Program table */
596*c2c66affSColin Finck CurrProg = Progs;
597*c2c66affSColin Finck CurrIcon = Icons;
598*c2c66affSColin Finck hProgram = group->hPrograms;
599*c2c66affSColin Finck while(hProgram)
600*c2c66affSColin Finck {
601*c2c66affSColin Finck PROGRAM *program = LocalLock(hProgram);
602*c2c66affSColin Finck
603*c2c66affSColin Finck PUT_SHORT(buffer, 0, CurrProg);
604*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
605*c2c66affSColin Finck return FALSE;
606*c2c66affSColin Finck
607*c2c66affSColin Finck GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon, &sizeAnd, &sizeXor);
608*c2c66affSColin Finck hProgram = program->hNext;
609*c2c66affSColin Finck }
610*c2c66affSColin Finck
611*c2c66affSColin Finck /* Title */
612*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle, strlen(lpszTitle) + 1))
613*c2c66affSColin Finck return FALSE;
614*c2c66affSColin Finck
615*c2c66affSColin Finck /* Program entries */
616*c2c66affSColin Finck CurrProg = Progs;
617*c2c66affSColin Finck CurrIcon = Icons;
618*c2c66affSColin Finck hProgram = group->hPrograms;
619*c2c66affSColin Finck while(hProgram)
620*c2c66affSColin Finck {
621*c2c66affSColin Finck PROGRAM *program = LocalLock(hProgram);
622*c2c66affSColin Finck LPCSTR Name = LocalLock(program->hName);
623*c2c66affSColin Finck LPCSTR CmdLine = LocalLock(program->hCmdLine);
624*c2c66affSColin Finck LPCSTR IconFile = LocalLock(program->hIconFile);
625*c2c66affSColin Finck INT next_prog = CurrProg;
626*c2c66affSColin Finck INT next_icon = CurrIcon;
627*c2c66affSColin Finck
628*c2c66affSColin Finck GRPFILE_CalculateSizes(program, &next_prog, &next_icon, &sizeAnd, &sizeXor);
629*c2c66affSColin Finck PUT_SHORT(buffer, 0, program->x);
630*c2c66affSColin Finck PUT_SHORT(buffer, 2, program->y);
631*c2c66affSColin Finck PUT_SHORT(buffer, 4, program->nIconIndex);
632*c2c66affSColin Finck PUT_SHORT(buffer, 6, 0x048c); /* unknown */
633*c2c66affSColin Finck PUT_SHORT(buffer, 8, sizeXor);
634*c2c66affSColin Finck PUT_SHORT(buffer, 10, sizeAnd * 8);
635*c2c66affSColin Finck PUT_SHORT(buffer, 12, CurrIcon);
636*c2c66affSColin Finck PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd);
637*c2c66affSColin Finck PUT_SHORT(buffer, 16, CurrIcon + 12);
638*c2c66affSColin Finck ptr = CurrProg + 24;
639*c2c66affSColin Finck PUT_SHORT(buffer, 18, ptr);
640*c2c66affSColin Finck ptr += strlen(Name) + 1;
641*c2c66affSColin Finck PUT_SHORT(buffer, 20, ptr);
642*c2c66affSColin Finck ptr += strlen(CmdLine) + 1;
643*c2c66affSColin Finck PUT_SHORT(buffer, 22, ptr);
644*c2c66affSColin Finck
645*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 24) ||
646*c2c66affSColin Finck (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, Name, strlen(Name) + 1) ||
647*c2c66affSColin Finck (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, CmdLine, strlen(CmdLine) + 1) ||
648*c2c66affSColin Finck (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, IconFile, strlen(IconFile) + 1))
649*c2c66affSColin Finck return FALSE;
650*c2c66affSColin Finck
651*c2c66affSColin Finck CurrProg = next_prog;
652*c2c66affSColin Finck CurrIcon = next_icon;
653*c2c66affSColin Finck hProgram = program->hNext;
654*c2c66affSColin Finck }
655*c2c66affSColin Finck
656*c2c66affSColin Finck /* Icons */
657*c2c66affSColin Finck #if 0 /* FIXME: this is broken anyway */
658*c2c66affSColin Finck hProgram = group->hPrograms;
659*c2c66affSColin Finck while(hProgram)
660*c2c66affSColin Finck {
661*c2c66affSColin Finck PROGRAM *program = LocalLock(hProgram);
662*c2c66affSColin Finck CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
663*c2c66affSColin Finck LPVOID XorBits, AndBits;
664*c2c66affSColin Finck INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
665*c2c66affSColin Finck INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
666*c2c66affSColin Finck /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
667*c2c66affSColin Finck
668*c2c66affSColin Finck PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x);
669*c2c66affSColin Finck PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y);
670*c2c66affSColin Finck PUT_SHORT(buffer, 4, iconinfo->nWidth);
671*c2c66affSColin Finck PUT_SHORT(buffer, 6, iconinfo->nHeight);
672*c2c66affSColin Finck PUT_SHORT(buffer, 8, iconinfo->nWidthBytes);
673*c2c66affSColin Finck buffer[10] = iconinfo->bPlanes;
674*c2c66affSColin Finck buffer[11] = iconinfo->bBitsPerPixel;
675*c2c66affSColin Finck
676*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 12) ||
677*c2c66affSColin Finck (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, AndBits, sizeAnd) ||
678*c2c66affSColin Finck (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, XorBits, sizeXor)) return FALSE;
679*c2c66affSColin Finck
680*c2c66affSColin Finck hProgram = program->hNext;
681*c2c66affSColin Finck }
682*c2c66affSColin Finck #endif
683*c2c66affSColin Finck
684*c2c66affSColin Finck if (need_extension)
685*c2c66affSColin Finck {
686*c2c66affSColin Finck /* write `PMCC' extension */
687*c2c66affSColin Finck PUT_SHORT(buffer, 0, 0x8000);
688*c2c66affSColin Finck PUT_SHORT(buffer, 2, 0xffff);
689*c2c66affSColin Finck PUT_SHORT(buffer, 4, 0x000a);
690*c2c66affSColin Finck buffer[6] = 'P', buffer[7] = 'M';
691*c2c66affSColin Finck buffer[8] = 'C', buffer[9] = 'C';
692*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 10))
693*c2c66affSColin Finck return FALSE;
694*c2c66affSColin Finck
695*c2c66affSColin Finck seqnum = 0;
696*c2c66affSColin Finck hProgram = group->hPrograms;
697*c2c66affSColin Finck while(hProgram)
698*c2c66affSColin Finck {
699*c2c66affSColin Finck PROGRAM *program = LocalLock(hProgram);
700*c2c66affSColin Finck LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
701*c2c66affSColin Finck
702*c2c66affSColin Finck /* Working directory */
703*c2c66affSColin Finck if (lpszWorkDir[0])
704*c2c66affSColin Finck {
705*c2c66affSColin Finck PUT_SHORT(buffer, 0, 0x8101);
706*c2c66affSColin Finck PUT_SHORT(buffer, 2, seqnum);
707*c2c66affSColin Finck PUT_SHORT(buffer, 4, 7 + strlen(lpszWorkDir));
708*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6) ||
709*c2c66affSColin Finck (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszWorkDir, strlen(lpszWorkDir) + 1))
710*c2c66affSColin Finck return FALSE;
711*c2c66affSColin Finck }
712*c2c66affSColin Finck
713*c2c66affSColin Finck /* Hot key */
714*c2c66affSColin Finck if (program->nHotKey)
715*c2c66affSColin Finck {
716*c2c66affSColin Finck PUT_SHORT(buffer, 0, 0x8102);
717*c2c66affSColin Finck PUT_SHORT(buffer, 2, seqnum);
718*c2c66affSColin Finck PUT_SHORT(buffer, 4, 8);
719*c2c66affSColin Finck PUT_SHORT(buffer, 6, program->nHotKey);
720*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
721*c2c66affSColin Finck }
722*c2c66affSColin Finck
723*c2c66affSColin Finck /* Show command */
724*c2c66affSColin Finck if (program->nCmdShow)
725*c2c66affSColin Finck {
726*c2c66affSColin Finck PUT_SHORT(buffer, 0, 0x8103);
727*c2c66affSColin Finck PUT_SHORT(buffer, 2, seqnum);
728*c2c66affSColin Finck PUT_SHORT(buffer, 4, 8);
729*c2c66affSColin Finck PUT_SHORT(buffer, 6, program->nCmdShow);
730*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
731*c2c66affSColin Finck }
732*c2c66affSColin Finck
733*c2c66affSColin Finck seqnum++;
734*c2c66affSColin Finck hProgram = program->hNext;
735*c2c66affSColin Finck }
736*c2c66affSColin Finck
737*c2c66affSColin Finck /* Write `End' extension */
738*c2c66affSColin Finck PUT_SHORT(buffer, 0, 0xffff);
739*c2c66affSColin Finck PUT_SHORT(buffer, 2, 0xffff);
740*c2c66affSColin Finck PUT_SHORT(buffer, 4, 0x0000);
741*c2c66affSColin Finck if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6)) return FALSE;
742*c2c66affSColin Finck }
743*c2c66affSColin Finck
744*c2c66affSColin Finck checksum = GRPFILE_GetChecksum();
745*c2c66affSColin Finck _llseek(file, 4, SEEK_SET);
746*c2c66affSColin Finck PUT_SHORT(buffer, 0, checksum);
747*c2c66affSColin Finck _lwrite(file, buffer, 2);
748*c2c66affSColin Finck
749*c2c66affSColin Finck return TRUE;
750*c2c66affSColin Finck }
751*c2c66affSColin Finck
752*c2c66affSColin Finck #endif
753