1 /*
2   Copyright (c) 1990-2009 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2009-Jan-02 or later
5   (the contents of which are also included in unzip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /*
10    This is a very simplistic example of how to load and make a call into the
11    dll. This has been compiled and tested for a 32-bit console version, but
12    not under 16-bit windows. However, the #ifdef's have been left in for the
13    16-bit code, simply as an example.
14 
15  */
16 
17 #ifndef WIN32   /* this code is currently only tested for 32-bit console */
18 #  define WIN32
19 #endif
20 
21 #if defined(__WIN32__) && !defined(WIN32)
22 #  define WIN32
23 #endif
24 
25 /* Tell Microsoft Visual C++ 2005 to leave us alone and
26  * let us use standard C functions the way we're supposed to.
27  */
28 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
29 #  ifndef _CRT_SECURE_NO_WARNINGS
30 #    define _CRT_SECURE_NO_WARNINGS
31 #  endif
32 #  ifndef _CRT_NONSTDC_NO_WARNINGS
33 #    define _CRT_NONSTDC_NO_WARNINGS
34 #  endif
35 #endif
36 
37 #include <stddef.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <time.h>
41 #include <string.h>
42 #include "uzexampl.h"
43 #include "../unzvers.h"
44 #ifdef WIN32
45 #  include <winver.h>
46 #else
47 #  include <ver.h>
48 #endif
49 
50 #ifndef _MAX_PATH
51 #  define _MAX_PATH 260           /* max total file or directory name path */
52 #endif
53 
54 #ifdef WIN32
55 #define UNZ_DLL_NAME "UNZIP32.DLL\0"
56 #else
57 #define UNZ_DLL_NAME "UNZIP16.DLL\0"
58 #endif
59 
60 #define DLL_WARNING "Cannot find %s."\
61             " The Dll must be in the application directory, the path, "\
62             "the Windows directory or the Windows System directory."
63 #define DLL_VERSION_WARNING "%s has the wrong version number."\
64             " Insure that you have the correct dll's installed, and that "\
65             "an older dll is not in your path or Windows System directory."
66 
67 int hFile;              /* file handle */
68 
69 LPUSERFUNCTIONS lpUserFunctions;
70 HANDLE hUF = (HANDLE)NULL;
71 LPDCL lpDCL = NULL;
72 HANDLE hDCL = (HANDLE)NULL;
73 HINSTANCE hUnzipDll;
74 HANDLE hZCL = (HANDLE)NULL;
75 #ifdef WIN32
76 DWORD dwPlatformId = 0xFFFFFFFF;
77 #endif
78 static ZCONST UzpVer *lpUzVersInfo = NULL;
79 
80 
81 /* Forward References */
82 int WINAPI DisplayBuf(LPSTR, unsigned long);
83 int WINAPI GetReplaceDlgRetVal(LPSTR, unsigned);
84 int WINAPI password(LPSTR, int, LPCSTR, LPCSTR);
85 
86 ZCONST UzpVer * UZ_EXP UzpVersion  OF((void));
87 _DLL_UZVER pUzpVersion;
88 _DLL_UNZIP pWiz_SingleEntryUnzip;
89 
90 static void FreeUpMemory(void);
91 
main(int argc,char ** argv)92 int main(int argc, char **argv)
93 {
94 int exfc, infc;
95 char **exfv, **infv;
96 char *x_opt;
97 DWORD dwVerInfoSize;
98 DWORD dwVerHnd;
99 char szFullPath[_MAX_PATH];
100 int retcode;
101 #ifdef WIN32
102 char *ptr;
103 #else
104 HFILE hfile;
105 OFSTRUCT ofs;
106 #endif
107 HANDLE  hMem;         /* handle to mem alloc'ed */
108 
109 if (argc < 2)   /* We must have an archive to unzip */
110    {
111    char *progname = strrchr(argv[0], '\\');
112 
113    if (progname != NULL)
114       progname++;
115    else
116       {
117       progname = argv[0];
118       if (progname == NULL || *progname == '\0') progname = "example";
119       }
120    printf("usage: %s <zipfile> [entry1 [entry2 [...]]] [-x xentry1 [...]]",
121           progname);
122    return 0;
123    }
124 
125 hDCL = GlobalAlloc( GPTR, (DWORD)sizeof(DCL));
126 if (!hDCL)
127    {
128    return -1;
129    }
130 lpDCL = (LPDCL)GlobalLock(hDCL);
131 if (!lpDCL)
132    {
133    GlobalFree(hDCL);
134    return -1;
135    }
136 
137 hUF = GlobalAlloc( GPTR, (DWORD)sizeof(USERFUNCTIONS));
138 if (!hUF)
139    {
140    GlobalUnlock(hDCL);
141    GlobalFree(hDCL);
142    return -1;
143    }
144 lpUserFunctions = (LPUSERFUNCTIONS)GlobalLock(hUF);
145 
146 if (!lpUserFunctions)
147    {
148    GlobalFree(hUF);
149    GlobalUnlock(hDCL);
150    GlobalFree(hDCL);
151    return -1;
152    }
153 
154 lpUserFunctions->password = password;
155 lpUserFunctions->print = DisplayBuf;
156 lpUserFunctions->sound = NULL;
157 lpUserFunctions->replace = GetReplaceDlgRetVal;
158 lpUserFunctions->SendApplicationMessage = ReceiveDllMessage;
159 
160 /* First we go look for the unzip dll */
161 #ifdef WIN32
162 if (SearchPath(
163     NULL,               /* address of search path               */
164     UNZ_DLL_NAME,       /* address of filename                  */
165     NULL,               /* address of extension                 */
166     _MAX_PATH,           /* size, in characters, of buffer       */
167     szFullPath,         /* address of buffer for found filename */
168     &ptr                /* address of pointer to file component */
169    ) == 0)
170 #else
171 hfile = OpenFile(UNZ_DLL_NAME,  &ofs, OF_SEARCH);
172 if (hfile == HFILE_ERROR)
173 #endif
174    {
175    char str[256];
176    wsprintf (str, DLL_WARNING, UNZ_DLL_NAME);
177    printf("%s\n", str);
178    FreeUpMemory();
179    return -1;
180    }
181 #ifndef WIN32
182 else
183    lstrcpy(szFullPath, ofs.szPathName);
184 _lclose(hfile);
185 #endif
186 
187 /* Now we'll check the unzip dll version information. Note that this is
188    not the same information as is returned from a call to UzpVersion()
189  */
190 dwVerInfoSize =
191     GetFileVersionInfoSize(szFullPath, &dwVerHnd);
192 
193 if (dwVerInfoSize)
194    {
195    BOOL  fRet, fRetName;
196    char str[256];
197    LPSTR   lpstrVffInfo; /* Pointer to block to hold info */
198    LPSTR lszVer = NULL;
199    LPSTR lszVerName = NULL;
200    UINT  cchVer = 0;
201 
202    /* Get a block big enough to hold the version information */
203    hMem          = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
204    lpstrVffInfo  = GlobalLock(hMem);
205 
206    /* Get the version information */
207    if (GetFileVersionInfo(szFullPath, 0L, dwVerInfoSize, lpstrVffInfo))
208       {
209       fRet = VerQueryValue(lpstrVffInfo,
210                TEXT("\\StringFileInfo\\040904E4\\FileVersion"),
211               (LPVOID)&lszVer,
212               &cchVer);
213       fRetName = VerQueryValue(lpstrVffInfo,
214                TEXT("\\StringFileInfo\\040904E4\\CompanyName"),
215                (LPVOID)&lszVerName,
216                &cchVer);
217       if (!fRet || !fRetName ||
218          (lstrcmpi(lszVer, UNZ_DLL_VERSION) != 0) ||
219          (lstrcmpi(lszVerName, IZ_COMPANY_NAME) != 0))
220          {
221          wsprintf (str, DLL_VERSION_WARNING, UNZ_DLL_NAME);
222          printf("%s\n", str);
223          GlobalUnlock(hMem);
224          GlobalFree(hMem);
225          FreeUpMemory();
226          return -1;
227          }
228       }
229       /* free memory */
230    GlobalUnlock(hMem);
231    GlobalFree(hMem);
232    }
233 else
234    {
235    char str[256];
236    wsprintf (str, DLL_VERSION_WARNING, UNZ_DLL_NAME);
237    printf("%s\n", str);
238    FreeUpMemory();
239    return -1;
240    }
241 /* Okay, now we know that the dll exists, and has the proper version
242  * information in it. We can go ahead and load it.
243  */
244 hUnzipDll = LoadLibrary(UNZ_DLL_NAME);
245 #ifndef WIN32
246 if (hUnzipDll > HINSTANCE_ERROR)
247 #else
248 if (hUnzipDll != NULL)
249 #endif
250    {
251    pUzpVersion =
252      (_DLL_UZVER)GetProcAddress(hUnzipDll, "UzpVersion");
253    pWiz_SingleEntryUnzip =
254      (_DLL_UNZIP)GetProcAddress(hUnzipDll, "Wiz_SingleEntryUnzip");
255    }
256 else
257    {
258    char str[256];
259    wsprintf (str, "Could not load %s", UNZ_DLL_NAME);
260    printf("%s\n", str);
261    FreeUpMemory();
262    return -1;
263    }
264 
265 /*
266    Before we actually start with the extraction process, we should first
267    check whether the API of the loaded dll is compatible with the API
268    definition used to compile this frontend program.
269  */
270 lpUzVersInfo = (*pUzpVersion)();
271 
272 /* The UnZip WinDLL code may change quite frequently.  To be safe, we
273  * require the DLL to be at least at the release level of this example
274  * frontend code.
275  */
276 #   define UZDLL_MINVERS_MAJOR          UZ_MAJORVER
277 #   define UZDLL_MINVERS_MINOR          UZ_MINORVER
278 #   define UZDLL_MINVERS_PATCHLEVEL     UZ_PATCHLEVEL
279 /* This UnZip DLL stub requires a DLL version of at least: */
280 if ( (lpUzVersInfo->unzip.major < UZDLL_MINVERS_MAJOR) ||
281      ((lpUzVersInfo->unzip.major == UZDLL_MINVERS_MAJOR) &&
282       ((lpUzVersInfo->unzip.minor < UZDLL_MINVERS_MINOR) ||
283        ((lpUzVersInfo->unzip.minor == UZDLL_MINVERS_MINOR) &&
284         (lpUzVersInfo->unzip.patchlevel < UZDLL_MINVERS_PATCHLEVEL)
285        )
286       )
287      ) )
288 {
289   char str[256];
290   wsprintf(str, "The version %u.%u%u of the loaded UnZip DLL is too old!",
291            lpUzVersInfo->unzip.major, lpUzVersInfo->unzip.minor,
292            lpUzVersInfo->unzip.patchlevel);
293   printf("%s\n", str);
294   FreeLibrary(hUnzipDll);
295   FreeUpMemory();
296   return -1;
297 }
298 
299 if (lpUzVersInfo->structlen >=
300     (offsetof(UzpVer, dllapimin) + sizeof(_version_type)))
301 {
302   if ( (lpUzVersInfo->dllapimin.major > UZ_WINAPI_COMP_MAJOR) ||
303        ((lpUzVersInfo->dllapimin.major == UZ_WINAPI_COMP_MAJOR) &&
304         ((lpUzVersInfo->dllapimin.minor > UZ_WINAPI_COMP_MINOR) ||
305          ((lpUzVersInfo->dllapimin.minor == UZ_WINAPI_COMP_MINOR) &&
306           (lpUzVersInfo->dllapimin.patchlevel > UZ_WINAPI_COMP_REVIS)
307          )
308         )
309        ) )
310   {
311     char str[256];
312     wsprintf(str, "Found incompatible WinDLL API version %u.%u%u, aborting!",
313              lpUzVersInfo->dllapimin.major, lpUzVersInfo->dllapimin.minor,
314              lpUzVersInfo->dllapimin.patchlevel);
315     printf("%s\n", str);
316     FreeLibrary(hUnzipDll);
317     FreeUpMemory();
318     return -1;
319   }
320 }
321 
322 /*
323    Here is where the actual extraction process begins. First we set up the
324    flags to be passed into the dll.
325  */
326 lpDCL->StructVersID = UZ_DCL_STRUCTVER; /* version of this structure */
327 lpDCL->ncflag = 0;              /* write to stdout if true */
328 lpDCL->fQuiet = 0;              /* we want all messages
329                                    1 = fewer messages,
330                                    2 = no messages */
331 lpDCL->ntflag = 0;              /* test zip file if true */
332 lpDCL->nvflag = 0;              /* give a verbose listing if true */
333 lpDCL->nzflag = 0;              /* display zip file comment if true */
334 lpDCL->ndflag = 1;              /* recreate directories != 0,
335                                    skip "../" if < 2 */
336 lpDCL->naflag = 0;              /* do not convert CR to CRLF */
337 lpDCL->nfflag = 0;              /* do not freshen existing files only */
338 lpDCL->noflag = 1;              /* over-write all files if true */
339 lpDCL->nZIflag = 0;             /* no ZipInfo output mode */
340 lpDCL->B_flag = 0;              /* do not backup existing files */
341 lpDCL->C_flag = 0;              /* do not match case-insensitive */
342 lpDCL->D_flag = 0;              /* restore all timestamps */
343 lpDCL->U_flag = 0;              /* do not disable UTF-8 support */
344 lpDCL->ExtractOnlyNewer = 0;    /* do not extract only newer */
345 lpDCL->SpaceToUnderscore = 0;   /* do not convert space to '_' in filenames */
346 lpDCL->PromptToOverwrite = 0;   /* "overwrite all" selected -> no query mode */
347 lpDCL->lpszZipFN = argv[1];     /* the archive name */
348 lpDCL->lpszExtractDir = NULL;   /* the directory to extract to.
349                                    This is set to NULL if you are extracting
350                                    to the current directory.
351                                  */
352 /*
353    As this is a quite short example, intended primarily to show how to
354    load and call in to the dll, the command-line parameters are only
355    parsed in a very simplistic way:
356    We assume that the command-line parameters after the zip archive
357    make up a list of file patterns:
358    " [file_i1] [file_i2] ... [file_iN] [-x file_x1 [file_x2] ...]".
359    We scan for an argument "-x"; all arguments in front are
360    "include file patterns", all arguments after are "exclude file patterns".
361    If no more arguments are given, we extract ALL files.
362 
363    In summary, the example program should be run like:
364    example <archive.name> [files to include] [-x files to exclude]
365    ("<...> denotes mandatory arguments, "[...]" optional arguments)
366  */
367 x_opt = NULL;
368 if (argc > 2) {
369   infv = &argv[2];
370   for (infc = 0; infc < argc-2; infc++)
371     if (!strcmp("-x", infv[infc])) {
372         x_opt = infv[infc];
373         infv[infc] = NULL;
374         break;
375     }
376   exfc = argc - infc - 3;
377   if (exfc > 0)
378     exfv = &argv[infc+3];
379   else {
380     exfc = 0;
381     exfv = NULL;
382   }
383 } else {
384   infc = exfc = 0;
385   infv = exfv = NULL;
386 }
387 retcode = (*pWiz_SingleEntryUnzip)(infc, infv, exfc, exfv, lpDCL,
388                                    lpUserFunctions);
389 if (x_opt) {
390   infv[infc] = x_opt;
391   x_opt = NULL;
392 }
393 
394 if (retcode != 0)
395    printf("Error unzipping (error/warning code %d)...\n", retcode);
396 
397 FreeLibrary(hUnzipDll);
398 FreeUpMemory();
399 return retcode;
400 }
401 
GetReplaceDlgRetVal(LPSTR filename,unsigned fnbufsiz)402 int WINAPI GetReplaceDlgRetVal(LPSTR filename, unsigned fnbufsiz)
403 {
404 /* This is where you will decide if you want to replace, rename etc existing
405    files.
406  */
407 return 1;
408 }
409 
FreeUpMemory(void)410 static void FreeUpMemory(void)
411 {
412 if (hUF)
413    {
414    GlobalUnlock(hUF);
415    GlobalFree(hUF);
416    }
417 if (hDCL)
418    {
419    GlobalUnlock(hDCL);
420    GlobalFree(hDCL);
421    }
422 }
423 
424 /* This is a very stripped down version of what is done in Wiz. Essentially
425    what this function is for is to do a listing of an archive contents. It
426    is actually never called in this example, but a dummy procedure had to
427    be put in, so this was used.
428  */
429 #ifdef Z_UINT8_DEFINED
ReceiveDllMessage(z_uint8 ucsize,z_uint8 csiz,unsigned cfactor,unsigned mo,unsigned dy,unsigned yr,unsigned hh,unsigned mm,char c,LPCSTR filename,LPCSTR methbuf,unsigned long crc,char fCrypt)430 void WINAPI ReceiveDllMessage(z_uint8 ucsize, z_uint8 csiz,
431     unsigned cfactor, unsigned mo, unsigned dy, unsigned yr,
432     unsigned hh, unsigned mm, char c, LPCSTR filename,
433     LPCSTR methbuf, unsigned long crc, char fCrypt)
434 #else
435 void WINAPI ReceiveDllMessage(unsigned long ucsize, unsigned long csiz,
436     unsigned cfactor,
437     unsigned mo, unsigned dy, unsigned yr, unsigned hh, unsigned mm,
438     char c, LPCSTR filename, LPCSTR methbuf, unsigned long crc, char fCrypt)
439 #endif
440 {
441 char psLBEntry[_MAX_PATH];
442 char LongHdrStats[] =
443           "%7lu  %7lu %4s  %02u-%02u-%02u  %02u:%02u  %c%s";
444 char CompFactorStr[] = "%c%d%%";
445 char CompFactor100[] = "100%%";
446 char szCompFactor[10];
447 char sgn;
448 
449 if (csiz > ucsize)
450    sgn = '-';
451 else
452    sgn = ' ';
453 if (cfactor == 100)
454    lstrcpy(szCompFactor, CompFactor100);
455 else
456    sprintf(szCompFactor, CompFactorStr, sgn, cfactor);
457    wsprintf(psLBEntry, LongHdrStats,
458       ucsize, csiz, szCompFactor, mo, dy, yr, hh, mm, c, filename);
459 
460 printf("%s\n", psLBEntry);
461 }
462 
463 /* Password entry routine - see password.c in the wiz directory for how
464    this is actually implemented in WiZ. If you have an encrypted file,
465    this will probably give you great pain.
466  */
password(LPSTR p,int n,LPCSTR m,LPCSTR name)467 int WINAPI password(LPSTR p, int n, LPCSTR m, LPCSTR name)
468 {
469 return 1;
470 }
471 
472 /* Dummy "print" routine that simply outputs what is sent from the dll */
DisplayBuf(LPSTR buf,unsigned long size)473 int WINAPI DisplayBuf(LPSTR buf, unsigned long size)
474 {
475 printf("%s", (char *)buf);
476 return (int)(unsigned int) size;
477 }
478