4 * Copyright 1996 Ulrich Schmid
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define WIN32_LEAN_AND_MEAN
28 #define MALLOCHUNK 1000
30 #define GET_USHORT(buffer, i)\
31 (((BYTE)((buffer)[(i)]) + 0x100 * (BYTE)((buffer)[(i)+1])))
32 #define GET_SHORT(buffer, i)\
33 (((BYTE)((buffer)[(i)]) + 0x100 * (signed char)((buffer)[(i)+1])))
34 #define PUT_SHORT(buffer, i, s)\
35 (((buffer)[(i)] = (s) & 0xff, (buffer)[(i)+1] = ((s) >> 8) & 0xff))
37 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR, HLOCAL*, INT*);
38 static HLOCAL GRPFILE_ScanGroup(LPCSTR, INT, LPCSTR, BOOL);
39 static HLOCAL GRPFILE_ScanProgram(LPCSTR, INT, LPCSTR, INT,
40 LPCSTR, HLOCAL,LPCSTR);
41 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group);
43 /***********************************************************************
45 * GRPFILE_ModifyFileName
47 * Change extension `.grp' to `.gr'
50 static VOID GRPFILE_ModifyFileName(LPSTR lpszNewName, LPCSTR lpszOrigName,
51 INT nSize, BOOL bModify)
53 lstrcpyn(lpszNewName, lpszOrigName, nSize);
54 lpszNewName[nSize-1] = '\0';
56 if (!lstrcmpi(lpszNewName + strlen(lpszNewName) - 4, ".grp"))
57 lpszNewName[strlen(lpszNewName) - 1] = '\0';
60 /***********************************************************************
62 * GRPFILE_ReadGroupFile
65 HLOCAL GRPFILE_ReadGroupFile(LPCSTR lpszPath)
67 CHAR szPath_gr[MAX_PATHNAME_LEN];
68 BOOL bFileNameModified = FALSE;
70 HLOCAL hBuffer, hGroup;
73 /* if `.gr' file exists use that */
74 GRPFILE_ModifyFileName(szPath_gr, lpszPath, MAX_PATHNAME_LEN, TRUE);
75 if (OpenFile(szPath_gr, &dummy, OF_EXIST) != HFILE_ERROR)
78 bFileNameModified = TRUE;
81 /* Read the whole file into a buffer */
82 if (!GRPFILE_ReadFileToBuffer(lpszPath, &hBuffer, &size))
84 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
88 /* Interpret buffer */
89 hGroup = GRPFILE_ScanGroup(LocalLock(hBuffer), size,
90 lpszPath, bFileNameModified);
92 MAIN_MessageBoxIDS_s(IDS_GRPFILE_READ_ERROR_s, lpszPath, IDS_ERROR, MB_YESNO);
99 /***********************************************************************
101 * GRPFILE_ReadFileToBuffer
104 static BOOL GRPFILE_ReadFileToBuffer(LPCSTR path, HLOCAL *phBuffer,
109 HLOCAL hBuffer, hNewBuffer;
112 file=_lopen(path, OF_READ);
113 if (file == HFILE_ERROR) return FALSE;
116 hBuffer = LocalAlloc(LMEM_FIXED, size + MALLOCHUNK + 1);
117 if (!hBuffer) return FALSE;
118 buffer = LocalLock(hBuffer);
120 while ((len = _lread(file, buffer + size, MALLOCHUNK))
124 hNewBuffer = LocalReAlloc(hBuffer, size + MALLOCHUNK + 1,
131 hBuffer = hNewBuffer;
132 buffer = LocalLock(hBuffer);
137 if (len == (UINT)HFILE_ERROR)
151 /***********************************************************************
155 static HLOCAL GRPFILE_ScanGroup(LPCSTR buffer, INT size,
157 BOOL bModifiedFileName)
163 INT x, y, width, height, iconx, icony, nCmdShow;
164 INT number_of_programs;
165 BOOL bOverwriteFileOk;
167 if (buffer[0] != 'P' || buffer[1] != 'M') return(0);
168 if (buffer[2] == 'C' && buffer[3] == 'C')
169 /* original with checksum */
170 bOverwriteFileOk = FALSE;
171 else if (buffer[2] == 'X' && buffer[3] == 'X')
172 /* modified without checksum */
173 bOverwriteFileOk = TRUE;
176 /* checksum = GET_USHORT(buffer, 4) (ignored) */
178 extension = buffer + GET_USHORT(buffer, 6);
179 if (extension == buffer + size) extension = 0;
180 else if (extension + 6 > buffer + size) return(0);
182 nCmdShow = GET_USHORT(buffer, 8);
183 x = GET_SHORT(buffer, 10);
184 y = GET_SHORT(buffer, 12);
185 width = GET_USHORT(buffer, 14);
186 height = GET_USHORT(buffer, 16);
187 iconx = GET_SHORT(buffer, 18);
188 icony = GET_SHORT(buffer, 20);
189 lpszName = buffer + GET_USHORT(buffer, 22);
190 if (lpszName >= buffer + size) return(0);
192 /* unknown bytes 24 - 31 ignored */
194 Unknown bytes should be:
195 wLogPixelsX = GET_SHORT(buffer, 24);
196 wLogPixelsY = GET_SHORT(buffer, 26);
197 byBitsPerPixel = byte at 28;
198 byPlanes = byte at 29;
199 wReserved = GET_SHORT(buffer, 30);
202 hGroup = GROUP_AddGroup(lpszName, lpszGrpFile, nCmdShow, x, y,
203 width, height, iconx, icony,
204 bModifiedFileName, bOverwriteFileOk,
206 if (!hGroup) return(0);
208 number_of_programs = GET_USHORT(buffer, 32);
209 if (2 * number_of_programs + 34 > size) return(0);
210 for (i=0, seqnum=0; i < number_of_programs; i++, seqnum++)
212 LPCSTR program_ptr = buffer + GET_USHORT(buffer, 34 + 2*i);
213 if (program_ptr + 24 > buffer + size) return(0);
214 if (!GET_USHORT(buffer, 34 + 2*i)) continue;
215 if (!GRPFILE_ScanProgram(buffer, size, program_ptr, seqnum,
216 extension, hGroup, lpszGrpFile))
218 GROUP_DeleteGroup(hGroup);
223 /* FIXME shouldn't be necessary */
224 GROUP_ShowGroupWindow(hGroup);
229 /***********************************************************************
230 * GRPFILE_ScanProgram
233 static HLOCAL GRPFILE_ScanProgram(LPCSTR buffer, INT size,
234 LPCSTR program_ptr, INT seqnum,
235 LPCSTR extension, HLOCAL hGroup,
240 LPCSTR lpszName, lpszCmdLine, lpszIconFile, lpszWorkDir;
241 LPCSTR iconinfo_ptr, iconANDbits_ptr, iconXORbits_ptr;
242 INT x, y, nIconIndex, iconANDsize, iconXORsize;
243 INT nHotKey, nCmdShow;
244 UINT width, height, planes, bpp;
246 x = GET_SHORT(program_ptr, 0);
247 y = GET_SHORT(program_ptr, 2);
248 nIconIndex = GET_USHORT(program_ptr, 4);
250 /* FIXME is this correct ?? */
251 icontype = GET_USHORT(program_ptr, 6);
255 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s, lpszGrpFile,
258 iconXORsize = GET_USHORT(program_ptr, 8);
259 iconANDsize = GET_USHORT(program_ptr, 10) / 8;
260 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
261 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 14);
262 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 16);
263 width = GET_USHORT(iconinfo_ptr, 4);
264 height = GET_USHORT(iconinfo_ptr, 6);
265 planes = GET_USHORT(iconinfo_ptr, 10);
266 bpp = GET_USHORT(iconinfo_ptr, 11);
269 iconANDsize = GET_USHORT(program_ptr, 8);
270 iconXORsize = GET_USHORT(program_ptr, 10);
271 iconinfo_ptr = buffer + GET_USHORT(program_ptr, 12);
272 iconANDbits_ptr = buffer + GET_USHORT(program_ptr, 14);
273 iconXORbits_ptr = buffer + GET_USHORT(program_ptr, 16);
274 width = GET_USHORT(iconinfo_ptr, 4);
275 height = GET_USHORT(iconinfo_ptr, 6);
276 planes = GET_USHORT(iconinfo_ptr, 10);
277 bpp = GET_USHORT(iconinfo_ptr, 11);
280 if (iconANDbits_ptr + iconANDsize > buffer + size ||
281 iconXORbits_ptr + iconXORsize > buffer + size) return(0);
283 hIcon = CreateIcon( Globals.hInstance, width, height, planes, bpp, iconANDbits_ptr, iconXORbits_ptr );
285 lpszName = buffer + GET_USHORT(program_ptr, 18);
286 lpszCmdLine = buffer + GET_USHORT(program_ptr, 20);
287 lpszIconFile = buffer + GET_USHORT(program_ptr, 22);
288 if (iconinfo_ptr + 6 > buffer + size ||
289 lpszName > buffer + size ||
290 lpszCmdLine > buffer + size ||
291 lpszIconFile > buffer + size) return(0);
293 /* Scan Extensions */
296 nCmdShow = SW_SHOWNORMAL;
299 LPCSTR ptr = extension;
300 while (ptr + 6 <= buffer + size)
302 UINT type = GET_USHORT(ptr, 0);
303 UINT number = GET_USHORT(ptr, 2);
304 UINT skip = GET_USHORT(ptr, 4);
306 if (number == seqnum)
311 if (ptr + 10 > buffer + size) return(0);
312 if (ptr[6] != 'P' || ptr[7] != 'M' ||
313 ptr[8] != 'C' || ptr[9] != 'C') return(0);
316 lpszWorkDir = ptr + 6;
319 if (ptr + 8 > buffer + size) return(0);
320 nHotKey = GET_USHORT(ptr, 6);
323 if (ptr + 8 > buffer + size) return(0);
324 nCmdShow = GET_USHORT(ptr, 6);
327 MAIN_MessageBoxIDS_s(IDS_UNKNOWN_FEATURE_s,
328 lpszGrpFile, IDS_WARNING, MB_OK);
336 return (PROGRAM_AddProgram(hGroup, hIcon, lpszName, x, y,
337 lpszCmdLine, lpszIconFile,
338 nIconIndex, lpszWorkDir,
342 /***********************************************************************
344 * GRPFILE_WriteGroupFile
347 BOOL GRPFILE_WriteGroupFile(HLOCAL hGroup)
349 CHAR szPath[MAX_PATHNAME_LEN];
350 PROGGROUP *group = LocalLock(hGroup);
355 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
357 group->bFileNameModified);
359 /* Try not to overwrite original files */
361 /* group->bOverwriteFileOk == TRUE only if a file has the modified format */
362 if (!group->bOverwriteFileOk &&
363 OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
365 /* Original file exists, try `.gr' extension */
366 GRPFILE_ModifyFileName(szPath, LocalLock(group->hGrpFile),
367 MAX_PATHNAME_LEN, TRUE);
368 if (OpenFile(szPath, &dummy, OF_EXIST) != HFILE_ERROR)
370 /* File exists. Do not overwrite */
371 MAIN_MessageBoxIDS_s(IDS_FILE_NOT_OVERWRITTEN_s, szPath,
375 /* Inform about the modified file name */
377 MAIN_MessageBoxIDS_s(IDS_SAVE_GROUP_AS_s, szPath, IDS_INFO,
378 MB_OKCANCEL | MB_ICONINFORMATION))
383 /* Warn about the (possible) incompatibility */
384 CHAR msg[MAX_PATHNAME_LEN + 200];
386 "Group files written by this DRAFT Program Manager "
387 "possibly cannot be read by the Microsoft Program Manager!!\n"
388 "Are you sure to write %s?", szPath);
389 if (IDOK != MessageBox(Globals.hMainWnd, msg, "WARNING",
390 MB_OKCANCEL | MB_DEFBUTTON2)) return FALSE;
394 file = _lcreat(szPath, 0);
395 if (file != HFILE_ERROR)
397 ret = GRPFILE_DoWriteGroupFile(file, group);
403 MAIN_MessageBoxIDS_s(IDS_FILE_WRITE_ERROR_s, szPath, IDS_ERROR, MB_OK);
408 /***********************************************************************
410 * GRPFILE_CalculateSizes
413 static VOID GRPFILE_CalculateSizes(PROGRAM *program, INT *Progs, INT *Icons,
414 UINT *sizeAnd, UINT *sizeXor)
419 GetIconInfo( program->hIcon, &info );
420 GetObjectW( info.hbmMask, sizeof(bmp), &bmp );
421 *sizeAnd = bmp.bmHeight * ((bmp.bmWidth + 15) / 16 * 2);
422 GetObjectW( info.hbmColor, sizeof(bmp), &bmp );
423 *sizeXor = bmp.bmHeight * bmp.bmWidthBytes;
424 DeleteObject( info.hbmMask );
425 DeleteObject( info.hbmColor );
428 *Progs += lstrlen(LocalLock(program->hName)) + 1;
429 *Progs += lstrlen(LocalLock(program->hCmdLine)) + 1;
430 *Progs += lstrlen(LocalLock(program->hIconFile)) + 1;
432 *Icons += 12; /* IconInfo */
437 /***********************************************************************/
438 UINT16 GRPFILE_checksum;
439 BOOL GRPFILE_checksum_half_word;
440 BYTE GRPFILE_checksum_last_byte;
441 /***********************************************************************
443 * GRPFILE_InitChecksum
446 static void GRPFILE_InitChecksum(void)
448 GRPFILE_checksum = 0;
449 GRPFILE_checksum_half_word = 0;
452 /***********************************************************************
454 * GRPFILE_GetChecksum
457 static UINT16 GRPFILE_GetChecksum(void)
459 return GRPFILE_checksum;
462 /***********************************************************************
464 * GRPFILE_WriteWithChecksum
466 * Looks crazier than it is:
469 * chksum = cksum - 1. word;
470 * chksum = cksum - 2. word;
473 * if (filelen is even)
479 static UINT GRPFILE_WriteWithChecksum(HFILE file, LPCSTR str, UINT size)
482 if (GRPFILE_checksum_half_word) {
483 GRPFILE_checksum -= GRPFILE_checksum_last_byte;
485 for (i=0; i < size; i++) {
486 if (GRPFILE_checksum_half_word) {
487 GRPFILE_checksum -= str[i] << 8;
489 GRPFILE_checksum -= str[i];
491 GRPFILE_checksum_half_word ^= 1;
494 if (GRPFILE_checksum_half_word) {
495 GRPFILE_checksum_last_byte = str[size-1];
496 GRPFILE_checksum += GRPFILE_checksum_last_byte;
499 return _lwrite(file, str, size);
503 /***********************************************************************
505 * GRPFILE_DoWriteGroupFile
508 static BOOL GRPFILE_DoWriteGroupFile(HFILE file, PROGGROUP *group)
512 INT NumProg, Title, Progs, Icons, Extension;
513 INT CurrProg, CurrIcon, nCmdShow, ptr, seqnum;
514 DWORD sizeAnd, sizeXor;
516 LPCSTR lpszTitle = LocalLock(group->hName);
520 GRPFILE_InitChecksum();
522 /* Calculate offsets */
526 need_extension = FALSE;
527 hProgram = group->hPrograms;
530 PROGRAM *program = LocalLock(hProgram);
531 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
534 GRPFILE_CalculateSizes(program, &Icons, &Extension, &sizeAnd, &sizeXor);
536 /* Set a flag if an extension is needed */
537 if (lpszWorkDir[0] || program->nHotKey ||
538 program->nCmdShow != SW_SHOWNORMAL) need_extension = TRUE;
540 hProgram = program->hNext;
542 Title = 34 + NumProg * 2;
543 Progs = Title + lstrlen(lpszTitle) + 1;
553 PUT_SHORT(buffer, 4, 0); /* Checksum zero for now, written later */
554 PUT_SHORT(buffer, 6, Extension);
555 /* Update group->nCmdShow */
556 if (IsIconic(group->hWnd)) nCmdShow = SW_SHOWMINIMIZED;
557 else if (IsZoomed(group->hWnd)) nCmdShow = SW_SHOWMAXIMIZED;
558 else nCmdShow = SW_SHOWNORMAL;
559 PUT_SHORT(buffer, 8, nCmdShow);
560 PUT_SHORT(buffer, 10, group->x);
561 PUT_SHORT(buffer, 12, group->y);
562 PUT_SHORT(buffer, 14, group->width);
563 PUT_SHORT(buffer, 16, group->height);
564 PUT_SHORT(buffer, 18, group->iconx);
565 PUT_SHORT(buffer, 20, group->icony);
566 PUT_SHORT(buffer, 22, Title);
567 PUT_SHORT(buffer, 24, 0x0020); /* unknown */
568 PUT_SHORT(buffer, 26, 0x0020); /* unknown */
569 PUT_SHORT(buffer, 28, 0x0108); /* unknown */
570 PUT_SHORT(buffer, 30, 0x0000); /* unknown */
571 PUT_SHORT(buffer, 32, NumProg);
573 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 34)) return FALSE;
578 hProgram = group->hPrograms;
581 PROGRAM *program = LocalLock(hProgram);
583 PUT_SHORT(buffer, 0, CurrProg);
584 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 2))
587 GRPFILE_CalculateSizes(program, &CurrProg, &CurrIcon, &sizeAnd, &sizeXor);
588 hProgram = program->hNext;
592 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszTitle,
593 lstrlen(lpszTitle) + 1))
596 /* Program entries */
599 hProgram = group->hPrograms;
602 PROGRAM *program = LocalLock(hProgram);
603 LPCSTR Name = LocalLock(program->hName);
604 LPCSTR CmdLine = LocalLock(program->hCmdLine);
605 LPCSTR IconFile = LocalLock(program->hIconFile);
606 INT next_prog = CurrProg;
607 INT next_icon = CurrIcon;
609 GRPFILE_CalculateSizes(program, &next_prog, &next_icon, &sizeAnd, &sizeXor);
610 PUT_SHORT(buffer, 0, program->x);
611 PUT_SHORT(buffer, 2, program->y);
612 PUT_SHORT(buffer, 4, program->nIconIndex);
613 PUT_SHORT(buffer, 6, 0x048c); /* unknown */
614 PUT_SHORT(buffer, 8, sizeXor);
615 PUT_SHORT(buffer, 10, sizeAnd * 8);
616 PUT_SHORT(buffer, 12, CurrIcon);
617 PUT_SHORT(buffer, 14, CurrIcon + 12 + sizeAnd);
618 PUT_SHORT(buffer, 16, CurrIcon + 12);
620 PUT_SHORT(buffer, 18, ptr);
621 ptr += lstrlen(Name) + 1;
622 PUT_SHORT(buffer, 20, ptr);
623 ptr += lstrlen(CmdLine) + 1;
624 PUT_SHORT(buffer, 22, ptr);
626 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 24) ||
627 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, Name, lstrlen(Name) + 1) ||
628 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, CmdLine, lstrlen(CmdLine) + 1) ||
629 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, IconFile, lstrlen(IconFile) + 1))
632 CurrProg = next_prog;
633 CurrIcon = next_icon;
634 hProgram = program->hNext;
638 #if 0 /* FIXME: this is broken anyway */
639 hProgram = group->hPrograms;
642 PROGRAM *program = LocalLock(hProgram);
643 CURSORICONINFO *iconinfo = LocalLock(program->hIcon);
644 LPVOID XorBits, AndBits;
645 INT sizeXor = iconinfo->nHeight * iconinfo->nWidthBytes;
646 INT sizeAnd = iconinfo->nHeight * ((iconinfo->nWidth + 15) / 16 * 2);
647 /* DumpIcon16(LocalLock(program->hIcon), 0, &XorBits, &AndBits);*/
649 PUT_SHORT(buffer, 0, iconinfo->ptHotSpot.x);
650 PUT_SHORT(buffer, 2, iconinfo->ptHotSpot.y);
651 PUT_SHORT(buffer, 4, iconinfo->nWidth);
652 PUT_SHORT(buffer, 6, iconinfo->nHeight);
653 PUT_SHORT(buffer, 8, iconinfo->nWidthBytes);
654 buffer[10] = iconinfo->bPlanes;
655 buffer[11] = iconinfo->bBitsPerPixel;
657 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 12) ||
658 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, AndBits, sizeAnd) ||
659 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, XorBits, sizeXor)) return FALSE;
661 hProgram = program->hNext;
667 /* write `PMCC' extension */
668 PUT_SHORT(buffer, 0, 0x8000);
669 PUT_SHORT(buffer, 2, 0xffff);
670 PUT_SHORT(buffer, 4, 0x000a);
671 buffer[6] = 'P', buffer[7] = 'M';
672 buffer[8] = 'C', buffer[9] = 'C';
673 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 10))
677 hProgram = group->hPrograms;
680 PROGRAM *program = LocalLock(hProgram);
681 LPCSTR lpszWorkDir = LocalLock(program->hWorkDir);
683 /* Working directory */
686 PUT_SHORT(buffer, 0, 0x8101);
687 PUT_SHORT(buffer, 2, seqnum);
688 PUT_SHORT(buffer, 4, 7 + lstrlen(lpszWorkDir));
689 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6) ||
690 (UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, lpszWorkDir, lstrlen(lpszWorkDir) + 1))
695 if (program->nHotKey)
697 PUT_SHORT(buffer, 0, 0x8102);
698 PUT_SHORT(buffer, 2, seqnum);
699 PUT_SHORT(buffer, 4, 8);
700 PUT_SHORT(buffer, 6, program->nHotKey);
701 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
705 if (program->nCmdShow)
707 PUT_SHORT(buffer, 0, 0x8103);
708 PUT_SHORT(buffer, 2, seqnum);
709 PUT_SHORT(buffer, 4, 8);
710 PUT_SHORT(buffer, 6, program->nCmdShow);
711 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 8)) return FALSE;
715 hProgram = program->hNext;
718 /* Write `End' extension */
719 PUT_SHORT(buffer, 0, 0xffff);
720 PUT_SHORT(buffer, 2, 0xffff);
721 PUT_SHORT(buffer, 4, 0x0000);
722 if ((UINT)HFILE_ERROR == GRPFILE_WriteWithChecksum(file, buffer, 6)) return FALSE;
725 checksum = GRPFILE_GetChecksum();
726 _llseek(file, 4, SEEK_SET);
727 PUT_SHORT(buffer, 0, checksum);
728 _lwrite(file, buffer, 2);
733 /* Local Variables: */
734 /* c-file-style: "GNU" */