1/*
2  api.c - Zip 3
3
4  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
5
6  See the accompanying file LICENSE, version 2007-Mar-4 or later
7  (the contents of which are also included in zip.h) for terms of use.
8  If, for some reason, all these files are missing, the Info-ZIP license
9  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
10*/
11/*---------------------------------------------------------------------------
12
13  api.c
14
15  This module supplies a Zip dll engine for use directly from C/C++
16  programs.
17
18  The entry points are:
19
20    ZpVer *ZpVersion(void);
21    int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc);
22    int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts);
23
24  This module is currently only used by the Windows dll, and is not used at
25  all by any of the other platforms, although it should be easy enough to
26  implement this on most platforms.
27
28  ---------------------------------------------------------------------------*/
29#define __API_C
30
31#include <malloc.h>
32#ifdef WINDLL
33#  include <windows.h>
34#  include "windll/windll.h"
35#endif
36
37#ifdef OS2
38#  define  INCL_DOSMEMMGR
39#  include <os2.h>
40#endif
41
42#ifdef __BORLANDC__
43#include <dir.h>
44#endif
45#include <direct.h>
46#include <ctype.h>
47#include "api.h"                /* this includes zip.h */
48#include "crypt.h"
49#include "revision.h"
50#ifdef USE_ZLIB
51#  include "zlib.h"
52#endif
53
54
55DLLPRNT *lpZipPrint;
56DLLPASSWORD *lpZipPassword;
57extern DLLCOMMENT *lpComment;
58ZIPUSERFUNCTIONS ZipUserFunctions, far * lpZipUserFunctions;
59
60int ZipRet;
61char szOrigDir[PATH_MAX];
62BOOL fNo_int64 = FALSE; /* flag for DLLSERVICE_NO_INT64 */
63
64/* Local forward declarations */
65extern int  zipmain OF((int, char **));
66int AllocMemory(unsigned int, char *, char *, BOOL);
67int ParseString(LPSTR, unsigned int);
68void FreeArgVee(void);
69
70ZPOPT Options;
71char **argVee;
72unsigned int argCee;
73
74/*---------------------------------------------------------------------------
75    Local functions
76  ---------------------------------------------------------------------------*/
77
78char szRootDir[PATH_MAX], szExcludeList[PATH_MAX], szIncludeList[PATH_MAX], szTempDir[PATH_MAX];
79
80int ParseString(LPSTR s, unsigned int ArgC)
81{
82unsigned int i;
83int root_flag, m, j;
84char *str1, *str2, *str3;
85size_t size;
86
87i = ArgC;
88str1 = (char *) malloc(lstrlen(s)+4);
89lstrcpy(str1, s);
90lstrcat(str1, " @");
91
92if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
93    {
94    root_flag = TRUE;
95    if (szRootDir[lstrlen(szRootDir)-1] != '\\')
96        lstrcat(szRootDir, "\\");
97    }
98else
99    root_flag = FALSE;
100
101str2 = strchr(str1, '\"'); /* get first occurance of double quote */
102
103while ((str3 = strchr(str1, '\t')) != NULL)
104    {
105    str3[0] = ' '; /* Change tabs into a single space */
106    }
107
108/* Note that if a quoted string contains multiple adjacent spaces, they
109   will not be removed, because they could well point to a valid
110   folder/file name.
111*/
112while ((str2 = strchr(str1, '\"')) != NULL)
113    /* Found a double quote if not NULL */
114    {
115    str3 = strchr(str2+1, '\"'); /* Get the second quote */
116    if (str3 == NULL)
117        {
118        free(str1);
119        return ZE_PARMS; /* Something is screwy with the
120                            string, bail out */
121        }
122    str3[0] = '\0';  /* terminate str2 with a NULL */
123
124    /* strip unwanted fully qualified path from entry */
125    if (root_flag)
126        if ((_strnicmp(szRootDir, str2+1, lstrlen(szRootDir))) == 0)
127            {
128            m = 0;
129            str2++;
130            for (j = lstrlen(szRootDir); j < lstrlen(str2); j++)
131                str2[m++] = str2[j];
132            str2[m] = '\0';
133            str2--;
134            }
135    size = _msize(argVee);
136    if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
137        {
138        fprintf(stdout, "Unable to allocate memory in zip dll\n");
139        return ZE_MEM;
140        }
141    /* argCee is incremented in AllocMemory */
142    if (AllocMemory(i, str2+1, "Creating file list from string", TRUE) != ZE_OK)
143        {
144        free(str1);
145        return ZE_MEM;
146        }
147    i++;
148    str3+=2;        /* Point past the whitespace character */
149    str2[0] = '\0'; /* Terminate str1 */
150    lstrcat(str1, str3);
151    }    /* end while */
152
153/* points to first occurance of a space */
154str2 = strchr(str1, ' ');
155
156/*  Go through the string character by character, looking for instances
157    of two spaces together. Terminate when you find the trailing @
158*/
159while ((str2[0] != '\0') && (str2[0] != '@'))
160    {
161    while ((str2[0] == ' ') && (str2[1] == ' '))
162        {
163        str3 = &str2[1];
164        str2[0] = '\0';
165        lstrcat(str1, str3);
166        }
167    str2++;
168    }
169
170/* Do we still have a leading space? */
171if (str1[0] == ' ')
172    {
173    str3 = &str1[1];
174    lstrcpy(str1, str3); /* Dump the leading space */
175    }
176
177
178/* Okay, now we have gotten rid of any tabs and replaced them with
179   spaces, and have replaced multiple spaces with a single space. We
180   couldn't do this before because the folder names could have actually
181   contained these characters.
182*/
183
184str2 = str3 = str1;
185
186while ((str2[0] != '\0') && (str3[0] != '@'))
187    {
188    str3 = strchr(str2+1, ' ');
189    str3[0] = '\0';
190    /* strip unwanted fully qualified path from entry */
191    if (root_flag)
192        if ((_strnicmp(szRootDir, str2, lstrlen(szRootDir))) == 0)
193           {
194            m = 0;
195            for (j = lstrlen(Options.szRootDir); j < lstrlen(str2); j++)
196            str2[m++] = str2[j];
197            str2[m] = '\0';
198            }
199    size = _msize(argVee);
200    if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
201        {
202        fprintf(stdout, "Unable to allocate memory in zip dll\n");
203        return ZE_MEM;
204        }
205    if (AllocMemory(i, str2, "Creating file list from string", TRUE) != ZE_OK)
206        {
207        free(str1);
208        return ZE_MEM;
209        }
210    i++;
211    str3++;
212    str2 = str3;
213    }
214free(str1);
215return ZE_OK;
216}
217
218int AllocMemory(unsigned int i, char *cmd, char *str, BOOL IncrementArgCee)
219{
220if ((argVee[i] = (char *) malloc( sizeof(char) * strlen(cmd)+1 )) == NULL)
221   {
222   if (IncrementArgCee)
223       argCee++;
224   FreeArgVee();
225   fprintf(stdout, "Unable to allocate memory in zip library at %s\n", str);
226   return ZE_MEM;
227   }
228strcpy( argVee[i], cmd );
229argCee++;
230return ZE_OK;
231}
232
233void FreeArgVee(void)
234{
235unsigned i;
236
237/* Free the arguments in the array */
238for (i = 0; i < argCee; i++)
239    {
240    free (argVee[i]);
241    argVee[i] = NULL;
242    }
243/* Then free the array itself */
244free(argVee);
245
246/* Restore the original working directory */
247chdir(szOrigDir);
248#ifdef __BORLANDC__
249setdisk(toupper(szOrigDir[0]) - 'A');
250#endif
251
252}
253
254
255/*---------------------------------------------------------------------------
256    Documented API entry points
257  ---------------------------------------------------------------------------*/
258
259int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc)
260{
261ZipUserFunctions = *lpZipUserFunc;
262lpZipUserFunctions = &ZipUserFunctions;
263
264if (!lpZipUserFunctions->print ||
265    !lpZipUserFunctions->comment)
266    return FALSE;
267
268return TRUE;
269}
270
271int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts)
272/* Add, update, freshen, or delete zip entries in a zip file.  See the
273   command help in help() zip.c */
274{
275int k, j, m;
276size_t size;
277
278Options = *Opts; /* Save off options, and make them available locally */
279szRootDir[0] = '\0';
280szExcludeList[0] = '\0';
281szIncludeList[0] = '\0';
282szTempDir[0] = '\0';
283if (Options.szRootDir) lstrcpy(szRootDir, Options.szRootDir);
284if (Options.szExcludeList) lstrcpy(szExcludeList, Options.szExcludeList);
285if (Options.szIncludeList) lstrcpy(szIncludeList, Options.szIncludeList);
286if (Options.szTempDir) lstrcpy(szTempDir, Options.szTempDir);
287
288getcwd(szOrigDir, PATH_MAX); /* Save current drive and directory */
289
290if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
291   {
292   /* Make sure there isn't a trailing slash */
293   if (szRootDir[lstrlen(szRootDir)-1] == '\\')
294       szRootDir[lstrlen(szRootDir)-1] = '\0';
295
296   chdir(szRootDir);
297#ifdef __BORLANDC__
298   setdisk(toupper(szRootDir[0]) - 'A');
299#endif
300   }
301
302argCee = 0;
303
304/* malloc additional 40 to allow for additional command line arguments. Note
305   that we are also adding in the count for the include lists as well as the
306   exclude list. */
307if ((argVee = (char **)malloc((C.argc+40)*sizeof(char *))) == NULL)
308   {
309   fprintf(stdout, "Unable to allocate memory in zip dll\n");
310   return ZE_MEM;
311   }
312if ((argVee[argCee] = (char *) malloc( sizeof(char) * strlen("wiz.exe")+1 )) == NULL)
313   {
314   free(argVee);
315   fprintf(stdout, "Unable to allocate memory in zip dll\n");
316   return ZE_MEM;
317   }
318strcpy( argVee[argCee], "wiz.exe" );
319argCee++;
320
321
322/* Set compression level efficacy -0...-9 */
323if (AllocMemory(argCee, "-0", "Compression", FALSE) != ZE_OK)
324    return ZE_MEM;
325
326/* Check to see if the compression level is set to a valid value. If
327 not, then set it to the default.
328*/
329if ((Options.fLevel < '0') || (Options.fLevel > '9'))
330    {
331    Options.fLevel = '6';
332    if (!Options.fDeleteEntries)
333        fprintf(stdout, "Compression level set to invalid value. Setting to default\n");
334    }
335
336argVee[argCee-1][1] = Options.fLevel;
337
338if (Options.fOffsets)    /* Update offsets for SFX prefix */
339   {
340   if (AllocMemory(argCee, "-A", "Offsets", FALSE) != ZE_OK)
341        return ZE_MEM;
342    }
343if (Options.fDeleteEntries)    /* Delete files from zip file -d */
344   {
345   if (AllocMemory(argCee, "-d", "Delete", FALSE) != ZE_OK)
346        return ZE_MEM;
347   }
348if (Options.fNoDirEntries) /* Do not add directory entries -D */
349   {
350        if (AllocMemory(argCee, "-D", "No Dir Entries", FALSE) != ZE_OK)
351            return ZE_MEM;
352   }
353if (Options.fFreshen) /* Freshen zip file--overwrite only -f */
354   {
355   if (AllocMemory(argCee, "-f", "Freshen", FALSE) != ZE_OK)
356        return ZE_MEM;
357   }
358if (Options.fRepair)  /* Fix archive -F or -FF */
359   {
360   if (Options.fRepair == 1)
361      {
362      if (AllocMemory(argCee, "-F", "Repair", FALSE) != ZE_OK)
363          return ZE_MEM;
364      }
365   else
366      {
367      if (AllocMemory(argCee, "-FF", "Repair", FALSE) != ZE_OK)
368        return ZE_MEM;
369      }
370   }
371if (Options.fGrow) /* Allow appending to a zip file -g */
372   {
373   if (AllocMemory(argCee, "-g", "Appending", FALSE) != ZE_OK)
374        return ZE_MEM;
375   }
376if (Options.fJunkDir) /* Junk directory names -j */
377   {
378   if (AllocMemory(argCee, "-j", "Junk Dir Names", FALSE) != ZE_OK)
379        return ZE_MEM;
380   }
381if (Options.fEncrypt) /* encrypt -e */
382   {
383   if (AllocMemory(argCee, "-e", "Encrypt", FALSE) != ZE_OK)
384        return ZE_MEM;
385   }
386if (Options.fJunkSFX) /* Junk sfx prefix */
387   {
388   if (AllocMemory(argCee, "-J", "Junk SFX", FALSE) != ZE_OK)
389        return ZE_MEM;
390   }
391
392if (Options.fForce) /* Make entries using DOS names (k for Katz) -k */
393   {
394   if (AllocMemory(argCee, "-k", "Force DOS", FALSE) != ZE_OK)
395        return ZE_MEM;
396   }
397
398if (Options.fLF_CRLF) /* Translate LF_CRLF -l */
399   {
400   if (AllocMemory(argCee, "-l", "LF-CRLF", FALSE) != ZE_OK)
401        return ZE_MEM;
402   }
403if (Options.fCRLF_LF) /* Translate CR/LF to LF -ll */
404   {
405   if (AllocMemory(argCee, "-ll", "CRLF-LF", FALSE) != ZE_OK)
406        return ZE_MEM;
407   }
408if (Options.fMove) /* Delete files added to or updated in zip file -m */
409   {
410   if (AllocMemory(argCee, "-m", "Move", FALSE) != ZE_OK)
411        return ZE_MEM;
412   }
413
414if (Options.fLatestTime) /* Set zip file time to time of latest file in it -o */
415   {
416   if (AllocMemory(argCee, "-o", "Time", FALSE) != ZE_OK)
417        return ZE_MEM;
418   }
419
420if (Options.fComment) /* Add archive comment "-z" */
421   {
422   if (AllocMemory(argCee, "-z", "Comment", FALSE) != ZE_OK)
423        return ZE_MEM;
424   }
425
426if (Options.fQuiet) /* quiet operation -q */
427   {
428   if (AllocMemory(argCee, "-q", "Quiet", FALSE) != ZE_OK)
429        return ZE_MEM;
430   }
431if (Options.fRecurse == 1) /* recurse into subdirectories -r */
432   {
433   if (AllocMemory(argCee, "-r", "Recurse -r", FALSE) != ZE_OK)
434        return ZE_MEM;
435   }
436else if (Options.fRecurse == 2) /* recurse into subdirectories -R */
437   {
438   if (AllocMemory(argCee, "-R", "Recurse -R", FALSE) != ZE_OK)
439        return ZE_MEM;
440   }
441if (Options.fSystem)  /* include system and hidden files -S */
442   {
443   if (AllocMemory(argCee, "-S", "System", FALSE) != ZE_OK)
444        return ZE_MEM;
445   }
446if (Options.fExcludeDate)    /* Exclude files newer than specified date -tt */
447   {
448     if ((Options.Date != NULL) && (Options.Date[0] != '\0'))
449        {
450        if (AllocMemory(argCee, "-tt", "Date", FALSE) != ZE_OK)
451            return ZE_MEM;
452        if (AllocMemory(argCee, Options.Date, "Date", FALSE) != ZE_OK)
453            return ZE_MEM;
454        }
455   }
456
457if (Options.fIncludeDate)    /* include files newer than specified date -t */
458   {
459     if ((Options.Date != NULL) && (Options.Date[0] != '\0'))
460        {
461        if (AllocMemory(argCee, "-t", "Date", FALSE) != ZE_OK)
462            return ZE_MEM;
463       if (AllocMemory(argCee, Options.Date, "Date", FALSE) != ZE_OK)
464            return ZE_MEM;
465        }
466   }
467
468if (Options.fUpdate) /* Update zip file--overwrite only if newer -u */
469    {
470    if (AllocMemory(argCee, "-u", "Update", FALSE) != ZE_OK)
471        return ZE_MEM;
472    }
473if (Options.fVerbose)  /* Mention oddities in zip file structure -v */
474    {
475    if (AllocMemory(argCee, "-v", "Verbose", FALSE) != ZE_OK)
476        return ZE_MEM;
477    }
478if (Options.fVolume)  /* Include volume label -$ */
479    {
480    if (AllocMemory(argCee, "-$", "Volume", FALSE) != ZE_OK)
481        return ZE_MEM;
482    }
483if (Options.szSplitSize != NULL)   /* Turn on archive splitting */
484    {
485    if (AllocMemory(argCee, "-s", "Splitting", FALSE) != ZE_OK)
486        return ZE_MEM;
487    if (AllocMemory(argCee, Options.szSplitSize, "Split size", FALSE) != ZE_OK)
488        return ZE_MEM;
489    }
490if (lpZipUserFunctions->split != NULL)   /* Turn on archive split destinations select */
491    {
492    if (AllocMemory(argCee, "-sp", "Split Pause Select Destination", FALSE) != ZE_OK)
493        return ZE_MEM;
494    }
495#ifdef WIN32
496if (Options.fPrivilege)  /* Use privileges -! */
497   {
498   if (AllocMemory(argCee, "-!", "Privileges", FALSE) != ZE_OK)
499        return ZE_MEM;
500   }
501#endif
502if (Options.fExtra)  /* Exclude extra attributes -X */
503    {
504    if (AllocMemory(argCee, "-X", "Extra", FALSE) != ZE_OK)
505        return ZE_MEM;
506    }
507if (Options.IncludeList != NULL) /* Include file list -i */
508    {
509    if (AllocMemory(argCee, "-i", "Include file list", FALSE) != ZE_OK)
510        return ZE_MEM;
511    k = 0;
512    if (Options.IncludeListCount > 0)
513        while ((Options.IncludeList[k] != NULL) && (Options.IncludeListCount != k+1))
514            {
515            size = _msize(argVee);
516            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
517                {
518                fprintf(stdout, "Unable to allocate memory in zip dll\n");
519                return ZE_MEM;
520                }
521            if (AllocMemory(argCee, Options.IncludeList[k], "Include file list array", TRUE) != ZE_OK)
522                {
523                return ZE_MEM;
524                }
525            k++;
526            }
527    else
528        while (Options.IncludeList[k] != NULL)
529            {
530            size = _msize(argVee);
531            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
532                {
533                FreeArgVee();
534                fprintf(stdout, "Unable to allocate memory in zip dll\n");
535                return ZE_MEM;
536                }
537            if (AllocMemory(argCee, Options.IncludeList[k], "Include file list array", TRUE) != ZE_OK)
538                return ZE_MEM;
539            k++;
540            }
541
542    if (AllocMemory(argCee, "@", "End of Include List", FALSE) != ZE_OK)
543        return ZE_MEM;
544    }
545if (Options.ExcludeList != NULL)  /* Exclude file list -x */
546    {
547    if (AllocMemory(argCee, "-x", "Exclude file list", FALSE) != ZE_OK)
548        return ZE_MEM;
549    k = 0;
550    if (Options.ExcludeListCount > 0)
551        while ((Options.ExcludeList[k] != NULL) && (Options.ExcludeListCount != k+1))
552            {
553            size = _msize(argVee);
554            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
555                {
556                fprintf(stdout, "Unable to allocate memory in zip dll\n");
557                return ZE_MEM;
558                }
559            if (AllocMemory(argCee, Options.ExcludeList[k], "Exclude file list array", TRUE) != ZE_OK)
560                return ZE_MEM;
561            k++;
562            }
563    else
564        while (Options.ExcludeList[k] != NULL)
565            {
566            size = _msize(argVee);
567            if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
568                {
569                FreeArgVee();
570                fprintf(stdout, "Unable to allocate memory in zip dll\n");
571                return ZE_MEM;
572                }
573            if (AllocMemory(argCee, Options.ExcludeList[k], "Exclude file list array", TRUE) != ZE_OK)
574                return ZE_MEM;
575            k++;
576            }
577   if (AllocMemory(argCee, "@", "End of Exclude List", FALSE) != ZE_OK)
578        return ZE_MEM;
579    }
580
581if (szIncludeList != NULL && szIncludeList[0] != '\0') /* Include file list -i */
582    {
583    if (AllocMemory(argCee, "-i", "Include file list", FALSE) != ZE_OK)
584        return ZE_MEM;
585    if ((k = ParseString(szIncludeList, argCee)) != ZE_OK)
586        return k;  /* Something was screwy with the parsed string
587                      bail out */
588    if (AllocMemory(argCee, "@", "End of Include List", FALSE) != ZE_OK)
589        return ZE_MEM;
590    }
591if (szExcludeList != NULL && szExcludeList[0] != '\0')  /* Exclude file list -x */
592    {
593    if (AllocMemory(argCee, "-x", "Exclude file list", FALSE) != ZE_OK)
594        return ZE_MEM;
595
596    if ((k = ParseString(szExcludeList, argCee)) != ZE_OK)
597        return k;  /* Something was screwy with the parsed string
598                      bail out */
599
600    if (AllocMemory(argCee, "@", "End of Exclude List", FALSE) != ZE_OK)
601        return ZE_MEM;
602    }
603
604if ((szTempDir != NULL) && (szTempDir[0] != '\0')
605     && Options.fTemp) /* Use temporary directory -b */
606    {
607    if (AllocMemory(argCee, "-b", "Temp dir switch command", FALSE) != ZE_OK)
608        return ZE_MEM;
609    if (AllocMemory(argCee, szTempDir, "Temporary directory", FALSE) != ZE_OK)
610        return ZE_MEM;
611    }
612
613if (AllocMemory(argCee, C.lpszZipFN, "Zip file name", FALSE) != ZE_OK)
614    return ZE_MEM;
615
616if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
617    {
618    if (szRootDir[lstrlen(szRootDir)-1] != '\\')
619         lstrcat(szRootDir, "\\"); /* append trailing \\ */
620    if (C.FNV != NULL)
621        {
622        for (k = 0; k < C.argc; k++)
623            {
624            if (AllocMemory(argCee, C.FNV[k], "Making argv", FALSE) != ZE_OK)
625                return ZE_MEM;
626            if ((_strnicmp(szRootDir, C.FNV[k], lstrlen(szRootDir))) == 0)
627                {
628                m = 0;
629                for (j = lstrlen(szRootDir); j < lstrlen(C.FNV[k]); j++)
630                    argVee[argCee-1][m++] = C.FNV[k][j];
631                argVee[argCee-1][m] = '\0';
632                }
633            }
634        }
635
636    }
637else
638  if (C.FNV != NULL)
639    for (k = 0; k < C.argc; k++)
640        {
641        if (AllocMemory(argCee, C.FNV[k], "Making argv", FALSE) != ZE_OK)
642            return ZE_MEM;
643        }
644
645if (C.lpszAltFNL != NULL)
646    {
647    if ((k = ParseString(C.lpszAltFNL, argCee)) != ZE_OK)
648        return k;  /* Something was screwy with the parsed string
649                      bail out
650                    */
651    }
652
653
654
655argVee[argCee] = NULL;
656
657ZipRet = zipmain(argCee, argVee);
658
659/* Free the arguments in the array. Note this also restores the
660   current directory
661 */
662FreeArgVee();
663
664return ZipRet;
665}
666
667#if CRYPT
668int encr_passwd(int modeflag, char *pwbuf, int size, const char *zfn)
669    {
670    return (*lpZipUserFunctions->password)(pwbuf, size, ((modeflag == ZP_PW_VERIFY) ?
671                  "Verify password: " : "Enter password: "),
672                  (char *)zfn);
673    }
674#endif /* CRYPT */
675
676void EXPENTRY ZpVersion(ZpVer far * p)   /* should be pointer to const struct */
677    {
678    p->structlen = ZPVER_LEN;
679
680#ifdef BETA
681    p->flag = 1;
682#else
683    p->flag = 0;
684#endif
685#ifdef CRYPT
686    p->fEncryption = TRUE;
687#else
688    p->fEncryption = FALSE;
689#endif
690    lstrcpy(p->betalevel, Z_BETALEVEL);
691    lstrcpy(p->date, REVDATE);
692
693#ifdef ZLIB_VERSION
694    lstrcpy(p->zlib_version, ZLIB_VERSION);
695    p->flag |= 2;
696#else
697    p->zlib_version[0] = '\0';
698#endif
699
700#ifdef ZIP64_SUPPORT
701    p->flag |= 4; /* Flag that ZIP64 was compiled in. */
702#endif
703
704    p->zip.major = Z_MAJORVER;
705    p->zip.minor = Z_MINORVER;
706    p->zip.patchlevel = Z_PATCHLEVEL;
707
708#ifdef OS2
709    p->os2dll.major = D2_MAJORVER;
710    p->os2dll.minor = D2_MINORVER;
711    p->os2dll.patchlevel = D2_PATCHLEVEL;
712#endif
713#ifdef WINDLL
714    p->windll.major = DW_MAJORVER;
715    p->windll.minor = DW_MINORVER;
716    p->windll.patchlevel = DW_PATCHLEVEL;
717#endif
718    }
719