1diff -ru2 unz60d10/extract.c unz60d10_w32w/extract.c
2--- unz60d10/extract.c	Thu Dec 27 21:41:40 2007
3+++ unz60d10_w32w/extract.c	Mon Feb 11 02:22:00 2008
4@@ -87,4 +87,11 @@
5 static int store_info OF((__GPRO));
6 #ifdef SET_DIR_ATTRIB
7+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
8+static int extract_or_test_entrylistw OF((__GPRO__ unsigned numchunk,
9+                ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
10+                unsigned *pnum_dirs,
11+                direntryw **pdirlistw,
12+                int error_in_archive));
13+# endif
14 static int extract_or_test_entrylist OF((__GPRO__ unsigned numchunk,
15                 ulg *pfilnum, ulg *pnum_bad_pwd, zoff_t *pold_extra_bytes,
16@@ -112,4 +119,7 @@
17 #endif
18 #ifdef SET_DIR_ATTRIB
19+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
20+   static int Cdecl dircompw OF((ZCONST zvoid *a, ZCONST zvoid *b));
21+# endif
22    static int Cdecl dircomp OF((ZCONST zvoid *a, ZCONST zvoid *b));
23 #endif
24@@ -336,4 +346,7 @@
25 #ifdef SET_DIR_ATTRIB
26     unsigned num_dirs=0;
27+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
28+    direntryw *dirlistw=(direntryw *)NULL, **sorted_dirlistw=(direntryw **)NULL;
29+#endif
30     direntry *dirlist=(direntry *)NULL, **sorted_dirlist=(direntry **)NULL;
31 #endif
32@@ -356,8 +369,25 @@
33     if (uO.exdir != (char *)NULL && G.extract_flag) {
34         G.create_dirs = !uO.fflag;
35+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
36+        if (G.has_win32_wide) {
37+          wchar_t *exdirw = local_to_wchar_string(uO.exdir);
38+          if ((error = checkdirw(exdirw, ROOT)) > MPN_INF_SKIP) {
39+              /* out of memory, or file in way */
40+              free(exdirw);
41+              return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
42+          }
43+          free(exdirw);
44+        } else {
45+          if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) {
46+              /* out of memory, or file in way */
47+              return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
48+          }
49+        }
50+# else /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
51         if ((error = checkdir(__G__ uO.exdir, ROOT)) > MPN_INF_SKIP) {
52             /* out of memory, or file in way */
53             return (error == MPN_NOMEM ? PK_MEM : PK_ERR);
54         }
55+# endif /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
56     }
57 #endif /* !SFX || SFX_EXDIR */
58@@ -570,5 +600,18 @@
59       -----------------------------------------------------------------------*/
60 
61-        error = extract_or_test_entrylist(__G__ j,
62+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
63+        if (G.has_win32_wide)
64+        {
65+          error = extract_or_test_entrylistw(__G__ j,
66+                        &filnum, &num_bad_pwd, &old_extra_bytes,
67+# ifdef SET_DIR_ATTRIB
68+                        &num_dirs, &dirlistw,
69+# endif
70+                        error_in_archive);
71+        }
72+        else
73+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
74+        {
75+          error = extract_or_test_entrylist(__G__ j,
76                         &filnum, &num_bad_pwd, &old_extra_bytes,
77 #ifdef SET_DIR_ATTRIB
78@@ -576,4 +619,5 @@
79 #endif
80                         error_in_archive);
81+        }
82         if (error != PK_COOL) {
83             if (error > error_in_archive)
84@@ -643,4 +687,55 @@
85 #ifdef SET_DIR_ATTRIB
86     if (num_dirs > 0) {
87+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
88+      if (G.has_win32_wide) {
89+        sorted_dirlistw = (direntryw **)malloc(num_dirs*sizeof(direntryw *));
90+        if (sorted_dirlistw == (direntryw **)NULL) {
91+            Info(slide, 0x401, ((char *)slide,
92+              LoadFarString(DirlistSortNoMem)));
93+            while (dirlistw != (direntryw *)NULL) {
94+                direntryw *dw = dirlistw;
95+
96+                dirlistw = dirlistw->next;
97+                free(dw);
98+            }
99+        } else {
100+            ulg ndirs_fail = 0;
101+
102+            if (num_dirs == 1)
103+                sorted_dirlistw[0] = dirlistw;
104+            else {
105+                for (i = 0;  i < num_dirs;  ++i) {
106+                    sorted_dirlistw[i] = dirlistw;
107+                    dirlistw = dirlistw->next;
108+                }
109+                qsort((char *)sorted_dirlistw, num_dirs, sizeof(direntryw *),
110+                  dircompw);
111+            }
112+
113+            Trace((stderr, "setting directory times/perms/attributes\n"));
114+            for (i = 0;  i < num_dirs;  ++i) {
115+                direntryw *dw = sorted_dirlistw[i];
116+
117+                Trace((stderr, "dir = %s\n", dw->fn));
118+                if ((error = set_direc_attribsw(__G__ dw)) != PK_OK) {
119+                    ndirs_fail++;
120+                    Info(slide, 0x201, ((char *)slide,
121+                      LoadFarString(DirlistSetAttrFailed), dw->fnw));
122+                    if (!error_in_archive)
123+                        error_in_archive = error;
124+                }
125+                free(dw);
126+            }
127+            free(sorted_dirlistw);
128+            if (!uO.tflag && QCOND2) {
129+                if (ndirs_fail > 0)
130+                    Info(slide, 0, ((char *)slide,
131+                      LoadFarString(DirlistFailAttrSum), ndirs_fail));
132+            }
133+        }
134+      }
135+      else
136+# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
137+      {
138         sorted_dirlist = (direntry **)malloc(num_dirs*sizeof(direntry *));
139         if (sorted_dirlist == (direntry **)NULL) {
140@@ -688,4 +783,5 @@
141             }
142         }
143+      }
144     }
145 #endif /* SET_DIR_ATTRIB */
146@@ -821,190 +917,731 @@
147 #endif
148 
149-#ifdef USE_WAVP
150-#  define UNKN_WAVP (G.crec.compression_method!=WAVPACKED)
151-#else
152-#  define UNKN_WAVP TRUE      /* WavPack unknown */
153+#ifdef USE_WAVP
154+#  define UNKN_WAVP (G.crec.compression_method!=WAVPACKED)
155+#else
156+#  define UNKN_WAVP TRUE      /* WavPack unknown */
157+#endif
158+
159+#ifdef USE_PPMD
160+#  define UNKN_PPMD (G.crec.compression_method!=PPMDED)
161+#else
162+#  define UNKN_PPMD TRUE      /* PPMd unknown */
163+#endif
164+
165+#ifdef SFX
166+#  ifdef USE_DEFLATE64
167+#    define UNKN_COMPR \
168+     (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
169+      && G.crec.compression_method>ENHDEFLATED \
170+      && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
171+#  else
172+#    define UNKN_COMPR \
173+     (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\
174+      && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
175+#  endif
176+#else
177+#  ifdef COPYRIGHT_CLEAN  /* no reduced files */
178+#    define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
179+                      G.crec.compression_method <= REDUCED4)
180+#  else
181+#    define UNKN_RED  FALSE  /* reducing not unknown */
182+#  endif
183+#  ifdef LZW_CLEAN  /* no shrunk files */
184+#    define UNKN_SHR (G.crec.compression_method == SHRUNK)
185+#  else
186+#    define UNKN_SHR  FALSE  /* unshrinking not unknown */
187+#  endif
188+#  ifdef USE_DEFLATE64
189+#    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
190+     G.crec.compression_method==TOKENIZED || \
191+     (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \
192+      && UNKN_WAVP && UNKN_PPMD))
193+#  else
194+#    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
195+     G.crec.compression_method==TOKENIZED || \
196+     (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \
197+      && UNKN_WAVP && UNKN_PPMD))
198+#  endif
199+#endif
200+
201+#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS))
202+    int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS);
203+#   define UNZVERS_SUPPORT  unzvers_support
204+#else
205+#   define UNZVERS_SUPPORT  UNZIP_VERSION
206+#endif
207+
208+/*---------------------------------------------------------------------------
209+    Check central directory info for version/compatibility requirements.
210+  ---------------------------------------------------------------------------*/
211+
212+    G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1;   /* bit field */
213+    G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8;  /* bit */
214+    G.pInfo->textfile = G.crec.internal_file_attributes & 1;    /* bit field */
215+    G.pInfo->crc = G.crec.crc32;
216+    G.pInfo->compr_size = G.crec.csize;
217+    G.pInfo->uncompr_size = G.crec.ucsize;
218+
219+    switch (uO.aflag) {
220+        case 0:
221+            G.pInfo->textmode = FALSE;   /* bit field */
222+            break;
223+        case 1:
224+            G.pInfo->textmode = G.pInfo->textfile;   /* auto-convert mode */
225+            break;
226+        default:  /* case 2: */
227+            G.pInfo->textmode = TRUE;
228+            break;
229+    }
230+
231+    if (G.crec.version_needed_to_extract[1] == VMS_) {
232+        if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
233+            if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
234+                Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
235+                  FnFilter1(G.filename), "VMS",
236+                  G.crec.version_needed_to_extract[0] / 10,
237+                  G.crec.version_needed_to_extract[0] % 10,
238+                  VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
239+            return 0;
240+        }
241+#ifndef VMS   /* won't be able to use extra field, but still have data */
242+        else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */
243+            Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
244+              FnFilter1(G.filename)));
245+            fgets(G.answerbuf, 9, stdin);
246+            if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
247+                return 0;
248+        }
249+#endif /* !VMS */
250+    /* usual file type:  don't need VMS to extract */
251+    } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) {
252+        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
253+            Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
254+              FnFilter1(G.filename), "PK",
255+              G.crec.version_needed_to_extract[0] / 10,
256+              G.crec.version_needed_to_extract[0] % 10,
257+              UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10));
258+        return 0;
259+    }
260+
261+    if (UNKN_COMPR) {
262+        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
263+#ifndef SFX
264+            unsigned cmpridx;
265+
266+            if ((cmpridx = find_compr_idx(G.crec.compression_method))
267+                < NUM_METHODS)
268+                Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
269+                  FnFilter1(G.filename),
270+                  LoadFarStringSmall(ComprNames[cmpridx])));
271+            else
272+#endif
273+                Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
274+                  FnFilter1(G.filename),
275+                  G.crec.compression_method));
276+        }
277+        return 0;
278+    }
279+#if (!CRYPT)
280+    if (G.pInfo->encrypted) {
281+        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
282+            Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
283+              FnFilter1(G.filename)));
284+        return 0;
285+    }
286+#endif /* !CRYPT */
287+
288+#ifndef SFX
289+    /* store a copy of the central header filename for later comparison */
290+    if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) {
291+        Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName),
292+          FnFilter1(G.filename)));
293+    } else
294+        zfstrcpy(G.pInfo->cfilname, G.filename);
295+#endif /* !SFX */
296+
297+    /* map whatever file attributes we have into the local format */
298+    mapattr(__G);   /* GRR:  worry about return value later */
299+
300+    G.pInfo->diskstart = G.crec.disk_number_start;
301+    G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header;
302+    return 1;
303+
304+} /* end function store_info() */
305+
306+
307+
308+
309+
310+#ifndef SFX
311+/*******************************/
312+/*  Function find_compr_idx()  */
313+/*******************************/
314+
315+unsigned find_compr_idx(compr_methodnum)
316+    unsigned compr_methodnum;
317+{
318+   unsigned i;
319+
320+   for (i = 0; i < NUM_METHODS; i++) {
321+      if (ComprIDs[i] == compr_methodnum) break;
322+   }
323+   return i;
324+}
325+#endif /* !SFX */
326+
327+
328+
329+
330+
331+/******************************************/
332+/*  Function extract_or_test_entrylist()  */
333+/******************************************/
334+
335+static int extract_or_test_entrylist(__G__ numchunk,
336+                pfilnum, pnum_bad_pwd, pold_extra_bytes,
337+#ifdef SET_DIR_ATTRIB
338+                pnum_dirs, pdirlist,
339+#endif
340+                error_in_archive)    /* return PK-type error code */
341+    __GDEF
342+    unsigned numchunk;
343+    ulg *pfilnum;
344+    ulg *pnum_bad_pwd;
345+    zoff_t *pold_extra_bytes;
346+#ifdef SET_DIR_ATTRIB
347+    unsigned *pnum_dirs;
348+    direntry **pdirlist;
349+#endif
350+    int error_in_archive;
351+{
352+    unsigned i;
353+    int renamed, query;
354+    int skip_entry;
355+    zoff_t bufstart, inbuf_offset, request;
356+    int error, errcode;
357+
358+/* possible values for local skip_entry flag: */
359+#define SKIP_NO         0       /* do not skip this entry */
360+#define SKIP_Y_EXISTING 1       /* skip this entry, do not overwrite file */
361+#define SKIP_Y_NONEXIST 2       /* skip this entry, do not create new file */
362+
363+    /*-----------------------------------------------------------------------
364+        Second loop:  process files in current block, extracting or testing
365+        each one.
366+      -----------------------------------------------------------------------*/
367+
368+    for (i = 0; i < numchunk; ++i) {
369+        (*pfilnum)++;   /* *pfilnum = i + blknum*DIR_BLKSIZ + 1; */
370+        G.pInfo = &G.info[i];
371+#ifdef NOVELL_BUG_FAILSAFE
372+        G.dne = FALSE;  /* assume file exists until stat() says otherwise */
373+#endif
374+
375+        /* if the target position is not within the current input buffer
376+         * (either haven't yet read far enough, or (maybe) skipping back-
377+         * ward), skip to the target position and reset readbuf(). */
378+
379+        /* seek_zipf(__G__ pInfo->offset);  */
380+        request = G.pInfo->offset + G.extra_bytes;
381+        inbuf_offset = request % INBUFSIZ;
382+        bufstart = request - inbuf_offset;
383+
384+        Trace((stderr, "\ndebug: request = %ld, inbuf_offset = %ld\n",
385+          (long)request, (long)inbuf_offset));
386+        Trace((stderr,
387+          "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
388+          (long)bufstart, (long)G.cur_zipfile_bufstart));
389+        if (request < 0) {
390+            Info(slide, 0x401, ((char *)slide, LoadFarStringSmall(SeekMsg),
391+              G.zipfn, LoadFarString(ReportMsg)));
392+            error_in_archive = PK_ERR;
393+            if (*pfilnum == 1 && G.extra_bytes != 0L) {
394+                Info(slide, 0x401, ((char *)slide,
395+                  LoadFarString(AttemptRecompensate)));
396+                *pold_extra_bytes = G.extra_bytes;
397+                G.extra_bytes = 0L;
398+                request = G.pInfo->offset;  /* could also check if != 0 */
399+                inbuf_offset = request % INBUFSIZ;
400+                bufstart = request - inbuf_offset;
401+                Trace((stderr, "debug: request = %ld, inbuf_offset = %ld\n",
402+                  (long)request, (long)inbuf_offset));
403+                Trace((stderr,
404+                  "debug: bufstart = %ld, cur_zipfile_bufstart = %ld\n",
405+                  (long)bufstart, (long)G.cur_zipfile_bufstart));
406+                /* try again */
407+                if (request < 0) {
408+                    Trace((stderr,
409+                      "debug: recompensated request still < 0\n"));
410+                    Info(slide, 0x401, ((char *)slide,
411+                      LoadFarStringSmall(SeekMsg),
412+                      G.zipfn, LoadFarString(ReportMsg)));
413+                    error_in_archive = PK_BADERR;
414+                    continue;
415+                }
416+            } else {
417+                error_in_archive = PK_BADERR;
418+                continue;  /* this one hosed; try next */
419+            }
420+        }
421+
422+        if (bufstart != G.cur_zipfile_bufstart) {
423+            Trace((stderr, "debug: bufstart != cur_zipfile_bufstart\n"));
424+#ifdef USE_STRM_INPUT
425+            zfseeko(G.zipfd, bufstart, SEEK_SET);
426+            G.cur_zipfile_bufstart = zftello(G.zipfd);
427+#else /* !USE_STRM_INPUT */
428+            G.cur_zipfile_bufstart =
429+              zlseek(G.zipfd, bufstart, SEEK_SET);
430+#endif /* ?USE_STRM_INPUT */
431+            if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
432+            {
433+                Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
434+                  *pfilnum, "lseek", (long)bufstart));
435+                error_in_archive = PK_BADERR;
436+                continue;   /* can still do next file */
437+            }
438+            G.inptr = G.inbuf + (int)inbuf_offset;
439+            G.incnt -= (int)inbuf_offset;
440+        } else {
441+            G.incnt += (int)(G.inptr-G.inbuf) - (int)inbuf_offset;
442+            G.inptr = G.inbuf + (int)inbuf_offset;
443+        }
444+
445+        /* should be in proper position now, so check for sig */
446+        if (readbuf(__G__ G.sig, 4) == 0) {  /* bad offset */
447+            Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
448+              *pfilnum, "EOF", (long)request));
449+            error_in_archive = PK_BADERR;
450+            continue;   /* but can still try next one */
451+        }
452+        if (strncmp(G.sig, local_hdr_sig, 4)) {
453+            Info(slide, 0x401, ((char *)slide, LoadFarString(OffsetMsg),
454+              *pfilnum, LoadFarStringSmall(LocalHdrSig), (long)request));
455+            /*
456+                GRRDUMP(G.sig, 4)
457+                GRRDUMP(local_hdr_sig, 4)
458+             */
459+            error_in_archive = PK_ERR;
460+            if ((*pfilnum == 1 && G.extra_bytes != 0L) ||
461+                (G.extra_bytes == 0L && *pold_extra_bytes != 0L)) {
462+                Info(slide, 0x401, ((char *)slide,
463+                  LoadFarString(AttemptRecompensate)));
464+                if (G.extra_bytes) {
465+                    *pold_extra_bytes = G.extra_bytes;
466+                    G.extra_bytes = 0L;
467+                } else
468+                    G.extra_bytes = *pold_extra_bytes; /* third attempt */
469+                if (((error = seek_zipf(__G__ G.pInfo->offset)) != PK_OK) ||
470+                    (readbuf(__G__ G.sig, 4) == 0)) {  /* bad offset */
471+                    if (error != PK_BADERR)
472+                      Info(slide, 0x401, ((char *)slide,
473+                        LoadFarString(OffsetMsg), *pfilnum, "EOF",
474+                        (long)request));
475+                    error_in_archive = PK_BADERR;
476+                    continue;   /* but can still try next one */
477+                }
478+                if (strncmp(G.sig, local_hdr_sig, 4)) {
479+                    Info(slide, 0x401, ((char *)slide,
480+                      LoadFarString(OffsetMsg), *pfilnum,
481+                      LoadFarStringSmall(LocalHdrSig), (long)request));
482+                    error_in_archive = PK_BADERR;
483+                    continue;
484+                }
485+            } else
486+                continue;  /* this one hosed; try next */
487+        }
488+        if ((error = process_local_file_hdr(__G)) != PK_COOL) {
489+            Info(slide, 0x421, ((char *)slide, LoadFarString(BadLocalHdr),
490+              *pfilnum));
491+            error_in_archive = error;   /* only PK_EOF defined */
492+            continue;   /* can still try next one */
493+        }
494+        if ((error = do_string(__G__ G.lrec.filename_length, DS_FN_L)) !=
495+             PK_COOL)
496+        {
497+            if (error > error_in_archive)
498+                error_in_archive = error;
499+            if (error > PK_WARN) {
500+                Info(slide, 0x401, ((char *)slide, LoadFarString(FilNamMsg),
501+                  FnFilter1(G.filename), "local"));
502+                continue;   /* go on to next one */
503+            }
504+        }
505+        if (G.extra_field != (uch *)NULL) {
506+            free(G.extra_field);
507+            G.extra_field = (uch *)NULL;
508+        }
509+        if ((error =
510+             do_string(__G__ G.lrec.extra_field_length, EXTRA_FIELD)) != 0)
511+        {
512+            if (error > error_in_archive)
513+                error_in_archive = error;
514+            if (error > PK_WARN) {
515+                Info(slide, 0x401, ((char *)slide,
516+                  LoadFarString(ExtFieldMsg),
517+                  FnFilter1(G.filename), "local"));
518+                continue;   /* go on */
519+            }
520+        }
521+#ifndef SFX
522+        /* Filename consistency checks must come after reading in the local
523+         * extra field, so that a UTF-8 entry name e.f. block has already
524+         * been processed.
525+         */
526+        if (G.pInfo->cfilname != (char Far *)NULL) {
527+            if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) {
528+#  ifdef SMALL_MEM
529+                char *temp_cfilnam = slide + (7 * (WSIZE>>3));
530+
531+                zfstrcpy((char Far *)temp_cfilnam, G.pInfo->cfilname);
532+#    define  cFile_PrintBuf  temp_cfilnam
533+#  else
534+#    define  cFile_PrintBuf  G.pInfo->cfilname
535+#  endif
536+                Info(slide, 0x401, ((char *)slide,
537+                  LoadFarStringSmall2(LvsCFNamMsg),
538+                  FnFilter2(cFile_PrintBuf), FnFilter1(G.filename)));
539+#  undef    cFile_PrintBuf
540+                zfstrcpy(G.filename, G.pInfo->cfilname);
541+                if (error_in_archive < PK_WARN)
542+                    error_in_archive = PK_WARN;
543+            }
544+            zffree(G.pInfo->cfilname);
545+            G.pInfo->cfilname = (char Far *)NULL;
546+        }
547+#endif /* !SFX */
548+        /* Size consistency checks must come after reading in the local extra
549+         * field, so that any Zip64 extension local e.f. block has already
550+         * been processed.
551+         */
552+        if (G.lrec.compression_method == STORED) {
553+            zusz_t csiz_decrypted = G.lrec.csize;
554+
555+            if (G.pInfo->encrypted)
556+                csiz_decrypted -= 12;
557+            if (G.lrec.ucsize != csiz_decrypted) {
558+                Info(slide, 0x401, ((char *)slide,
559+                  LoadFarStringSmall2(WrnStorUCSizCSizDiff),
560+                  FnFilter1(G.filename),
561+                  FmZofft(G.lrec.ucsize, NULL, "u"),
562+                  FmZofft(csiz_decrypted, NULL, "u")));
563+                G.lrec.ucsize = csiz_decrypted;
564+                if (error_in_archive < PK_WARN)
565+                    error_in_archive = PK_WARN;
566+            }
567+        }
568+
569+#if CRYPT
570+        if (G.pInfo->encrypted &&
571+            (error = decrypt(__G__ uO.pwdarg)) != PK_COOL) {
572+            if (error == PK_WARN) {
573+                if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
574+                    Info(slide, 0x401, ((char *)slide,
575+                      LoadFarString(SkipIncorrectPasswd),
576+                      FnFilter1(G.filename)));
577+                ++(*pnum_bad_pwd);
578+            } else {  /* (error > PK_WARN) */
579+                if (error > error_in_archive)
580+                    error_in_archive = error;
581+                Info(slide, 0x401, ((char *)slide,
582+                  LoadFarString(SkipCannotGetPasswd),
583+                  FnFilter1(G.filename)));
584+            }
585+            continue;   /* go on to next file */
586+        }
587+#endif /* CRYPT */
588+
589+        /*
590+         * just about to extract file:  if extracting to disk, check if
591+         * already exists, and if so, take appropriate action according to
592+         * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
593+         * loop because we don't store the possibly renamed filename[] in
594+         * info[])
595+         */
596+#ifdef DLL
597+        if (!uO.tflag && !uO.cflag && !G.redirect_data)
598+#else
599+        if (!uO.tflag && !uO.cflag)
600+#endif
601+        {
602+            renamed = FALSE;   /* user hasn't renamed output file yet */
603+
604+startover:
605+            query = FALSE;
606+            skip_entry = SKIP_NO;
607+            /* for files from DOS FAT, check for use of backslash instead
608+             *  of slash as directory separator (bug in some zipper(s); so
609+             *  far, not a problem in HPFS, NTFS or VFAT systems)
610+             */
611+#ifndef SFX
612+            if (G.pInfo->hostnum == FS_FAT_ && !MBSCHR(G.filename, '/')) {
613+                char *p=G.filename;
614+
615+                if (*p) do {
616+                    if (*p == '\\') {
617+                        if (!G.reported_backslash) {
618+                            Info(slide, 0x21, ((char *)slide,
619+                              LoadFarString(BackslashPathSep), G.zipfn));
620+                            G.reported_backslash = TRUE;
621+                            if (!error_in_archive)
622+                                error_in_archive = PK_WARN;
623+                        }
624+                        *p = '/';
625+                    }
626+                } while (*PREINCSTR(p));
627+            }
628+#endif /* !SFX */
629+
630+            if (!renamed) {
631+               /* remove absolute path specs */
632+               if (G.filename[0] == '/') {
633+                   Info(slide, 0x401, ((char *)slide,
634+                        LoadFarString(AbsolutePathWarning),
635+                        FnFilter1(G.filename)));
636+                   if (!error_in_archive)
637+                       error_in_archive = PK_WARN;
638+                   do {
639+                       char *p = G.filename + 1;
640+                       do {
641+                           *(p-1) = *p;
642+                       } while (*p++ != '\0');
643+                   } while (G.filename[0] == '/');
644+               }
645+            }
646+
647+            /* mapname can create dirs if not freshening or if renamed */
648+            error = mapname(__G__ renamed);
649+            if ((errcode = error & ~MPN_MASK) != PK_OK &&
650+                error_in_archive < errcode)
651+                error_in_archive = errcode;
652+            if ((errcode = error & MPN_MASK) > MPN_INF_TRUNC) {
653+                if (errcode == MPN_CREATED_DIR) {
654+#ifdef SET_DIR_ATTRIB
655+                    direntry *d_entry;
656+
657+                    error = defer_dir_attribs(__G__ &d_entry);
658+                    if (d_entry == (direntry *)NULL) {
659+                        /* There may be no dir_attribs info available, or
660+                         * we have encountered a mem allocation error.
661+                         * In case of an error, report it and set program
662+                         * error state to warning level.
663+                         */
664+                        if (error) {
665+                            Info(slide, 0x401, ((char *)slide,
666+                                 LoadFarString(DirlistEntryNoMem)));
667+                            if (!error_in_archive)
668+                                error_in_archive = PK_WARN;
669+                        }
670+                    } else {
671+                        d_entry->next = (*pdirlist);
672+                        (*pdirlist) = d_entry;
673+                        ++(*pnum_dirs);
674+                    }
675+#endif /* SET_DIR_ATTRIB */
676+                } else if (errcode == MPN_VOL_LABEL) {
677+#ifdef DOS_OS2_W32
678+                    Info(slide, 0x401, ((char *)slide,
679+                      LoadFarString(SkipVolumeLabel),
680+                      FnFilter1(G.filename),
681+                      uO.volflag? "hard disk " : ""));
682+#else
683+                    Info(slide, 1, ((char *)slide,
684+                      LoadFarString(SkipVolumeLabel),
685+                      FnFilter1(G.filename), ""));
686+#endif
687+                } else if (errcode > MPN_INF_SKIP &&
688+                           error_in_archive < PK_ERR)
689+                    error_in_archive = PK_ERR;
690+                Trace((stderr, "mapname(%s) returns error code = %d\n",
691+                  FnFilter1(G.filename), error));
692+                continue;   /* go on to next file */
693+            }
694+
695+#ifdef QDOS
696+            QFilename(__G__ G.filename);
697+#endif
698+            switch (check_for_newer(__G__ G.filename)) {
699+                case DOES_NOT_EXIST:
700+#ifdef NOVELL_BUG_FAILSAFE
701+                    G.dne = TRUE;   /* stat() says file DOES NOT EXIST */
702+#endif
703+                    /* freshen (no new files): skip unless just renamed */
704+                    if (uO.fflag && !renamed)
705+                        skip_entry = SKIP_Y_NONEXIST;
706+                    break;
707+                case EXISTS_AND_OLDER:
708+#ifdef UNIXBACKUP
709+                    if (!uO.B_flag)
710+#endif
711+                    {
712+                        if (IS_OVERWRT_NONE)
713+                            /* never overwrite:  skip file */
714+                            skip_entry = SKIP_Y_EXISTING;
715+                        else if (!IS_OVERWRT_ALL)
716+                            query = TRUE;
717+                    }
718+                    break;
719+                case EXISTS_AND_NEWER:             /* (or equal) */
720+#ifdef UNIXBACKUP
721+                    if ((!uO.B_flag && IS_OVERWRT_NONE) ||
722+#else
723+                    if (IS_OVERWRT_NONE ||
724+#endif
725+                        (uO.uflag && !renamed)) {
726+                        /* skip if update/freshen & orig name */
727+                        skip_entry = SKIP_Y_EXISTING;
728+                    } else {
729+#ifdef UNIXBACKUP
730+                        if (!IS_OVERWRT_ALL && !uO.B_flag)
731+#else
732+                        if (!IS_OVERWRT_ALL)
733+#endif
734+                            query = TRUE;
735+                    }
736+                    break;
737+                }
738+            if (query) {
739+#ifdef WINDLL
740+                switch (G.lpUserFunctions->replace != NULL ?
741+                        (*G.lpUserFunctions->replace)(G.filename) :
742+                        IDM_REPLACE_NONE) {
743+                    case IDM_REPLACE_RENAME:
744+                        _ISO_INTERN(G.filename);
745+                        renamed = TRUE;
746+                        goto startover;
747+                    case IDM_REPLACE_ALL:
748+                        G.overwrite_mode = OVERWRT_ALWAYS;
749+                        /* FALL THROUGH, extract */
750+                    case IDM_REPLACE_YES:
751+                        break;
752+                    case IDM_REPLACE_NONE:
753+                        G.overwrite_mode = OVERWRT_NEVER;
754+                        /* FALL THROUGH, skip */
755+                    case IDM_REPLACE_NO:
756+                        skip_entry = SKIP_Y_EXISTING;
757+                        break;
758+                }
759+#else /* !WINDLL */
760+                extent fnlen;
761+reprompt:
762+                Info(slide, 0x81, ((char *)slide,
763+                  LoadFarString(ReplaceQuery),
764+                  FnFilter1(G.filename)));
765+                if (fgets(G.answerbuf, 9, stdin) == (char *)NULL) {
766+                    Info(slide, 1, ((char *)slide,
767+                      LoadFarString(AssumeNone)));
768+                    *G.answerbuf = 'N';
769+                    if (!error_in_archive)
770+                        error_in_archive = 1;  /* not extracted:  warning */
771+                }
772+                switch (*G.answerbuf) {
773+                    case 'r':
774+                    case 'R':
775+                        do {
776+                            Info(slide, 0x81, ((char *)slide,
777+                              LoadFarString(NewNameQuery)));
778+                            fgets(G.filename, FILNAMSIZ, stdin);
779+                            /* usually get \n here:  better check for it */
780+                            fnlen = strlen(G.filename);
781+                            if (lastchar(G.filename, fnlen) == '\n')
782+                                G.filename[--fnlen] = '\0';
783+                        } while (fnlen == 0);
784+#ifdef WIN32  /* WIN32 fgets( ... , stdin) returns OEM coded strings */
785+                        _OEM_INTERN(G.filename);
786+#endif
787+                        renamed = TRUE;
788+                        goto startover;   /* sorry for a goto */
789+                    case 'A':   /* dangerous option:  force caps */
790+                        G.overwrite_mode = OVERWRT_ALWAYS;
791+                        /* FALL THROUGH, extract */
792+                    case 'y':
793+                    case 'Y':
794+                        break;
795+                    case 'N':
796+                        G.overwrite_mode = OVERWRT_NEVER;
797+                        /* FALL THROUGH, skip */
798+                    case 'n':
799+                        /* skip file */
800+                        skip_entry = SKIP_Y_EXISTING;
801+                        break;
802+                    case '\n':
803+                    case '\r':
804+                        /* Improve echo of '\n' and/or '\r'
805+                           (sizeof(G.answerbuf) == 10 (see globals.h), so
806+                           there is enough space for the provided text...) */
807+                        strcpy(G.answerbuf, "{ENTER}");
808+                        /* fall through ... */
809+                    default:
810+                        Info(slide, 1, ((char *)slide,
811+                          LoadFarString(InvalidResponse), *G.answerbuf));
812+                        goto reprompt;   /* yet another goto? */
813+                } /* end switch (*answerbuf) */
814+#endif /* ?WINDLL */
815+            } /* end if (query) */
816+            if (skip_entry != SKIP_NO) {
817+#ifdef WINDLL
818+                if (skip_entry == SKIP_Y_EXISTING) {
819+                    /* report skipping of an existing entry */
820+                    Info(slide, 0, ((char *)slide,
821+                      ((IS_OVERWRT_NONE || !uO.uflag || renamed) ?
822+                       "Target file exists.\nSkipping %s\n" :
823+                       "Target file newer.\nSkipping %s\n"),
824+                      FnFilter1(G.filename)));
825+                }
826+#endif /* WINDLL */
827+                continue;
828+            }
829+        } /* end if (extracting to disk) */
830+
831+#ifdef DLL
832+        if ((G.statreportcb != NULL) &&
833+            (*G.statreportcb)(__G__ UZ_ST_START_EXTRACT, G.zipfn,
834+                              G.filename, NULL)) {
835+            return IZ_CTRLC;        /* cancel operation by user request */
836+        }
837 #endif
838-
839-#ifdef USE_PPMD
840-#  define UNKN_PPMD (G.crec.compression_method!=PPMDED)
841-#else
842-#  define UNKN_PPMD TRUE      /* PPMd unknown */
843+#ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand */
844+        UserStop();
845 #endif
846-
847-#ifdef SFX
848-#  ifdef USE_DEFLATE64
849-#    define UNKN_COMPR \
850-     (G.crec.compression_method!=STORED && G.crec.compression_method<DEFLATED \
851-      && G.crec.compression_method>ENHDEFLATED \
852-      && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
853-#  else
854-#    define UNKN_COMPR \
855-     (G.crec.compression_method!=STORED && G.crec.compression_method!=DEFLATED\
856-      && UNKN_BZ2 && UNKN_LZMA && UNKN_WAVP && UNKN_PPMD)
857-#  endif
858-#else
859-#  ifdef COPYRIGHT_CLEAN  /* no reduced files */
860-#    define UNKN_RED (G.crec.compression_method >= REDUCED1 && \
861-                      G.crec.compression_method <= REDUCED4)
862-#  else
863-#    define UNKN_RED  FALSE  /* reducing not unknown */
864-#  endif
865-#  ifdef LZW_CLEAN  /* no shrunk files */
866-#    define UNKN_SHR (G.crec.compression_method == SHRUNK)
867-#  else
868-#    define UNKN_SHR  FALSE  /* unshrinking not unknown */
869-#  endif
870-#  ifdef USE_DEFLATE64
871-#    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
872-     G.crec.compression_method==TOKENIZED || \
873-     (G.crec.compression_method>ENHDEFLATED && UNKN_BZ2 && UNKN_LZMA \
874-      && UNKN_WAVP && UNKN_PPMD))
875-#  else
876-#    define UNKN_COMPR (UNKN_RED || UNKN_SHR || \
877-     G.crec.compression_method==TOKENIZED || \
878-     (G.crec.compression_method>DEFLATED && UNKN_BZ2 && UNKN_LZMA \
879-      && UNKN_WAVP && UNKN_PPMD))
880-#  endif
881+#ifdef AMIGA
882+        G.filenote_slot = i;
883 #endif
884-
885-#if (defined(USE_BZIP2) && (UNZIP_VERSION < UNZIP_BZ2VERS))
886-    int unzvers_support = (UNKN_BZ2 ? UNZIP_VERSION : UNZIP_BZ2VERS);
887-#   define UNZVERS_SUPPORT  unzvers_support
888+        G.disk_full = 0;
889+        if ((error = extract_or_test_member(__G)) != PK_COOL) {
890+            if (error > error_in_archive)
891+                error_in_archive = error;       /* ...and keep going */
892+#ifdef DLL
893+            if (G.disk_full > 1 || error_in_archive == IZ_CTRLC) {
894 #else
895-#   define UNZVERS_SUPPORT  UNZIP_VERSION
896+            if (G.disk_full > 1) {
897 #endif
898-
899-/*---------------------------------------------------------------------------
900-    Check central directory info for version/compatibility requirements.
901-  ---------------------------------------------------------------------------*/
902-
903-    G.pInfo->encrypted = G.crec.general_purpose_bit_flag & 1;   /* bit field */
904-    G.pInfo->ExtLocHdr = (G.crec.general_purpose_bit_flag & 8) == 8;  /* bit */
905-    G.pInfo->textfile = G.crec.internal_file_attributes & 1;    /* bit field */
906-    G.pInfo->crc = G.crec.crc32;
907-    G.pInfo->compr_size = G.crec.csize;
908-    G.pInfo->uncompr_size = G.crec.ucsize;
909-
910-    switch (uO.aflag) {
911-        case 0:
912-            G.pInfo->textmode = FALSE;   /* bit field */
913-            break;
914-        case 1:
915-            G.pInfo->textmode = G.pInfo->textfile;   /* auto-convert mode */
916-            break;
917-        default:  /* case 2: */
918-            G.pInfo->textmode = TRUE;
919-            break;
920-    }
921-
922-    if (G.crec.version_needed_to_extract[1] == VMS_) {
923-        if (G.crec.version_needed_to_extract[0] > VMS_UNZIP_VERSION) {
924-            if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
925-                Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
926-                  FnFilter1(G.filename), "VMS",
927-                  G.crec.version_needed_to_extract[0] / 10,
928-                  G.crec.version_needed_to_extract[0] % 10,
929-                  VMS_UNZIP_VERSION / 10, VMS_UNZIP_VERSION % 10));
930-            return 0;
931+                return error_in_archive;        /* (unless disk full) */
932+            }
933         }
934-#ifndef VMS   /* won't be able to use extra field, but still have data */
935-        else if (!uO.tflag && !IS_OVERWRT_ALL) { /* if -o, extract anyway */
936-            Info(slide, 0x481, ((char *)slide, LoadFarString(VMSFormatQuery),
937-              FnFilter1(G.filename)));
938-            fgets(G.answerbuf, 9, stdin);
939-            if ((*G.answerbuf != 'y') && (*G.answerbuf != 'Y'))
940-                return 0;
941+#ifdef DLL
942+        if ((G.statreportcb != NULL) &&
943+            (*G.statreportcb)(__G__ UZ_ST_FINISH_MEMBER, G.zipfn,
944+                              G.filename, (zvoid *)&G.lrec.ucsize)) {
945+            return IZ_CTRLC;        /* cancel operation by user request */
946         }
947-#endif /* !VMS */
948-    /* usual file type:  don't need VMS to extract */
949-    } else if (G.crec.version_needed_to_extract[0] > UNZVERS_SUPPORT) {
950-        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
951-            Info(slide, 0x401, ((char *)slide, LoadFarString(VersionMsg),
952-              FnFilter1(G.filename), "PK",
953-              G.crec.version_needed_to_extract[0] / 10,
954-              G.crec.version_needed_to_extract[0] % 10,
955-              UNZVERS_SUPPORT / 10, UNZVERS_SUPPORT % 10));
956-        return 0;
957-    }
958-
959-    if (UNKN_COMPR) {
960-        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2))) {
961-#ifndef SFX
962-            unsigned cmpridx;
963-
964-            if ((cmpridx = find_compr_idx(G.crec.compression_method))
965-                < NUM_METHODS)
966-                Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgName),
967-                  FnFilter1(G.filename),
968-                  LoadFarStringSmall(ComprNames[cmpridx])));
969-            else
970 #endif
971-                Info(slide, 0x401, ((char *)slide, LoadFarString(ComprMsgNum),
972-                  FnFilter1(G.filename),
973-                  G.crec.compression_method));
974-        }
975-        return 0;
976-    }
977-#if (!CRYPT)
978-    if (G.pInfo->encrypted) {
979-        if (!((uO.tflag && uO.qflag) || (!uO.tflag && !QCOND2)))
980-            Info(slide, 0x401, ((char *)slide, LoadFarString(SkipEncrypted),
981-              FnFilter1(G.filename)));
982-        return 0;
983-    }
984-#endif /* !CRYPT */
985-
986-#ifndef SFX
987-    /* store a copy of the central header filename for later comparison */
988-    if ((G.pInfo->cfilname = zfmalloc(strlen(G.filename) + 1)) == NULL) {
989-        Info(slide, 0x401, ((char *)slide, LoadFarString(WarnNoMemCFName),
990-          FnFilter1(G.filename)));
991-    } else
992-        zfstrcpy(G.pInfo->cfilname, G.filename);
993-#endif /* !SFX */
994-
995-    /* map whatever file attributes we have into the local format */
996-    mapattr(__G);   /* GRR:  worry about return value later */
997-
998-    G.pInfo->diskstart = G.crec.disk_number_start;
999-    G.pInfo->offset = (zoff_t)G.crec.relative_offset_local_header;
1000-    return 1;
1001-
1002-} /* end function store_info() */
1003-
1004-
1005-
1006-
1007-
1008-#ifndef SFX
1009-/*******************************/
1010-/*  Function find_compr_idx()  */
1011-/*******************************/
1012-
1013-unsigned find_compr_idx(compr_methodnum)
1014-    unsigned compr_methodnum;
1015-{
1016-   unsigned i;
1017-
1018-   for (i = 0; i < NUM_METHODS; i++) {
1019-      if (ComprIDs[i] == compr_methodnum) break;
1020-   }
1021-   return i;
1022-}
1023-#endif /* !SFX */
1024+#ifdef MACOS  /* MacOS is no preemptive OS, thus call event-handling by hand */
1025+        UserStop();
1026+#endif
1027+    } /* end for-loop (i:  files in current block) */
1028 
1029+    return error_in_archive;
1030 
1031+} /* end function extract_or_test_entrylist() */
1032 
1033 
1034 
1035-/******************************************/
1036-/*  Function extract_or_test_entrylist()  */
1037-/******************************************/
1038+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1039 
1040-static int extract_or_test_entrylist(__G__ numchunk,
1041+static int extract_or_test_entrylistw(__G__ numchunk,
1042                 pfilnum, pnum_bad_pwd, pold_extra_bytes,
1043 #ifdef SET_DIR_ATTRIB
1044-                pnum_dirs, pdirlist,
1045+                pnum_dirs, pdirlistw,
1046 #endif
1047                 error_in_archive)    /* return PK-type error code */
1048@@ -1016,5 +1653,5 @@
1049 #ifdef SET_DIR_ATTRIB
1050     unsigned *pnum_dirs;
1051-    direntry **pdirlist;
1052+    direntryw **pdirlistw;
1053 #endif
1054     int error_in_archive;
1055@@ -1190,8 +1827,4 @@
1056         }
1057 #ifndef SFX
1058-        /* Filename consistency checks must come after reading in the local
1059-         * extra field, so that a UTF-8 entry name e.f. block has already
1060-         * been processed.
1061-         */
1062         if (G.pInfo->cfilname != (char Far *)NULL) {
1063             if (zfstrcmp(G.pInfo->cfilname, G.filename) != 0) {
1064@@ -1316,5 +1949,8 @@
1065 
1066             /* mapname can create dirs if not freshening or if renamed */
1067-            error = mapname(__G__ renamed);
1068+            if (G.has_win32_wide)
1069+              error = mapnamew(__G__ renamed);
1070+            else
1071+              error = mapname(__G__ renamed);
1072             if ((errcode = error & ~MPN_MASK) != PK_OK &&
1073                 error_in_archive < errcode)
1074@@ -1323,24 +1959,24 @@
1075                 if (errcode == MPN_CREATED_DIR) {
1076 #ifdef SET_DIR_ATTRIB
1077-                    direntry *d_entry;
1078+                  direntryw *d_entryw;
1079 
1080-                    error = defer_dir_attribs(__G__ &d_entry);
1081-                    if (d_entry == (direntry *)NULL) {
1082-                        /* There may be no dir_attribs info available, or
1083-                         * we have encountered a mem allocation error.
1084-                         * In case of an error, report it and set program
1085-                         * error state to warning level.
1086-                         */
1087-                        if (error) {
1088-                            Info(slide, 0x401, ((char *)slide,
1089-                                 LoadFarString(DirlistEntryNoMem)));
1090-                            if (!error_in_archive)
1091-                                error_in_archive = PK_WARN;
1092-                        }
1093-                    } else {
1094-                        d_entry->next = (*pdirlist);
1095-                        (*pdirlist) = d_entry;
1096-                        ++(*pnum_dirs);
1097-                    }
1098+                  error = defer_dir_attribsw(__G__ &d_entryw);
1099+                  if (d_entryw == (direntryw *)NULL) {
1100+                      /* There may be no dir_attribs info available, or
1101+                       * we have encountered a mem allocation error.
1102+                       * In case of an error, report it and set program
1103+                       * error state to warning level.
1104+                       */
1105+                      if (error) {
1106+                          Info(slide, 0x401, ((char *)slide,
1107+                               LoadFarString(DirlistEntryNoMem)));
1108+                          if (!error_in_archive)
1109+                              error_in_archive = PK_WARN;
1110+                      }
1111+                  } else {
1112+                      d_entryw->next = (*pdirlistw);
1113+                      (*pdirlistw) = d_entryw;
1114+                      ++(*pnum_dirs);
1115+                  }
1116 #endif /* SET_DIR_ATTRIB */
1117                 } else if (errcode == MPN_VOL_LABEL) {
1118@@ -1366,5 +2002,5 @@
1119             QFilename(__G__ G.filename);
1120 #endif
1121-            switch (check_for_newer(__G__ G.filename)) {
1122+            switch (check_for_newerw(__G__ G.unipath_widefilename)) {
1123                 case DOES_NOT_EXIST:
1124 #ifdef NOVELL_BUG_FAILSAFE
1125@@ -1538,5 +2174,7 @@
1126     return error_in_archive;
1127 
1128-} /* end function extract_or_test_entrylist() */
1129+} /* end function extract_or_test_entrylistw() */
1130+
1131+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
1132 
1133 
1134@@ -2565,4 +3203,14 @@
1135  /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */
1136 }
1137+
1138+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1139+static int Cdecl dircompw(a, b)  /* used by qsort(); swiped from Zip */
1140+    ZCONST zvoid *a, *b;
1141+{
1142+    /* order is significant:  this sorts in reverse order (deepest first) */
1143+    return wcscmp((*(direntryw **)b)->fnw, (*(direntryw **)a)->fnw);
1144+ /* return namecmp((*(direntry **)b)->fn, (*(direntry **)a)->fn); */
1145+}
1146+# endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
1147 
1148 #endif /* SET_DIR_ATTRIB */
1149diff -ru2 unz60d10/fileio.c unz60d10_w32w/fileio.c
1150--- unz60d10/fileio.c	Sun Jan 27 16:39:14 2008
1151+++ unz60d10_w32w/fileio.c	Mon Feb 11 01:09:22 2008
1152@@ -294,5 +294,12 @@
1153         zlstat(G.filename, &G.statbuf) == 0)
1154 #else
1155+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1156+    if ((G.has_win32_wide
1157+         ? SSTATW(G.unipath_widefilename, &G.statbuf)
1158+         : SSTAT(G.filename, &G.statbuf)
1159+        ) == 0)
1160+#else
1161     if (SSTAT(G.filename, &G.statbuf) == 0)
1162+#endif
1163 #endif /* ?SYMLINKS */
1164     {
1165@@ -378,5 +385,13 @@
1166             chmod(G.filename, 0);
1167 #endif /* NLM */
1168-            if (unlink(G.filename) != 0) {
1169+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1170+            if ((G.has_win32_wide
1171+                 ? _wunlink(G.unipath_widefilename)
1172+                 : unlink(G.filename)
1173+                ) != 0)
1174+#else
1175+            if (unlink(G.filename) != 0)
1176+#endif
1177+            {
1178                 Info(slide, 0x401, ((char *)slide,
1179                   LoadFarString(CannotDeleteOldFile), FnFilter1(G.filename)));
1180@@ -456,5 +471,12 @@
1181         G.outfile = zfopen(G.filename, FOPWR);
1182 #else
1183+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1184+        G.outfile = (G.has_win32_wide
1185+                    ? zfopenw(G.unipath_widefilename, L"wb")
1186+                    : zfopen(G.filename, FOPW)
1187+                    );
1188+#else /* (UNICODE_SUPPORT && WIN32_WIDE) */
1189         G.outfile = zfopen(G.filename, FOPW);
1190+#endif /* ?(UNICODE_SUPPORT && WIN32_WIDE) */
1191 #endif
1192 #if defined(ATH_BE_UNX) || defined(AOS_VS) || defined(QDOS) || defined(TANDEM)
1193@@ -1984,4 +2006,115 @@
1194 } /* end function check_for_newer() */
1195 
1196+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1197+int check_for_newerw(__G__ filenamew)  /* return 1 if existing file is newer */
1198+    __GDEF                           /*  or equal; 0 if older; -1 if doesn't */
1199+    wchar_t *filenamew;                  /*  exist yet */
1200+{
1201+    time_t existing, archive;
1202+#ifdef USE_EF_UT_TIME
1203+    iztimes z_utime;
1204+#endif
1205+#ifdef AOS_VS
1206+    long    dyy, dmm, ddd, dhh, dmin, dss;
1207+
1208+
1209+    dyy = (lrec.last_mod_dos_datetime >> 25) + 1980;
1210+    dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f;
1211+    ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f;
1212+    dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f;
1213+    dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f;
1214+    dss = (lrec.last_mod_dos_datetime & 0x1f) * 2;
1215+
1216+    /* under AOS/VS, file times can only be set at creation time,
1217+     * with the info in a special DG format.  Make sure we can create
1218+     * it here - we delete it later & re-create it, whether or not
1219+     * it exists now.
1220+     */
1221+    if (!zvs_create(filenamew, (((ulg)dgdate(dmm, ddd, dyy)) << 16) |
1222+        (dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1))
1223+        return DOES_NOT_EXIST;
1224+#endif /* AOS_VS */
1225+
1226+    Trace((stderr, "check_for_newer:  doing stat(%s)\n", FnFilter1(filename)));
1227+    if (SSTATW(filenamew, &G.statbuf)) {
1228+        Trace((stderr,
1229+          "check_for_newer:  stat(%s) returns %d:  file does not exist\n",
1230+          FnFilter1(filename), SSTAT(filename, &G.statbuf)));
1231+#ifdef SYMLINKS
1232+        Trace((stderr, "check_for_newer:  doing lstat(%s)\n",
1233+          FnFilter1(filename)));
1234+        /* GRR OPTION:  could instead do this test ONLY if G.symlnk is true */
1235+        if (zlstat(filename, &G.statbuf) == 0) {
1236+            Trace((stderr,
1237+              "check_for_newer:  lstat(%s) returns 0:  symlink does exist\n",
1238+              FnFilter1(filename)));
1239+            if (QCOND2 && !IS_OVERWRT_ALL)
1240+                Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
1241+                  FnFilter1(filename), " with no real file"));
1242+            return EXISTS_AND_OLDER;   /* symlink dates are meaningless */
1243+        }
1244+#endif /* SYMLINKS */
1245+        return DOES_NOT_EXIST;
1246+    }
1247+    Trace((stderr, "check_for_newer:  stat(%s) returns 0:  file exists\n",
1248+      FnFilter1(filename)));
1249+
1250+#ifdef SYMLINKS
1251+    /* GRR OPTION:  could instead do this test ONLY if G.symlnk is true */
1252+    if (zlstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) {
1253+        Trace((stderr, "check_for_newer:  %s is a symbolic link\n",
1254+          FnFilter1(filename)));
1255+        if (QCOND2 && !IS_OVERWRT_ALL)
1256+            Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
1257+              FnFilter1(filename), ""));
1258+        return EXISTS_AND_OLDER;   /* symlink dates are meaningless */
1259+    }
1260+#endif /* SYMLINKS */
1261+
1262+    NATIVE_TO_TIMET(G.statbuf.st_mtime)   /* NOP unless MSC 7.0 or Macintosh */
1263+
1264+#ifdef USE_EF_UT_TIME
1265+    /* The `Unix extra field mtime' should be used for comparison with the
1266+     * time stamp of the existing file >>>ONLY<<< when the EF info is also
1267+     * used to set the modification time of the extracted file.
1268+     */
1269+    if (G.extra_field &&
1270+#ifdef IZ_CHECK_TZ
1271+        G.tz_is_valid &&
1272+#endif
1273+        (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
1274+                          G.lrec.last_mod_dos_datetime, &z_utime, NULL)
1275+         & EB_UT_FL_MTIME))
1276+    {
1277+        TTrace((stderr, "check_for_newer:  using Unix extra field mtime\n"));
1278+        existing = G.statbuf.st_mtime;
1279+        archive  = z_utime.mtime;
1280+    } else {
1281+        /* round up existing filetime to nearest 2 seconds for comparison,
1282+         * but saturate in case of arithmetic overflow
1283+         */
1284+        existing = ((G.statbuf.st_mtime & 1) &&
1285+                    (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
1286+                   G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
1287+        archive  = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
1288+    }
1289+#else /* !USE_EF_UT_TIME */
1290+    /* round up existing filetime to nearest 2 seconds for comparison,
1291+     * but saturate in case of arithmetic overflow
1292+     */
1293+    existing = ((G.statbuf.st_mtime & 1) &&
1294+                (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
1295+               G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
1296+    archive  = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
1297+#endif /* ?USE_EF_UT_TIME */
1298+
1299+    TTrace((stderr, "check_for_newer:  existing %lu, archive %lu, e-a %ld\n",
1300+      (ulg)existing, (ulg)archive, (long)(existing-archive)));
1301+
1302+    return (existing >= archive);
1303+
1304+} /* end function check_for_newerw() */
1305+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
1306+
1307 #endif /* !VMS && !OS2 && !CMS_MVS */
1308 
1309@@ -2319,4 +2452,23 @@
1310                 free(fn);
1311               }
1312+# ifdef WIN32_WIDE
1313+              G.unipath_widefilename = NULL;
1314+              if (G.has_win32_wide) {
1315+                if (G.unipath_filename)
1316+                  /* Get wide path from UTF-8 */
1317+                  G.unipath_widefilename = utf8_to_wchar_string(G.unipath_filename);
1318+                else
1319+                  G.unipath_widefilename = utf8_to_wchar_string(G.filename);
1320+
1321+                if (G.pInfo->lcflag)      /* replace with lowercase filename */
1322+                    wcslwr(G.unipath_widefilename);
1323+
1324+                if (G.pInfo->vollabel && length > 8 && G.unipath_widefilename[8] == '.') {
1325+                    wchar_t *p = G.unipath_widefilename+8;
1326+                    while (*p++)
1327+                        p[-1] = *p;  /* disk label, and 8th char is dot:  remove dot */
1328+                }
1329+              }
1330+# endif /* WIN32_WIDE */
1331             }
1332 #endif /* UNICODE_SUPPORT */
1333diff -ru2 unz60d10/globals.h unz60d10_w32w/globals.h
1334--- unz60d10/globals.h	Sun Jan 27 16:31:56 2008
1335+++ unz60d10_w32w/globals.h	Mon Feb 11 01:09:22 2008
1336@@ -302,4 +302,8 @@
1337     ulg      unipath_checksum;     /* Unicode field checksum */
1338     char     *unipath_filename;    /* UTF-8 path */
1339+# ifdef WIN32_WIDE
1340+    wchar_t  *unipath_widefilename;     /* wide character filename */
1341+    int      has_win32_wide;       /* true if Win32 W calls work */
1342+# endif
1343     char     *unipath_escapedfilename;
1344 #endif /* UNICODE_SUPPORT */
1345diff -ru2 unz60d10/match.c unz60d10_w32w/match.c
1346--- unz60d10/match.c	Sun Aug 14 20:00:36 2005
1347+++ unz60d10_w32w/match.c	Sun Jan  6 18:19:46 2008
1348@@ -1,4 +1,4 @@
1349 /*
1350-  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
1351+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
1352 
1353   See the accompanying file LICENSE, version 2000-Apr-09 or later
1354@@ -407,5 +407,18 @@
1355 } /* end function iswild() */
1356 
1357+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1358+int iswildw(pw)          /* originally only used for stat()-bug workaround in */
1359+    ZCONST wchar_t *pw;  /*  VAX C, Turbo/Borland C, Watcom C, Atari MiNT libs; */
1360+{                    /*  now used in process_zipfiles() as well */
1361+    for (; *pw; pw++)
1362+        if (*pw == '\\' && *(pw+1))
1363+            ++pw;
1364+        else if (*pw == '?' || *pw == '*' || *pw == '[')
1365+            return TRUE;
1366+
1367+    return FALSE;
1368 
1369+} /* end function iswildw() */
1370+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
1371 
1372 
1373diff -ru2 unz60d10/process.c unz60d10_w32w/process.c
1374--- unz60d10/process.c	Sun Feb  3 00:03:34 2008
1375+++ unz60d10_w32w/process.c	Mon Feb 11 01:09:22 2008
1376@@ -43,4 +43,7 @@
1377 #  include "crc32.h"
1378 #endif
1379+#ifdef UNICODE_SUPPORT
1380+#  include <wchar.h>
1381+#endif /* def UNICODE_SUPPORT */
1382 
1383 static int    do_seekable        OF((__GPRO__ int lastchance));
1384@@ -552,5 +555,12 @@
1385 
1386     inflate_free(__G);
1387+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1388+    if (G.has_win32_wide)
1389+      checkdirw(__G__ (wchar_t *)NULL, END);
1390+    else
1391+      checkdir(__G__ (char *)NULL, END);
1392+#else
1393     checkdir(__G__ (char *)NULL, END);
1394+#endif
1395 
1396 #ifdef DYNALLOC_CRCTAB
1397@@ -1507,26 +1517,4 @@
1398      */
1399 
1400-    /* This is an internal comment.  Remove before the next public beta.
1401-
1402-       Below check does not catch when an entry requires Zip64, as
1403-       when the uncompressed size is larger than 4 GB, but the
1404-       standard fields in ecrec (called EOCDR in the Zip source)
1405-       are sufficient, as when the file compresses under the Zip64
1406-       limit.  In such cases ecrec64 (called Zip64 EOCDR in Zip)
1407-       will exist to flag the archive as Zip64, even though none
1408-       of the ecrec values are set to the FFFF or FFFFFFFF flag
1409-       values.
1410-
1411-      if(check_ecrec_zip64(__G)){
1412-        need_zip64 = TRUE;
1413-      }
1414-
1415-       In fact, this check is not needed, as ecrec64 will ALWAYS
1416-       exist for a proper Zip64 archive, as the Version Needed To Extract
1417-       field is required to be set to 4.5 or higher.
1418-
1419-       End of internal comment.
1420-     */
1421-
1422     /* The ecrec64 will ALWAYS exist for a proper Zip64 archive, as
1423        the Version Needed To Extract field is required to be set to
1424@@ -1954,7 +1942,4 @@
1425             G.unipath_filename[ULen] = '\0';
1426           }
1427-# if 0
1428-          G.unipath_escapedfilename = utf8_to_escaped_string(G.unipath_filename);
1429-# endif
1430         }
1431 
1432@@ -2324,4 +2309,37 @@
1433   return w;
1434 }
1435+
1436+char *wchar_to_local_string(wchar_string, escape_all)
1437+  wchar_t *wchar_string;
1438+  int escape_all;
1439+{
1440+  zwchar *wide_string = wchar_to_wide_string(wchar_string);
1441+  char *local_string = wide_to_local_string(wide_string, escape_all);
1442+
1443+  free(wide_string);
1444+
1445+  return local_string;
1446+}
1447+
1448+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1449+zwchar *wchar_to_wide_string(wchar_string)
1450+  wchar_t *wchar_string;
1451+{
1452+  int i;
1453+  int wchar_len;
1454+  zwchar *wide_string;
1455+
1456+  wchar_len = wcslen(wchar_string);
1457+
1458+  if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) {
1459+    return NULL;
1460+  }
1461+  for (i = 0; i <= wchar_len; i++) {
1462+    wide_string[i] = wchar_string[i];
1463+  }
1464+
1465+  return wide_string;
1466+}
1467+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
1468 
1469 char *utf8_to_escaped_string(utf8_string, escape_all)
1470diff -ru2 unz60d10/unzpriv.h unz60d10_w32w/unzpriv.h
1471--- unz60d10/unzpriv.h	Sun Feb  3 15:50:52 2008
1472+++ unz60d10_w32w/unzpriv.h	Mon Feb 11 02:05:46 2008
1473@@ -1318,4 +1318,7 @@
1474 #     define zstat _stati64
1475 #     define zfstat _fstati64
1476+#  if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1477+#     define zstatw _wstati64
1478+#  endif
1479 
1480     /* 64-bit lseek */
1481@@ -1332,4 +1335,7 @@
1482     /* 64-bit fopen */
1483 #     define zfopen fopen
1484+#   if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1485+#     define zfopenw _wfopen
1486+#   endif
1487 #     define zfdopen fdopen
1488 
1489@@ -1904,4 +1910,11 @@
1490        char buf[1];             /* start of system-specific internal data */
1491    } direntry;
1492+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1493+   typedef struct direntryw {   /* head of system-specific struct holding */
1494+       struct direntryw *next;  /*  defered directory attributes info */
1495+       wchar_t *fnw;            /* filename of directory */
1496+       wchar_t buf[1];          /* start of system-specific internal data */
1497+   } direntryw;
1498+# endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
1499 #endif /* SET_DIR_ATTRIB */
1500 
1501@@ -2225,4 +2238,7 @@
1502 time_t   dos_to_unix_time     OF((ulg dos_datetime));
1503 int      check_for_newer      OF((__GPRO__ char *filename)); /* os2,vmcms,vms */
1504+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1505+int      check_for_newerw     OF((__GPRO__ wchar_t *filenamew)); /* os2,vmcms,vms */
1506+#endif
1507 int      do_string            OF((__GPRO__ unsigned int length, int option));
1508 ush      makeword             OF((ZCONST uch *b));
1509@@ -2468,4 +2484,8 @@
1510    int   zstat_win32    OF((__W32STAT_GLOBALS__
1511                             const char *path, z_stat *buf));      /* win32.c */
1512+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1513+   int   zstat_win32w   OF((__W32STAT_GLOBALS__
1514+                            const wchar_t *pathw, z_stat *buf));      /* win32.c */
1515+# endif
1516 #endif
1517 #endif
1518@@ -2485,4 +2505,7 @@
1519                              int ic __WDLPRO));                   /* match.c */
1520 int      iswild          OF((ZCONST char *p));                    /* match.c */
1521+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1522+int      iswildw         OF((ZCONST wchar_t *pw));                /* match.c */
1523+#endif
1524 
1525 /* declarations of public CRC-32 functions have been moved into crc32.h
1526@@ -2497,4 +2520,8 @@
1527 int      mapname         OF((__GPRO__ int renamed));                /* local */
1528 int      checkdir        OF((__GPRO__ char *pathcomp, int flag));   /* local */
1529+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1530+  int    mapnamew        OF((__GPRO__ int renamed));                /* local */
1531+  int    checkdirw       OF((__GPRO__ wchar_t *pathcomp, int flag));   /* local */
1532+#endif
1533 char    *do_wild         OF((__GPRO__ ZCONST char *wildzipfn));     /* local */
1534 char    *GetLoadPath     OF((__GPRO));                              /* local */
1535@@ -2517,4 +2544,8 @@
1536    int   defer_dir_attribs  OF((__GPRO__ direntry **pd));           /* local */
1537    int   set_direc_attribs  OF((__GPRO__ direntry *d));             /* local */
1538+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1539+   int   defer_dir_attribsw  OF((__GPRO__ direntryw **pd));           /* local */
1540+   int   set_direc_attribsw  OF((__GPRO__ direntryw *d));             /* local */
1541+# endif
1542 #endif
1543 #ifdef TIMESTAMP
1544@@ -2980,4 +3011,8 @@
1545   /* convert UTF-8 string to wide string */
1546   zwchar *utf8_to_wide_string OF((char *));
1547+
1548+  char *wchar_to_local_string OF((wchar_t *, int));
1549+
1550+  zwchar *wchar_to_wide_string OF((wchar_t *));
1551 
1552   /* convert wide string to multi-byte string */
1553diff -ru2 unz60d10/win32/nt.c unz60d10_w32w/win32/nt.c
1554--- unz60d10/win32/nt.c	Tue Dec 25 12:34:50 2007
1555+++ unz60d10_w32w/win32/nt.c	Mon Feb 11 02:09:20 2008
1556@@ -1,6 +1,6 @@
1557 /*
1558-  Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
1559+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
1560 
1561-  See the accompanying file LICENSE, version 2000-Apr-09 or later
1562+  See the accompanying file LICENSE, version 2007-Mar-04 or later
1563   (the contents of which are also included in unzip.h) for terms of use.
1564   If, for some reason, all these files are missing, the Info-ZIP license
1565@@ -63,5 +63,10 @@
1566 
1567 static BOOL Initialize(VOID);
1568+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1569+static VOID GetRemotePrivilegesSet(wchar_t *FileName,
1570+                                   PDWORD dwRemotePrivileges);
1571+#else
1572 static VOID GetRemotePrivilegesSet(CHAR *FileName, PDWORD dwRemotePrivileges);
1573+#endif
1574 static VOID InitLocalPrivileges(VOID);
1575 
1576@@ -191,5 +196,10 @@
1577 }
1578 
1579+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1580+static VOID GetRemotePrivilegesSet(wchar_t *FileName,
1581+                                   PDWORD dwRemotePrivileges)
1582+#else
1583 static VOID GetRemotePrivilegesSet(char *FileName, PDWORD dwRemotePrivileges)
1584+#endif
1585 {
1586     HANDLE hFile;
1587@@ -199,5 +209,9 @@
1588     /* see if we have the SeRestorePrivilege */
1589 
1590+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1591+    hFile = CreateFileW(
1592+#else
1593     hFile = CreateFileA(
1594+#endif
1595         FileName,
1596         ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER | READ_CONTROL,
1597@@ -236,5 +250,9 @@
1598         /* note we don't need this if we have SeRestorePrivilege */
1599 
1600+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1601+        hFile = CreateFileW(
1602+#else
1603         hFile = CreateFileA(
1604+#endif
1605             FileName,
1606             ACCESS_SYSTEM_SECURITY,
1607@@ -255,10 +273,19 @@
1608 
1609 BOOL GetVolumeCaps(
1610+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1611+    wchar_t *rootpath,      /* filepath, or NULL */
1612+    wchar_t *name,          /* filename associated with rootpath */
1613+#else
1614     char *rootpath,         /* filepath, or NULL */
1615     char *name,             /* filename associated with rootpath */
1616+#endif
1617     PVOLUMECAPS VolumeCaps  /* result structure describing capabilities */
1618     )
1619 {
1620+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1621+    wchar_t TempRootPath[MAX_PATH + 1];
1622+#else
1623     char TempRootPath[MAX_PATH + 1];
1624+#endif
1625     DWORD cchTempRootPath = 0;
1626     BOOL bSuccess = TRUE;   /* assume success until told otherwise */
1627@@ -273,5 +300,9 @@
1628         DWORD i;
1629 
1630+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1631+        cchTempRootPath = lstrlenW(rootpath);
1632+#else
1633         cchTempRootPath = lstrlenA(rootpath);
1634+#endif
1635         if(cchTempRootPath > MAX_PATH) return FALSE;
1636 
1637@@ -345,5 +376,9 @@
1638 
1639     if(!g_VolumeCaps.bValid ||
1640+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1641+       lstrcmpiW(g_VolumeCaps.RootPath, TempRootPath) != 0)
1642+#else
1643        lstrcmpiA(g_VolumeCaps.RootPath, TempRootPath) != 0)
1644+#endif
1645     {
1646 
1647@@ -357,5 +392,9 @@
1648         LeaveCriticalSection( &VolumeCapsLock );
1649 
1650+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1651+        bSuccess = GetVolumeInformationW(
1652+#else
1653         bSuccess = GetVolumeInformationA(
1654+#endif
1655             (TempRootPath[0] == '\0') ? NULL : TempRootPath,
1656             NULL, 0,
1657@@ -371,5 +410,9 @@
1658            VolumeCaps->bUsePrivileges)
1659         {
1660+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1661+            if(GetDriveTypeW( (TempRootPath[0] == '\0') ? NULL : TempRootPath )
1662+#else
1663             if(GetDriveTypeA( (TempRootPath[0] == '\0') ? NULL : TempRootPath )
1664+#endif
1665                == DRIVE_REMOTE)
1666             {
1667@@ -388,5 +431,9 @@
1668         if(bSuccess) {
1669 
1670+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1671+            lstrcpynW(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1);
1672+#else
1673             lstrcpynA(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1);
1674+#endif
1675             g_VolumeCaps.dwFileSystemFlags = dwFileSystemFlags;
1676             g_VolumeCaps.bRemote = bRemote;
1677@@ -413,5 +460,9 @@
1678 
1679 
1680+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1681+BOOL SecuritySet(wchar_t *resource, PVOLUMECAPS VolumeCaps, uch *securitydata)
1682+#else
1683 BOOL SecuritySet(char *resource, PVOLUMECAPS VolumeCaps, uch *securitydata)
1684+#endif
1685 {
1686     HANDLE hFile;
1687@@ -491,5 +542,9 @@
1688         dwFlags |= FILE_FLAG_BACKUP_SEMANTICS;
1689 
1690+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1691+    hFile = CreateFileW(
1692+#else
1693     hFile = CreateFileA(
1694+#endif
1695         resource,
1696         dwDesiredAccess,
1697diff -ru2 unz60d10/win32/nt.h unz60d10_w32w/win32/nt.h
1698--- unz60d10/win32/nt.h	Mon Jan 24 02:46:38 2005
1699+++ unz60d10_w32w/win32/nt.h	Mon Feb 11 02:07:20 2008
1700@@ -1,4 +1,4 @@
1701 /*
1702-  Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
1703+  Copyright (c) 1990-2008 Info-ZIP.  All rights reserved.
1704 
1705   See the accompanying file LICENSE, version 2000-Apr-09 or later
1706@@ -24,9 +24,18 @@
1707     DWORD dwRemotePrivileges;   /* relevant only on remote volumes */
1708     DWORD dwFileAttributes;
1709+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1710+    wchar_t RootPath[MAX_PATH+1];  /* path to network / filesystem */
1711+#else
1712     char RootPath[MAX_PATH+1];  /* path to network / filesystem */
1713+#endif
1714 } VOLUMECAPS, *PVOLUMECAPS, *LPVOLUMECAPS;
1715 
1716+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1717+BOOL SecuritySet(wchar_t *resource, PVOLUMECAPS VolumeCaps, uch *securitydata);
1718+BOOL GetVolumeCaps(wchar_t *rootpath, wchar_t *name, PVOLUMECAPS VolumeCaps);
1719+#else
1720 BOOL SecuritySet(char *resource, PVOLUMECAPS VolumeCaps, uch *securitydata);
1721 BOOL GetVolumeCaps(char *rootpath, char *name, PVOLUMECAPS VolumeCaps);
1722+#endif
1723 BOOL ValidateSecurity(uch *securitydata);
1724 
1725diff -ru2 unz60d10/win32/vc6/funzip.dsp unz60d10_w32w/win32/vc6/funzip.dsp
1726--- unz60d10/win32/vc6/funzip.dsp	Mon Feb 11 02:55:18 2008
1727+++ unz60d10_w32w/win32/vc6/funzip.dsp	Mon Feb 11 02:55:38 2008
1728@@ -45,5 +45,5 @@
1729 # PROP Target_Dir ""
1730 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
1731-# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /FD /c
1732+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1733 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1734 # ADD RSC /l 0x409 /d "NDEBUG"
1735@@ -69,5 +69,5 @@
1736 # PROP Target_Dir ""
1737 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
1738-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1739+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FD /GZ /c
1740 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1741 # ADD RSC /l 0x409 /d "_DEBUG"
1742@@ -93,5 +93,5 @@
1743 # PROP Target_Dir ""
1744 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "FUNZIP" /FD /c
1745-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c
1746+# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1747 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1748 # ADD RSC /l 0x409 /d "NDEBUG"
1749@@ -117,5 +117,5 @@
1750 # PROP Target_Dir ""
1751 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "FUNZIP" /FD /GZ /c
1752-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1753+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "FUNZIP" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c
1754 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1755 # ADD RSC /l 0x409 /d "_DEBUG"
1756diff -ru2 unz60d10/win32/vc6/unzip.dsp unz60d10_w32w/win32/vc6/unzip.dsp
1757--- unz60d10/win32/vc6/unzip.dsp	Sat Mar 24 19:51:24 2007
1758+++ unz60d10_w32w/win32/vc6/unzip.dsp	Mon Feb 11 02:52:48 2008
1759@@ -45,5 +45,5 @@
1760 # PROP Target_Dir ""
1761 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
1762-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /c
1763+# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1764 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1765 # ADD RSC /l 0x409 /d "NDEBUG"
1766@@ -69,5 +69,5 @@
1767 # PROP Target_Dir ""
1768 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
1769-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1770+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FR /FD /GZ /c
1771 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1772 # ADD RSC /l 0x409 /d "_DEBUG"
1773@@ -93,5 +93,5 @@
1774 # PROP Target_Dir ""
1775 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
1776-# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c
1777+# ADD CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1778 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1779 # ADD RSC /l 0x409 /d "NDEBUG"
1780@@ -118,5 +118,5 @@
1781 # PROP Target_Dir ""
1782 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
1783-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1784+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c
1785 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1786 # ADD RSC /l 0x409 /d "_DEBUG"
1787diff -ru2 unz60d10/win32/vc6/unzipbz2.dsp unz60d10_w32w/win32/vc6/unzipbz2.dsp
1788--- unz60d10/win32/vc6/unzipbz2.dsp	Sun Jan  6 19:14:44 2008
1789+++ unz60d10_w32w/win32/vc6/unzipbz2.dsp	Mon Feb 11 02:52:48 2008
1790@@ -45,5 +45,5 @@
1791 # PROP Target_Dir ""
1792 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
1793-# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /c
1794+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1795 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1796 # ADD RSC /l 0x409 /d "NDEBUG"
1797@@ -69,5 +69,5 @@
1798 # PROP Target_Dir ""
1799 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
1800-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1801+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FD /GZ /c
1802 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1803 # ADD RSC /l 0x409 /d "_DEBUG"
1804@@ -93,5 +93,5 @@
1805 # PROP Target_Dir ""
1806 # ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /FD /c
1807-# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /c
1808+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NDEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1809 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1810 # ADD RSC /l 0x409 /d "NDEBUG"
1811@@ -118,5 +118,5 @@
1812 # PROP Target_Dir ""
1813 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /FD /GZ /c
1814-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1815+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "_DEBUG" /D "WIN32" /D "ASM_CRC" /D "USE_BZIP2" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c
1816 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1817 # ADD RSC /l 0x409 /d "_DEBUG"
1818diff -ru2 unz60d10/win32/vc6/unzipsfx.dsp unz60d10_w32w/win32/vc6/unzipsfx.dsp
1819--- unz60d10/win32/vc6/unzipsfx.dsp	Sun Jan  6 19:13:46 2008
1820+++ unz60d10_w32w/win32/vc6/unzipsfx.dsp	Mon Feb 11 02:52:48 2008
1821@@ -45,5 +45,5 @@
1822 # PROP Target_Dir ""
1823 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
1824-# ADD CPP /nologo /W3 /GX /O1 /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /FD /c
1825+# ADD CPP /nologo /W3 /GX /O1 /D "WIN32" /D "SFX" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1826 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1827 # ADD RSC /l 0x409 /d "NDEBUG"
1828@@ -69,5 +69,5 @@
1829 # PROP Target_Dir ""
1830 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
1831-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1832+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "_CONSOLE" /D "_MBCS" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FD /GZ /c
1833 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1834 # ADD RSC /l 0x409 /d "_DEBUG"
1835@@ -93,5 +93,5 @@
1836 # PROP Target_Dir ""
1837 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "SFX" /FD /c
1838-# ADD CPP /nologo /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /c
1839+# ADD CPP /nologo /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /c
1840 # ADD BASE RSC /l 0x409 /d "NDEBUG"
1841 # ADD RSC /l 0x409 /d "NDEBUG"
1842@@ -117,5 +117,5 @@
1843 # PROP Target_Dir ""
1844 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "SFX" /FD /GZ /c
1845-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
1846+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "SFX" /D "ASM_CRC" /D "_CONSOLE" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /D "_MBCS" /FD /GZ /c
1847 # ADD BASE RSC /l 0x409 /d "_DEBUG"
1848 # ADD RSC /l 0x409 /d "_DEBUG"
1849diff -ru2 unz60d10/win32/w32cfg.h unz60d10_w32w/win32/w32cfg.h
1850--- unz60d10/win32/w32cfg.h	Thu Oct  4 02:05:42 2007
1851+++ unz60d10_w32w/win32/w32cfg.h	Tue Jan  1 18:34:48 2008
1852@@ -271,15 +271,38 @@
1853 #define STR_TO_ISO
1854 
1855+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1856+   wchar_t *utf8_to_wchar_string OF((char *));
1857+   wchar_t *local_to_wchar_string OF((char *));
1858+   int has_win32_wide();
1859+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
1860+
1861 /* Static variables that we have to add to Uz_Globs: */
1862+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1863 #define SYSTEM_SPECIFIC_GLOBALS \
1864     int created_dir, renamed_fullpath, fnlen;\
1865     unsigned nLabelDrive;\
1866     char lastRootPath[4];\
1867+    wchar_t lastRootPathw[4];\
1868     int lastVolOldFAT, lastVolLocTim;\
1869     char *rootpath, *buildpathHPFS, *buildpathFAT, *endHPFS, *endFAT;\
1870+    wchar_t *rootpathw, *buildpathHPFSw, *buildpathFATw, *endHPFSw, *endFATw;\
1871     ZCONST char *wildname;\
1872+    ZCONST wchar_t *wildnamew;\
1873     char *dirname, matchname[FILNAMSIZ];\
1874+    wchar_t *dirnamew, matchnamew[FILNAMSIZ];\
1875     int rootlen, have_dirname, dirnamelen, notfirstcall;\
1876     zvoid *wild_dir;
1877+#else /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
1878+#define SYSTEM_SPECIFIC_GLOBALS \
1879+    int created_dir, renamed_fullpath, fnlen;\
1880+    unsigned nLabelDrive;\
1881+    char lastRootPath[4];\
1882+    int lastVolOldFAT, lastVolLocTim;\
1883+    char *rootpath, *buildpathHPFS, *buildpathFAT, *endHPFS, *endFAT;\
1884+    ZCONST char *wildname;\
1885+    char *dirname, matchname[FILNAMSIZ];\
1886+    int rootlen, have_dirname, dirnamelen, notfirstcall;\
1887+    zvoid *wild_dir;
1888+#endif /* ?(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
1889 
1890 /* created_dir, renamed_fullpath, fnlen, and nLabelDrive are used by   */
1891@@ -342,4 +365,13 @@
1892 #  define SSTAT(path, pbuf) zstat_win32(__W32STAT_G__ path, pbuf)
1893 #endif
1894+
1895+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1896+# ifdef WILD_STAT_BUG
1897+#  define SSTATW(pathw, pbuf) (iswildw(pathw) || zstat_win32w(__W32STAT_G__ pathw, pbuf))
1898+# else
1899+#  define SSTATW(pathw, pbuf) zstat_win32w(__W32STAT_G__ pathw, pbuf)
1900+# endif
1901+#endif /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
1902+
1903 
1904 #ifdef __WATCOMC__
1905diff -ru2 unz60d10/win32/win32.c unz60d10_w32w/win32/win32.c
1906--- unz60d10/win32/win32.c	Tue Jan  1 21:26:22 2008
1907+++ unz60d10_w32w/win32/win32.c	Tue Jan  1 21:26:24 2008
1908@@ -75,4 +75,12 @@
1909 #endif
1910 
1911+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1912+# if (defined(__EMX__) || defined(__CYGWIN__))
1913+#  define MKDIRW(pathw,mode)   _wmkdir(pathw,mode)
1914+# else
1915+#  define MKDIRW(pathw,mode)   _wmkdir(pathw)
1916+# endif
1917+#endif
1918+
1919 #ifdef HAVE_WORKING_DIRENT_H
1920 #  undef HAVE_WORKING_DIRENT_H
1921@@ -124,4 +132,22 @@
1922 } NTdirattr;
1923 #define NtAtt(d)  ((NTdirattr *)d)    /* typecast shortcut */
1924+
1925+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1926+ typedef struct NTdirattrw {     /* struct for holding unix style directory */
1927+    struct NTdirattrw *next;     /*  info until can be sorted and set at end */
1928+    wchar_t *fnw;                /* filename of directory */
1929+    FILETIME Modft;    /* File time type defined in NT, `last modified' time */
1930+    FILETIME Accft;    /* NT file time type, `last access' time */
1931+    FILETIME Creft;    /* NT file time type, `file creation' time */
1932+    int gotTime;
1933+    unsigned perms;             /* same as min_info.file_attr */
1934+# ifdef NTSD_EAS
1935+    unsigned SDlen;             /* length of SD data in buf */
1936+# endif
1937+    wchar_t buf[1];                /* buffer stub for directory SD and name */
1938+ } NTdirattrw;
1939+# define NtAttw(dw)  ((NTdirattrw *)dw)    /* typecast shortcut */
1940+# endif
1941+
1942 #endif /* SET_DIR_ATTRIB */
1943 
1944@@ -129,10 +155,15 @@
1945 /* Function prototypes */
1946 #ifdef NTSD_EAS
1947+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1948+   static int  SetSD(__GPRO__ wchar_t *path, unsigned fperms,
1949+                     uch *eb_ptr, unsigned eb_len);
1950+# else
1951    static int  SetSD(__GPRO__ char *path, unsigned fperms,
1952                      uch *eb_ptr, unsigned eb_len);
1953+# endif
1954    static int  FindSDExtraField(__GPRO__
1955                                 uch *ef_ptr, unsigned ef_len,
1956                                 uch **p_ebSD_ptr, unsigned *p_ebSD_len);
1957-#endif
1958+#endif /* NTSD_EAS */
1959 
1960 #ifndef NO_W32TIMES_IZFIX
1961@@ -147,13 +178,27 @@
1962 #endif
1963 static int FStampIsLocTime(__GPRO__ const char *path);
1964+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1965+   static int FStampIsLocTimeW(__GPRO__ const wchar_t *pathw);
1966+#endif
1967 
1968 
1969 static int  getNTfiletime   (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
1970                              FILETIME *pCreFT);
1971+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1972+static int  getNTfiletimeW  (__GPRO__ FILETIME *pModFT, FILETIME *pAccFT,
1973+                             FILETIME *pCreFT);
1974+#endif
1975 static int  isfloppy        (int nDrive);
1976 static int  NTQueryVolInfo  (__GPRO__ const char *name);
1977+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1978+   static int  NTQueryVolInfoW  (__GPRO__ const wchar_t *namew);
1979+#endif
1980 static int  IsVolumeOldFAT  (__GPRO__ const char *name);
1981 static void maskDOSdevice   (__GPRO__ char *pathcomp);
1982 static void map2fat         (char *pathcomp, char **pEndFAT);
1983+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1984+  static void maskDOSdevicew (__GPRO__ wchar_t *pathcompw);
1985+  static void map2fatw      (wchar_t *pathcompw, wchar_t **pEndFATw);
1986+#endif
1987 
1988 
1989@@ -309,7 +354,13 @@
1990 /**********************/
1991 
1992+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
1993+static int SetSD(__G__ path, fperms, eb_ptr, eb_len)
1994+    __GDEF
1995+    wchar_t *path;
1996+#else
1997 static int SetSD(__G__ path, fperms, eb_ptr, eb_len)
1998     __GDEF
1999     char *path;
2000+#endif
2001     unsigned fperms;
2002     uch *eb_ptr;
2003@@ -918,4 +969,12 @@
2004 
2005 
2006+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2007+static int FStampIsLocTimeW(__GPRO__ const wchar_t *pathw)
2008+{
2009+    return (NTQueryVolInfoW(__G__ pathw) ? G.lastVolLocTim : FALSE);
2010+}
2011+#endif
2012+
2013+
2014 
2015 #ifndef NO_W32TIMES_IZFIX
2016@@ -991,4 +1050,63 @@
2017 
2018 
2019+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2020+  static int getNTfiletimeW(__G__ pModFT, pAccFT, pCreFT)
2021+      __GDEF
2022+      FILETIME *pModFT;
2023+      FILETIME *pAccFT;
2024+      FILETIME *pCreFT;
2025+  {
2026+# ifdef USE_EF_UT_TIME
2027+      unsigned eb_izux_flg;
2028+      iztimes z_utime;   /* struct for Unix-style actime & modtime, + creatime */
2029+# endif
2030+      int fs_uses_loctime = FStampIsLocTimeW(__G__ G.unipath_widefilename);
2031+
2032+      /* Copy and/or convert time and date variables, if necessary;
2033+       * return a flag indicating which time stamps are available. */
2034+# ifdef USE_EF_UT_TIME
2035+      if (G.extra_field &&
2036+#  ifdef IZ_CHECK_TZ
2037+          G.tz_is_valid &&
2038+#  endif
2039+          ((eb_izux_flg = ef_scan_for_izux(G.extra_field,
2040+            G.lrec.extra_field_length, 0, G.lrec.last_mod_dos_datetime,
2041+            &z_utime, NULL)) & EB_UT_FL_MTIME))
2042+      {
2043+          TTrace((stderr, "getNTfiletime:  Unix e.f. modif. time = %lu\n",
2044+            z_utime.mtime));
2045+          UTIME_2_IZFILETIME(z_utime.mtime, pModFT)
2046+          if (eb_izux_flg & EB_UT_FL_ATIME) {
2047+              UTIME_2_IZFILETIME(z_utime.atime, pAccFT)
2048+          }
2049+          if (eb_izux_flg & EB_UT_FL_CTIME) {
2050+              UTIME_2_IZFILETIME(z_utime.ctime, pCreFT)
2051+          }
2052+          return (int)eb_izux_flg;
2053+      }
2054+# endif /* USE_EF_UT_TIME */
2055+# ifndef NO_W32TIMES_IZFIX
2056+      if (!fs_uses_loctime) {
2057+          time_t ux_modtime;
2058+
2059+          ux_modtime = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
2060+          utime2NtfsFileTime(ux_modtime, pModFT);
2061+      } else
2062+#endif /* NO_W32TIMES_IZFIX */
2063+      {
2064+          FILETIME lft;
2065+
2066+          DosDateTimeToFileTime((WORD)(G.lrec.last_mod_dos_datetime >> 16),
2067+                                (WORD)(G.lrec.last_mod_dos_datetime & 0xFFFFL),
2068+                                &lft);
2069+          LocalFileTimeToFileTime(&lft, pModFT);
2070+      }
2071+      *pAccFT = *pModFT;
2072+      return (EB_UT_FL_MTIME | EB_UT_FL_ATIME);
2073+
2074+  } /* end function getNTfiletime() */
2075+#endif /* (UNICODE_SUPPORT && WIN32_WIDE) */
2076+
2077+
2078 
2079 
2080@@ -1059,66 +1177,72 @@
2081     unsigned ebSDlen;
2082 #endif
2083+
2084+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2085+    if (!G.has_win32_wide) {
2086+#endif
2087 #ifdef __RSXNT__        /* RSXNT/EMX C rtl uses OEM charset */
2088-    char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
2089+      char *ansi_name = (char *)alloca(strlen(G.filename) + 1);
2090 
2091-    INTERN_TO_ISO(G.filename, ansi_name);
2092-#   define Ansi_Fname  ansi_name
2093+      INTERN_TO_ISO(G.filename, ansi_name);
2094+#     define Ansi_Fname  ansi_name
2095 #else
2096-#   define Ansi_Fname  G.filename
2097+#     define Ansi_Fname  G.filename
2098 #endif
2099 
2100 #ifndef __RSXNT__
2101-    if (IsWinNT()) {
2102+# if !(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE))
2103+      if (IsWinNT()) {
2104         /* Truncate the file to the current position.
2105          * This is needed to remove excess allocation in case the
2106          * extraction has failed or stopped prematurely. */
2107         SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile)));
2108-    }
2109+      }
2110+# endif /* !(defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
2111 #endif
2112 
2113-    /* Close the file and then re-open it using the Win32
2114-     * CreateFile call, so that the file can be created
2115-     * with GENERIC_WRITE access, otherwise the SetFileTime
2116-     * call will fail. */
2117-    fclose(G.outfile);
2118-
2119-    /* don't set the time stamp and attributes on standard output */
2120-    if (uO.cflag)
2121-        return;
2122-
2123-    /* skip restoring time stamps on user's request */
2124-    if (uO.D_flag <= 1) {
2125-        gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
2126-
2127-        /* open a handle to the file before processing extra fields;
2128-           we do this in case new security on file prevents us from updating
2129-           time stamps */
2130-        hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
2131-             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2132-    } else {
2133-        gotTime = 0;
2134-    }
2135-
2136-    /* sfield@microsoft.com: set attributes before time in case we decide to
2137-       support other filetime members later.  This also allows us to apply
2138-       attributes before the security is changed, which may prevent this
2139-       from succeeding otherwise.  Also, since most files don't have
2140-       any interesting attributes, only change them if something other than
2141-       FILE_ATTRIBUTE_ARCHIVE appears in the attributes.  This works well
2142-       as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
2143-       file anyway, when it's created new. */
2144-    if ((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
2145-        if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
2146-            Info(slide, 1, ((char *)slide,
2147-              "\nwarning (%d): could not set file attributes\n",
2148-              (int)GetLastError()));
2149-    }
2150+      /* Close the file and then re-open it using the Win32
2151+       * CreateFile call, so that the file can be created
2152+       * with GENERIC_WRITE access, otherwise the SetFileTime
2153+       * call will fail. */
2154+      fclose(G.outfile);
2155+
2156+      /* don't set the time stamp and attributes on standard output */
2157+      if (uO.cflag)
2158+          return;
2159+
2160+      gotTime = getNTfiletime(__G__ &Modft, &Accft, &Creft);
2161+
2162+      /* open a handle to the file before processing extra fields;
2163+         we do this in case new security on file prevents us from updating
2164+         time stamps */
2165+      hFile = CreateFileA(Ansi_Fname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
2166+           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2167+
2168+      /* sfield@microsoft.com: set attributes before time in case we decide to
2169+         support other filetime members later.  This also allows us to apply
2170+         attributes before the security is changed, which may prevent this
2171+         from succeeding otherwise.  Also, since most files don't have
2172+         any interesting attributes, only change them if something other than
2173+         FILE_ATTRIBUTE_ARCHIVE appears in the attributes.  This works well
2174+         as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
2175+         file anyway, when it's created new. */
2176+      if((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
2177+          if (!SetFileAttributesA(Ansi_Fname, G.pInfo->file_attr & 0x7F))
2178+              Info(slide, 1, ((char *)slide,
2179+                "\nwarning (%d): could not set file attributes\n",
2180+                (int)GetLastError()));
2181+      }
2182 
2183 #ifdef NTSD_EAS
2184-    /* set NTFS SD extra fields */
2185-    if (G.extra_field &&    /* zipfile extra field may have extended attribs */
2186-        FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
2187-                         &ebSDptr, &ebSDlen))
2188-    {
2189+      /* set NTFS SD extra fields */
2190+      if (G.extra_field &&    /* zipfile extra field may have extended attribs */
2191+          FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
2192+                           &ebSDptr, &ebSDlen))
2193+      {
2194+# if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2195+        /* no win32_wide implies "no NT SD support", so FindSDExtraField
2196+         * will never return "success".
2197+         */
2198+# else /* (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
2199         int err = SetSD(__G__ Ansi_Fname, G.pInfo->file_attr,
2200                         ebSDptr, ebSDlen);
2201@@ -1131,9 +1255,10 @@
2202               ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":""));
2203         }
2204-    }
2205+# endif /* ? (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
2206+      }
2207 #endif /* NTSD_EAS */
2208 
2209-    /* skip restoring time stamps on user's request */
2210-    if (uO.D_flag <= 1) {
2211+      /* skip restoring time stamps on user's request */
2212+      if (uO.D_flag <= 1) {
2213         if ( hFile == INVALID_HANDLE_VALUE )
2214             Info(slide, 1, ((char *)slide,
2215@@ -1152,10 +1277,101 @@
2216             CloseHandle(hFile);
2217         }
2218-    }
2219+      }
2220 
2221-    return;
2222+      return;
2223 
2224 #undef Ansi_Fname
2225 
2226+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2227+    } else {
2228+      /* wide version */
2229+
2230+#ifndef __RSXNT__
2231+      if (IsWinNT()) {
2232+          /* Truncate the file to the current position.
2233+           * This is needed to remove excess allocation in case the
2234+           * extraction has failed or stopped prematurely. */
2235+          SetEndOfFile((HANDLE)_get_osfhandle(fileno(G.outfile)));
2236+      }
2237+#endif
2238+
2239+      /* Close the file and then re-open it using the Win32
2240+       * CreateFile call, so that the file can be created
2241+       * with GENERIC_WRITE access, otherwise the SetFileTime
2242+       * call will fail. */
2243+      fclose(G.outfile);
2244+
2245+      /* don't set the time stamp and attributes on standard output */
2246+      if (uO.cflag)
2247+          return;
2248+
2249+      gotTime = getNTfiletimeW(__G__ &Modft, &Accft, &Creft);
2250+
2251+      /* open a handle to the file before processing extra fields;
2252+         we do this in case new security on file prevents us from updating
2253+         time stamps */
2254+      hFile = CreateFileW(G.unipath_widefilename,
2255+           GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
2256+           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2257+
2258+      /* sfield@microsoft.com: set attributes before time in case we decide to
2259+         support other filetime members later.  This also allows us to apply
2260+         attributes before the security is changed, which may prevent this
2261+         from succeeding otherwise.  Also, since most files don't have
2262+         any interesting attributes, only change them if something other than
2263+         FILE_ATTRIBUTE_ARCHIVE appears in the attributes.  This works well
2264+         as an optimization because FILE_ATTRIBUTE_ARCHIVE gets applied to the
2265+         file anyway, when it's created new. */
2266+      if((G.pInfo->file_attr & 0x7F) & ~FILE_ATTRIBUTE_ARCHIVE) {
2267+          if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F))
2268+              Info(slide, 1, ((char *)slide,
2269+                "\nwarning (%d): could not set file attributes\n",
2270+                (int)GetLastError()));
2271+      }
2272+
2273+#ifdef NTSD_EAS
2274+      /* set NTFS SD extra fields */
2275+      if (G.extra_field &&    /* zipfile extra field may have extended attribs */
2276+          FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
2277+                           &ebSDptr, &ebSDlen))
2278+      {
2279+          int err = SetSD(__G__ G.unipath_widefilename, G.pInfo->file_attr,
2280+                          ebSDptr, ebSDlen);
2281+
2282+          if (err == IZ_EF_TRUNC) {
2283+              if (uO.qflag)
2284+                  Info(slide, 1, ((char *)slide, "%-22s ",
2285+                    FnFilter1(G.filename)));
2286+              Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
2287+                ebSDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), uO.qflag? "\n":""));
2288+          }
2289+      }
2290+#endif /* NTSD_EAS */
2291+
2292+      /* skip restoring time stamps on user's request */
2293+      if (uO.D_flag <= 1) {
2294+        if ( hFile == INVALID_HANDLE_VALUE )
2295+            Info(slide, 1, ((char *)slide,
2296+              "\nCreateFile() error %d when trying set file time\n",
2297+              (int)GetLastError()));
2298+        else {
2299+            if (gotTime) {
2300+                FILETIME *pModft = (gotTime & EB_UT_FL_MTIME) ? &Modft : NULL;
2301+                FILETIME *pAccft = (gotTime & EB_UT_FL_ATIME) ? &Accft : NULL;
2302+                FILETIME *pCreft = (gotTime & EB_UT_FL_CTIME) ? &Creft : NULL;
2303+
2304+                if (!SetFileTime(hFile, pCreft, pAccft, pModft))
2305+                    Info(slide, 0, ((char *)slide,
2306+                      "\nSetFileTime failed: %d\n", (int)GetLastError()));
2307+            }
2308+            CloseHandle(hFile);
2309+        }
2310+      }
2311+
2312+      return;
2313+
2314+    }
2315+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2316+
2317 } /* end function close_outfile() */
2318 
2319@@ -1225,8 +1441,76 @@
2320 
2321 
2322+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2323+int defer_dir_attribsw(__G__ pdw)
2324+    __GDEF
2325+    direntryw **pdw;
2326+{
2327+    NTdirattrw *d_entryw;
2328+#ifdef NTSD_EAS
2329+    uch *ebSDptr;
2330+    unsigned ebSDlen;
2331+#endif
2332+
2333+    /* Win9x does not support setting directory time stamps. */
2334+    if (!IsWinNT()) {
2335+        *pdw = (direntryw *)NULL;
2336+        return PK_OK;
2337+    }
2338+
2339+#ifdef NTSD_EAS
2340+    /* set extended attributes from extra fields */
2341+    if (G.extra_field &&  /* zipfile e.f. may have extended attribs */
2342+        FindSDExtraField(__G__ G.extra_field, G.lrec.extra_field_length,
2343+                         &ebSDptr, &ebSDlen)) {
2344+        /* ebSDlen contains the payload size of the e.f. block, but
2345+           we store it including the e.b. header. */
2346+        ebSDlen += EB_HEADSIZE;
2347+    } else {
2348+        /* no NTSD e.f. block -> no space needed to allocate */
2349+        ebSDlen = 0;
2350+    }
2351+#endif /* NTSD_EAS */
2352+
2353+    d_entryw = (NTdirattrw *)malloc(sizeof(NTdirattrw)
2354+#ifdef NTSD_EAS
2355+                                  + ebSDlen
2356+#endif
2357+                                  + (wcslen(G.unipath_widefilename)
2358+                                     * sizeof(wchar_t)));
2359+    *pdw = (direntryw *)d_entryw;
2360+    if (d_entryw == (NTdirattrw *)NULL) {
2361+        return PK_MEM;
2362+    }
2363+#ifdef NTSD_EAS
2364+    if (ebSDlen > 0)
2365+        memcpy(d_entryw->buf, ebSDptr, ebSDlen);
2366+    d_entryw->SDlen = ebSDlen;
2367+    d_entryw->fnw = d_entryw->buf + ebSDlen;
2368+#else
2369+    d_entryw->fnw = d_entryw->buf;
2370+#endif
2371+
2372+    wcscpy(d_entryw->fnw, G.unipath_widefilename);
2373+
2374+    d_entryw->perms = G.pInfo->file_attr;
2375+
2376+    d_entryw->gotTime = (uO.D_flag <= 0
2377+                         ? getNTfiletimeW(__G__ &(d_entryw->Modft),
2378+                                          &(d_entryw->Accft),
2379+                                          &(d_entryw->Creft))
2380+                         : 0);
2381+    return PK_OK;
2382+} /* end function defer_dir_attribsw() */
2383+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2384+
2385+
2386 int set_direc_attribs(__G__ d)
2387     __GDEF
2388     direntry *d;
2389 {
2390+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2391+    /* Win9x does not support setting directory time stamps. */
2392+    return PK_OK;
2393+#else /* ! (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
2394     int errval;
2395     HANDLE hFile = INVALID_HANDLE_VALUE;        /* File handle defined in NT */
2396@@ -1320,6 +1604,107 @@
2397 
2398     return errval;
2399+#endif /* ? (defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)) */
2400 } /* end function set_direc_attribs() */
2401 
2402+
2403+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2404+int set_direc_attribsw(__G__ dw)
2405+    __GDEF
2406+    direntryw *dw;
2407+{
2408+    int errval;
2409+    HANDLE hFile = INVALID_HANDLE_VALUE;        /* File handle defined in NT */
2410+
2411+    /* Win9x does not support setting directory time stamps. */
2412+    if (!IsWinNT())
2413+        return PK_OK;
2414+
2415+    errval = PK_OK;
2416+
2417+    /* Skip restoring directory time stamps on user' request. */
2418+    if (uO.D_flag <= 0) {
2419+        /* Open a handle to the directory before processing extra fields;
2420+           we do this in case new security on file prevents us from updating
2421+           time stamps.
2422+           Although the WIN32 documentation recommends to use GENERIC_WRITE
2423+           access flag to create the handle for SetFileTime(), this is too
2424+           demanding for directories with the "read-only" attribute bit set.
2425+           So we use the more specific flag FILE_WRITE_ATTRIBUTES here to
2426+           request the minimum required access rights. (This problem is a
2427+           Windows bug that has been silently fixed in Windows XP SP2.) */
2428+        hFile = CreateFileW(dw->fnw, FILE_WRITE_ATTRIBUTES,
2429+                            FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
2430+                            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2431+    }
2432+
2433+#ifdef NTSD_EAS
2434+    if (NtAtt(dw)->SDlen > 0) {
2435+        int err;
2436+
2437+        if (QCOND2) {
2438+            char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all);
2439+            Info(slide, 1, ((char *)slide, " set attrib: %-22s  ",
2440+              FnFilter1(fn)));
2441+            free(fn);
2442+        }
2443+
2444+        /* set NTFS SD extra fields */
2445+        err = SetSD(__G__ dw->fnw, NtAtt(dw)->perms,
2446+                        NtAtt(dw)->buf, NtAtt(dw)->SDlen - EB_HEADSIZE);
2447+        if (err == IZ_EF_TRUNC) {
2448+            if (!QCOND2) {
2449+                char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all);
2450+                Info(slide, 1, ((char *)slide, "%-22s  ",
2451+                  FnFilter1(fn)));
2452+                free(fn);
2453+            }
2454+            Info(slide, 1, ((char *)slide, LoadFarString(TruncNTSD),
2455+              NtAtt(dw)->SDlen-(EB_NTSD_L_LEN+EB_CMPRHEADLEN), "\n"));
2456+        } else if (QCOND2) {
2457+            Info(slide, 0, ((char *)slide, "\n"));
2458+        }
2459+        if (errval < err)
2460+            errval = err;
2461+    }
2462+#endif /* NTSD_EAS */
2463+
2464+    /* Skip restoring directory time stamps on user' request. */
2465+    if (uO.D_flag <= 0) {
2466+        if (hFile == INVALID_HANDLE_VALUE) {
2467+            char *fn = wchar_to_local_string(dw->fnw, G.unicode_escape_all);
2468+            Info(slide, 1, ((char *)slide,
2469+              "warning: CreateFile() error %d (set file times for %s)\n",
2470+              (int)GetLastError(), FnFilter1(fn)));
2471+            free(fn);
2472+            if (!errval)
2473+                errval = PK_WARN;
2474+        } else {
2475+            if (NtAtt(dw)->gotTime) {
2476+                FILETIME *pModft = (NtAtt(dw)->gotTime & EB_UT_FL_MTIME)
2477+                                  ? &(NtAtt(dw)->Modft) : NULL;
2478+                FILETIME *pAccft = (NtAtt(dw)->gotTime & EB_UT_FL_ATIME)
2479+                                  ? &(NtAtt(dw)->Accft) : NULL;
2480+                FILETIME *pCreft = (NtAtt(dw)->gotTime & EB_UT_FL_CTIME)
2481+                                  ? &(NtAtt(dw)->Creft) : NULL;
2482+
2483+                if (!SetFileTime(hFile, pCreft, pAccft, pModft)) {
2484+                    char *fn = wchar_to_local_string(dw->fnw,
2485+                                                     G.unicode_escape_all);
2486+                    Info(slide, 0, ((char *)slide,
2487+                      "warning:  SetFileTime() for %s error %d\n",
2488+                      FnFilter1(fn), (int)GetLastError()));
2489+                    free(fn);
2490+                    if (!errval)
2491+                        errval = PK_WARN;
2492+                }
2493+            }
2494+            CloseHandle(hFile);
2495+        }
2496+    }
2497+
2498+    return errval;
2499+} /* end function set_direc_attribsw() */
2500+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2501+
2502 #endif /* SET_DIR_ATTRIB */
2503 
2504@@ -1419,5 +1804,5 @@
2505 #endif
2506 
2507-    if ((!strncmp(name, "//", 2) || !strncmp(name, "\\\\", 2)) &&
2508+    if ((!strncmp(name, "//", 2) || !strncmp(name,"\\\\", 2)) &&
2509         (name[2] != '\0' && name[2] != '/' && name[2] != '\\')) {
2510         /* GetFullPathname() and GetVolumeInformation() do not work
2511@@ -1467,4 +1852,63 @@
2512 
2513 
2514+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2515+static int NTQueryVolInfoW(__GPRO__ const wchar_t *namew)
2516+{
2517+ /* static char lastRootPath[4] = ""; */
2518+ /* static int lastVolOldFAT; */
2519+ /* static int lastVolLocTim; */
2520+    wchar_t *tmp0w;
2521+    wchar_t tmp1w[MAX_PATH], tmp2w[MAX_PATH];
2522+    DWORD volSerNo, maxCompLen, fileSysFlags;
2523+
2524+    if ((!wcsncmp(namew, L"//", 2) || !wcsncmp(namew, L"\\\\", 2)) &&
2525+        (namew[2] != '\0' && namew[2] != '/' && namew[2] != '\\')) {
2526+        /* GetFullPathname() and GetVolumeInformation() do not work
2527+         * on UNC names. For now, we return "error".
2528+         * **FIXME**: check if UNC name is mapped to a drive letter
2529+         *            and use mapped drive for volume info query.
2530+         */
2531+        return FALSE;
2532+    }
2533+    if (iswalpha(namew[0]) && (namew[1] == ':'))
2534+        tmp0w = (wchar_t *)namew;
2535+    else
2536+    {
2537+        if (!GetFullPathNameW(namew, MAX_PATH, tmp1w, &tmp0w))
2538+            return FALSE;
2539+        tmp0w = &tmp1w[0];
2540+    }
2541+    if (wcsncmp(G.lastRootPathw, tmp0w, 2) != 0) {
2542+        /* For speed, we skip repeated queries for the same device */
2543+        wcsncpy(G.lastRootPathw, tmp0w, 2); /* Build the root path name, */
2544+        G.lastRootPathw[2] = '/';           /* e.g. "A:/"                */
2545+        G.lastRootPathw[3] = '\0';
2546+
2547+        if (!GetVolumeInformationW(G.lastRootPathw,
2548+              tmp1w, (DWORD)MAX_PATH,
2549+              &volSerNo, &maxCompLen, &fileSysFlags,
2550+              tmp2w, (DWORD)MAX_PATH)) {
2551+            G.lastRootPathw[0] = '\0';
2552+            return FALSE;
2553+        }
2554+
2555+        /*  LFNs are available if the component length is > 12 */
2556+        G.lastVolOldFAT = (maxCompLen <= 12);
2557+/*      G.lastVolOldFAT = !strncmp(strupr(tmp2), "FAT", 3);   old version */
2558+
2559+        /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
2560+         * local time!
2561+         */
2562+        G.lastVolLocTim = !wcsncmp(_wcsupr(tmp2w), L"VFAT", 4) ||
2563+                          !wcsncmp(tmp2w, L"HPFS", 4) ||
2564+                          !wcsncmp(tmp2w, L"FAT", 3);
2565+    }
2566+
2567+    return TRUE;
2568+
2569+} /* end function NTQueryVolInfoW() */
2570+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2571+
2572+
2573 
2574 
2575@@ -1478,4 +1922,11 @@
2576 }
2577 
2578+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2579+static int IsVolumeOldFATw(__GPRO__ const wchar_t *namew)
2580+{
2581+    return (NTQueryVolInfoW(__G__ namew) ? G.lastVolOldFAT : FALSE);
2582+}
2583+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2584+
2585 
2586 
2587@@ -1931,13 +2382,253 @@
2588 
2589 
2590+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2591 
2592+/* Win32 wide version */
2593 
2594-/****************************/
2595-/* Function maskDOSdevice() */
2596-/****************************/
2597-
2598-static void maskDOSdevice(__G__ pathcomp)
2599+int mapnamew(__G__ renamed)
2600     __GDEF
2601-    char *pathcomp;
2602+    int renamed;
2603+/*
2604+ * returns:
2605+ *  MPN_OK          - no problem detected
2606+ *  MPN_INF_TRUNC   - caution (truncated filename)
2607+ *  MPN_INF_SKIP    - info "skip entry" (dir doesn't exist)
2608+ *  MPN_ERR_SKIP    - error -> skip entry
2609+ *  MPN_ERR_TOOLONG - error -> path is too long
2610+ *  MPN_NOMEM       - error (memory allocation failed) -> skip entry
2611+ *  [also MPN_VOL_LABEL, MPN_CREATED_DIR]
2612+ */
2613+{
2614+    wchar_t pathcompw[FILNAMSIZ];   /* path-component buffer */
2615+    wchar_t *ppw, *cpw=NULL;         /* character pointers */
2616+    wchar_t *lastsemiw = NULL;      /* pointer to last semi-colon in pathcomp */
2617+    int killed_ddot = FALSE;    /* is set when skipping "../" pathcomp */
2618+    int error;
2619+    register wchar_t workchw;   /* hold the character being tested */
2620+
2621+
2622+/*---------------------------------------------------------------------------
2623+    Initialize various pointers and counters and stuff.
2624+  ---------------------------------------------------------------------------*/
2625+
2626+    /* can create path as long as not just freshening, or if user told us */
2627+    G.create_dirs = (!uO.fflag || renamed);
2628+
2629+    G.created_dir = FALSE;      /* not yet */
2630+    G.renamed_fullpath = FALSE;
2631+    G.fnlen = wcslen(G.unipath_widefilename);
2632+
2633+    if (renamed) {
2634+        cpw = G.unipath_widefilename;    /* point to beginning of renamed name... */
2635+        if (*cpw) do {
2636+            if (*cpw == '\\')    /* convert backslashes to forward */
2637+                *cpw = '/';
2638+        } while (*(++cpw));
2639+        cpw = G.unipath_widefilename;
2640+        /* use temporary rootpath if user gave full pathname */
2641+        if (G.unipath_widefilename[0] == '/') {
2642+            G.renamed_fullpath = TRUE;
2643+            pathcompw[0] = '/';  /* copy the '/' and terminate */
2644+            pathcompw[1] = '\0';
2645+            ++cpw;
2646+        } else if (iswalpha(G.unipath_widefilename[0]) && G.unipath_widefilename[1] == ':') {
2647+            G.renamed_fullpath = TRUE;
2648+            ppw = pathcompw;
2649+            *ppw++ = *cpw++;      /* copy the "d:" (+ '/', possibly) */
2650+            *ppw++ = *cpw++;
2651+            if (*cpw == '/')
2652+                *ppw++ = *cpw++;  /* otherwise add "./"? */
2653+            *ppw = '\0';
2654+        }
2655+    }
2656+
2657+    /* pathcomp is ignored unless renamed_fullpath is TRUE: */
2658+    if ((error = checkdirw(__G__ pathcompw, INIT)) != 0)    /* init path buffer */
2659+        return error;           /* ...unless no mem or vol label on hard disk */
2660+
2661+    *pathcompw = '\0';           /* initialize translation buffer */
2662+    ppw = pathcompw;              /* point to translation buffer */
2663+    if (!renamed) {             /* cp already set if renamed */
2664+        if (uO.jflag)           /* junking directories */
2665+            cpw = wcschr(G.unipath_widefilename, '/');
2666+        if (cpw == NULL)         /* no '/' or not junking dirs */
2667+            cpw = G.unipath_widefilename;    /* point to internal zipfile-member pathname */
2668+        else
2669+            ++cpw;               /* point to start of last component of path */
2670+    }
2671+
2672+/*---------------------------------------------------------------------------
2673+    Begin main loop through characters in filename.
2674+  ---------------------------------------------------------------------------*/
2675+
2676+    for (; (workchw = *cpw) != 0; cpw++) {
2677+
2678+        switch (workchw) {
2679+            case '/':             /* can assume -j flag not given */
2680+                *ppw = '\0';
2681+                maskDOSdevicew(__G__ pathcompw);
2682+                if (wcscmp(pathcompw, L".") == 0) {
2683+                    /* don't botherw appending "./" to the path */
2684+                    *pathcompw = '\0';
2685+                } else if (!uO.ddotflag && wcscmp(pathcompw, L"..") == 0) {
2686+                    /* "../" dir traversal detected, skip over it */
2687+                    *pathcompw = '\0';
2688+                    killed_ddot = TRUE;     /* set "show message" flag */
2689+                }
2690+                /* when path component is not empty, append it now */
2691+                if (*pathcompw != '\0' &&
2692+                    ((error = checkdirw(__G__ pathcompw, APPEND_DIR))
2693+                     & MPN_MASK) > MPN_INF_TRUNC)
2694+                    return error;
2695+                ppw = pathcompw;    /* reset conversion buffer for next piece */
2696+                lastsemiw = (wchar_t *)NULL; /* leave direct. semi-colons alone */
2697+                break;
2698+
2699+            case ':':             /* drive spec not stored, so no colon allowed */
2700+            case '\\':            /* '\\' may come as normal filename char (not */
2701+            case '<':             /*  dir sep char!) from unix-like file system */
2702+            case '>':             /* no redirection symbols allowed either */
2703+            case '|':             /* no pipe signs allowed */
2704+            case '"':             /* no double quotes allowed */
2705+            case '?':             /* no wildcards allowed */
2706+            case '*':
2707+                *ppw++ = '_';      /* these rules apply equally to FAT and NTFS */
2708+                break;
2709+            case ';':             /* start of VMS version? */
2710+                lastsemiw = ppw;    /* remove VMS version later... */
2711+                *ppw++ = ';';      /*  but keep semicolon for now */
2712+                break;
2713+
2714+
2715+            case ' ':             /* keep spaces unless specifically */
2716+                /* NT cannot create filenames with spaces on FAT volumes */
2717+                if (uO.sflag || IsVolumeOldFATw(__G__ G.unipath_widefilename))
2718+                    *ppw++ = '_';
2719+                else
2720+                    *ppw++ = ' ';
2721+                break;
2722+
2723+            default:
2724+                /* allow European characters in filenames: */
2725+                if (iswprint(workchw) || workchw >= 127)
2726+                    *ppw++ = workchw;
2727+        } /* end switch */
2728+
2729+    } /* end while loop */
2730+
2731+    /* Show warning when stripping insecure "parent dir" path components */
2732+    /* For now use standard path for output messages */
2733+    if (killed_ddot && QCOND2) {
2734+        Info(slide, 0, ((char *)slide,
2735+          "warning:  skipped \"../\" path component(s) in %s\n",
2736+          FnFilter1(G.filename)));
2737+        if (!(error & ~MPN_MASK))
2738+            error = (error & MPN_MASK) | PK_WARN;
2739+    }
2740+
2741+/*---------------------------------------------------------------------------
2742+    Report if directory was created (and no file to create:  filename ended
2743+    in '/'), check name to be sure it exists, and combine path and name be-
2744+    fore exiting.
2745+  ---------------------------------------------------------------------------*/
2746+
2747+    if (G.unipath_widefilename[wcslen(G.unipath_widefilename) - 1] == '/') {
2748+        checkdirw(__G__ G.unipath_widefilename, GETPATH);
2749+        if (G.created_dir) {
2750+            if (QCOND2) {
2751+                Info(slide, 0, ((char *)slide, "   creating: %-22s\n",
2752+                  FnFilter1(G.filename)));
2753+            }
2754+
2755+            /* set file attributes:
2756+               The default for newly created directories is "DIR attribute
2757+               flags set", so there is no need to change attributes unless
2758+               one of the DOS style attribute flags is set. The readonly
2759+               attribute need not be masked, since it does not prevent
2760+               modifications in the new directory. */
2761+            if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
2762+                if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F))
2763+                    Info(slide, 1, ((char *)slide,
2764+                      "\nwarning (%d): could not set file attributes for %s\n",
2765+                      (int)GetLastError(), FnFilter1(G.filename)));
2766+            }
2767+
2768+            /* set dir time (note trailing '/') */
2769+            return (error & ~MPN_MASK) | MPN_CREATED_DIR;
2770+        } else if (IS_OVERWRT_ALL) {
2771+            /* overwrite attributes of existing directory on user's request */
2772+
2773+            /* set file attributes: */
2774+            if(G.pInfo->file_attr & (0x7F & ~FILE_ATTRIBUTE_DIRECTORY)) {
2775+                if (!SetFileAttributesW(G.unipath_widefilename, G.pInfo->file_attr & 0x7F))
2776+                    Info(slide, 1, ((char *)slide,
2777+                      "\nwarning (%d): could not set file attributes for %s\n",
2778+                      (int)GetLastError(), FnFilter1(G.filename)));
2779+            }
2780+        }
2781+        /* dir existed already; don't look for data to extract */
2782+        return (error & ~MPN_MASK) | MPN_INF_SKIP;
2783+    }
2784+
2785+    *ppw = '\0';                   /* done with pathcomp:  terminate it */
2786+
2787+    /* if not saving them, remove VMS version numbers (appended "###") */
2788+    if (!uO.V_flag && lastsemiw) {
2789+        ppw = lastsemiw + 1;        /* semi-colon was kept:  expect #'s after */
2790+        while (iswdigit(*ppw))
2791+            ++ppw;
2792+        if (*ppw == '\0')          /* only digits between ';' and end:  nuke */
2793+            *lastsemiw = '\0';
2794+    }
2795+
2796+    maskDOSdevicew(__G__ pathcompw);
2797+
2798+    if (*pathcompw == '\0') {
2799+        Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
2800+          FnFilter1(G.filename)));
2801+        return (error & ~MPN_MASK) | MPN_ERR_SKIP;
2802+    }
2803+
2804+    checkdirw(__G__ pathcompw, APPEND_NAME);  /* returns 1 if truncated: care? */
2805+    checkdirw(__G__ G.unipath_widefilename, GETPATH);
2806+
2807+    if (G.pInfo->vollabel) {    /* set the volume label now */
2808+        char drive[4];
2809+        wchar_t drivew[4];
2810+
2811+        /* Build a drive string, e.g. "b:" */
2812+        drive[0] = (char)('a' + G.nLabelDrive - 1);
2813+        drivew[0] = (wchar_t)('a' + G.nLabelDrive - 1);
2814+        wcscpy(drivew + 1, L":\\");
2815+        if (QCOND2)
2816+            Info(slide, 0, ((char *)slide, "labelling %s %-22s\n", drive,
2817+              FnFilter1(G.filename)));
2818+        if (!SetVolumeLabelW(drivew, G.unipath_widefilename)) {
2819+            Info(slide, 1, ((char *)slide,
2820+              "mapname:  error setting volume label\n"));
2821+            return (error & ~MPN_MASK) | MPN_ERR_SKIP;
2822+        }
2823+        /* success:  skip the "extraction" quietly */
2824+        return (error & ~MPN_MASK) | MPN_INF_SKIP;
2825+    }
2826+
2827+    Trace((stderr, "mapname returns with filename = [%s] (error = %d)\n\n",
2828+      FnFilter1(G.filename), error));
2829+    return error;
2830+
2831+} /* end function mapnamew() */
2832+
2833+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2834+
2835+
2836+
2837+
2838+/****************************/
2839+/* Function maskDOSdevice() */
2840+/****************************/
2841+
2842+static void maskDOSdevice(__G__ pathcomp)
2843+    __GDEF
2844+    char *pathcomp;
2845 {
2846 /*---------------------------------------------------------------------------
2847@@ -1981,4 +2672,40 @@
2848 
2849 
2850+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2851+
2852+static void maskDOSdevicew(__G__ pathcompw)
2853+    __GDEF
2854+    wchar_t *pathcompw;
2855+{
2856+/*---------------------------------------------------------------------------
2857+    Put an underscore in front of the file name if the file name is a
2858+    DOS/WINDOWS device name like CON.*, AUX.*, PRN.*, etc. Trying to
2859+    extract such a file would fail at best and wedge us at worst.
2860+  ---------------------------------------------------------------------------*/
2861+#if !defined(S_IFCHR) && defined(_S_IFCHR)
2862+#  define S_IFCHR _S_IFCHR
2863+#endif
2864+#if !defined(S_ISCHR)
2865+# if defined(_S_ISCHR)
2866+#  define S_ISCHR(m) _S_ISCHR(m)
2867+# elif defined(S_IFCHR)
2868+#  define S_ISCHR(m) ((m) & S_IFCHR)
2869+# endif
2870+#endif
2871+
2872+    if (zstatw(pathcompw, &G.statbuf) == 0 && S_ISCHR(G.statbuf.st_mode)) {
2873+        extent i;
2874+
2875+        /* pathcomp contains a name of a DOS character device (builtin or
2876+         * installed device driver).
2877+         * Prepend a '_' to allow creation of the item in the file system.
2878+         */
2879+        for (i = wcslen(pathcompw) + 1; i > 0; --i)
2880+            pathcompw[i] = pathcompw[i - 1];
2881+        pathcompw[0] = '_';
2882+    }
2883+} /* end function maskDOSdevicew() */
2884+
2885+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2886 
2887 
2888@@ -2080,19 +2807,511 @@
2889             *pEndFAT = pEnd;   /* filename is fine; point at terminating zero */
2890 
2891-        if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
2892-            last_dot[-1] = '_';                /* NO blank in front of '.'! */
2893+        if ((last_dot - pBegin) > 0 && last_dot[-1] == ' ')
2894+            last_dot[-1] = '_';                /* NO blank in front of '.'! */
2895+    }
2896+} /* end function map2fat() */
2897+
2898+
2899+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
2900+
2901+static void map2fatw(pathcompw, pEndFATw)
2902+    wchar_t *pathcompw, **pEndFATw;
2903+{
2904+    wchar_t *ppcw = pathcompw;       /* variable pointer to pathcomp */
2905+    wchar_t *pEndw = *pEndFATw;      /* variable pointer to buildpathFAT */
2906+    wchar_t *pBeginw = *pEndFATw;    /* constant pointer to start of this comp. */
2907+    wchar_t *last_dotw = NULL;      /* last dot not converted to underscore */
2908+    register wchar_t workchw;   /* hold the character being tested */
2909+
2910+
2911+    /* Only need check those characters which are legal in NTFS but not
2912+     * in FAT:  to get here, must already have passed through mapname.
2913+     * Also must truncate path component to ensure 8.3 compliance.
2914+     */
2915+    while ((workchw = *ppcw++) != 0) {
2916+        switch (workchw) {
2917+            case '[':
2918+            case ']':
2919+            case '+':
2920+            case ',':
2921+            case ';':
2922+            case '=':
2923+                *pEndw++ = '_';      /* convert brackets to underscores */
2924+                break;
2925+
2926+            case '.':
2927+                if (pEndw == *pEndFATw) {   /* nothing appended yet... */
2928+                    if (*ppcw == '\0')     /* don't bother appending a */
2929+                        break;            /*  "./" component to the path */
2930+                    else if (*ppcw == '.' && ppcw[1] == '\0') {   /* "../" */
2931+                        *pEndw++ = '.';    /*  add first dot, */
2932+                        *pEndw++ = '.';    /*  add second dot, and */
2933+                        ++ppcw;            /*  skip over to pathcomp's end */
2934+                    } else {              /* FAT doesn't allow null filename */
2935+                        *pEndw++ = '_';    /*  bodies, so map .exrc -> _exrc */
2936+                    }                     /*  (_.exr would keep max 3 chars) */
2937+                } else {                  /* found dot within path component */
2938+                    last_dotw = pEndw;      /*  point at last dot so far... */
2939+                    *pEndw++ = '_';        /*  convert to underscore for now */
2940+                }
2941+                break;
2942+
2943+            default:
2944+                *pEndw++ = workchw;
2945+
2946+        } /* end switch */
2947+    } /* end while loop */
2948+
2949+    *pEndw = '\0';                 /* terminate buildpathFAT */
2950+
2951+    /* NOTE:  keep in mind that pEnd points to the end of the path
2952+     * component, and *pEndFAT still points to the *beginning* of it...
2953+     * Also note that the algorithm does not try to get too fancy:
2954+     * if there are no dots already, the name either gets truncated
2955+     * at 8 characters or the last underscore is converted to a dot
2956+     * (only if more characters are saved that way).  In no case is
2957+     * a dot inserted between existing characters.
2958+     */
2959+    if (last_dotw == NULL) {       /* no dots:  check for underscores... */
2960+        wchar_t *pluw = wcschr(pBeginw, '_');   /* pointer to last underscore */
2961+
2962+        if ((pluw != NULL) &&      /* found underscore: convert to dot? */
2963+            (MIN(pluw - pBeginw, 8) + MIN(pEndw - pluw - 1, 3) > 8)) {
2964+            last_dotw = pluw;       /* be lazy:  drop through to next if-blk */
2965+        } else if ((pEndw - *pEndFATw) > 8) {
2966+            /* no underscore; or converting underscore to dot would save less
2967+               chars than leaving everything in the basename */
2968+            *pEndFATw += 8;        /* truncate at 8 chars */
2969+            **pEndFATw = '\0';
2970+        } else
2971+            *pEndFATw = pEndw;      /* whole thing fits into 8 chars or less */
2972+    }
2973+
2974+    if (last_dotw != NULL) {       /* one dot is OK: */
2975+        *last_dotw = '.';          /* put it back in */
2976+
2977+        if ((last_dotw - pBeginw) > 8) {
2978+            wchar_t *pw, *qw;
2979+            int i;
2980+
2981+            pw = last_dotw;
2982+            qw = last_dotw = pBeginw + 8;
2983+            for (i = 0;  (i < 4) && *pw;  ++i)  /* too many chars in basename: */
2984+                *qw++ = *pw++;                   /*  shift .ext left and trun- */
2985+            *qw = '\0';                         /*  cate/terminate it */
2986+            *pEndFATw = qw;
2987+        } else if ((pEndw - last_dotw) > 4) {    /* too many chars in extension */
2988+            *pEndFATw = last_dotw + 4;
2989+            **pEndFATw = '\0';
2990+        } else
2991+            *pEndFATw = pEndw;   /* filename is fine; point at terminating zero */
2992+
2993+        if ((last_dotw - pBeginw) > 0 && last_dotw[-1] == ' ')
2994+            last_dotw[-1] = '_';                /* NO blank in front of '.'! */
2995+    }
2996+} /* end function map2fatw() */
2997+
2998+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
2999+
3000+
3001+
3002+/***********************/       /* Borrowed from os2.c for UnZip 5.1.        */
3003+/* Function checkdir() */       /* Difference: no EA stuff                   */
3004+/***********************/       /*             HPFS stuff works on NTFS too  */
3005+
3006+int checkdir(__G__ pathcomp, flag)
3007+    __GDEF
3008+    char *pathcomp;
3009+    int flag;
3010+/*
3011+ * returns:
3012+ *  MPN_OK          - no problem detected
3013+ *  MPN_INF_TRUNC   - (on APPEND_NAME) truncated filename
3014+ *  MPN_INF_SKIP    - path doesn't exist, not allowed to create
3015+ *  MPN_ERR_SKIP    - path doesn't exist, tried to create and failed; or path
3016+ *                    exists and is not a directory, but is supposed to be
3017+ *  MPN_ERR_TOOLONG - path is too long
3018+ *  MPN_NOMEM       - can't allocate memory for filename buffers
3019+ */
3020+{
3021+ /* static int rootlen = 0;     */   /* length of rootpath */
3022+ /* static char *rootpath;      */   /* user's "extract-to" directory */
3023+ /* static char *buildpathHPFS; */   /* full path (so far) to extracted file, */
3024+ /* static char *buildpathFAT;  */   /*  both HPFS/EA (main) and FAT versions */
3025+ /* static char *endHPFS;       */   /* corresponding pointers to end of */
3026+ /* static char *endFAT;        */   /*  buildpath ('\0') */
3027+
3028+#   define FN_MASK   7
3029+#   define FUNCTION  (flag & FN_MASK)
3030+
3031+
3032+
3033+/*---------------------------------------------------------------------------
3034+    APPEND_DIR:  append the path component to the path being built and check
3035+    for its existence.  If doesn't exist and we are creating directories, do
3036+    so for this one; else signal success or error as appropriate.
3037+  ---------------------------------------------------------------------------*/
3038+
3039+    if (FUNCTION == APPEND_DIR) {
3040+        char *p = pathcomp;
3041+        int too_long = FALSE;
3042+
3043+        Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
3044+        while ((*G.endHPFS = *p++) != '\0')     /* copy to HPFS filename */
3045+            ++G.endHPFS;
3046+        if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
3047+            p = pathcomp;
3048+            while ((*G.endFAT = *p++) != '\0')  /* copy to FAT filename, too */
3049+                ++G.endFAT;
3050+        } else
3051+            map2fat(pathcomp, &G.endFAT);   /* map into FAT fn, update endFAT */
3052+
3053+        /* GRR:  could do better check, see if overrunning buffer as we go:
3054+         * check endHPFS-buildpathHPFS after each append, set warning variable
3055+         * if within 20 of FILNAMSIZ; then if var set, do careful check when
3056+         * appending.  Clear variable when begin new path. */
3057+
3058+        /* next check:  need to append '/', at least one-char name, '\0' */
3059+        if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
3060+            too_long = TRUE;                    /* check if extracting dir? */
3061+#ifdef FIX_STAT_BUG
3062+        /* Borland C++ 5.0 does not handle a call to stat() well if the
3063+         * directory does not exist (it tends to crash in strange places.)
3064+         * This is apparently a problem only when compiling for GUI rather
3065+         * than console. The code below attempts to work around this problem.
3066+         */
3067+        if (access(G.buildpathFAT, 0) != 0) {
3068+            if (!G.create_dirs) { /* told not to create (freshening) */
3069+                free(G.buildpathHPFS);
3070+                free(G.buildpathFAT);
3071+                /* path doesn't exist:  nothing to do */
3072+                return MPN_INF_SKIP;
3073+            }
3074+            if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
3075+                Info(slide, 1, ((char *)slide,
3076+                  "checkdir error:  path too long: %s\n",
3077+                  FnFilter1(G.buildpathHPFS)));
3078+                free(G.buildpathHPFS);
3079+                free(G.buildpathFAT);
3080+                /* no room for filenames:  fatal */
3081+                return MPN_ERR_TOOLONG;
3082+            }
3083+            if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
3084+                Info(slide, 1, ((char *)slide,
3085+                  "checkdir error:  cannot create %s\n\
3086+                 unable to process %s.\n",
3087+                  FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
3088+                free(G.buildpathHPFS);
3089+                free(G.buildpathFAT);
3090+                /* path didn't exist, tried to create, failed */
3091+                return MPN_ERR_SKIP;
3092+            }
3093+            G.created_dir = TRUE;
3094+        }
3095+#endif /* FIX_STAT_BUG */
3096+        if (SSTAT(G.buildpathFAT, &G.statbuf))   /* path doesn't exist */
3097+        {
3098+            if (!G.create_dirs) { /* told not to create (freshening) */
3099+                free(G.buildpathHPFS);
3100+                free(G.buildpathFAT);
3101+                /* path doesn't exist:  nothing to do */
3102+                return MPN_INF_SKIP;
3103+            }
3104+            if (too_long) {   /* GRR:  should allow FAT extraction w/o EAs */
3105+                Info(slide, 1, ((char *)slide,
3106+                  "checkdir error:  path too long: %s\n",
3107+                  FnFilter1(G.buildpathHPFS)));
3108+                free(G.buildpathHPFS);
3109+                free(G.buildpathFAT);
3110+                /* no room for filenames:  fatal */
3111+                return MPN_ERR_TOOLONG;
3112+            }
3113+            if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
3114+                Info(slide, 1, ((char *)slide,
3115+                  "checkdir error:  cannot create %s\n\
3116+                 unable to process %s.\n",
3117+                  FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
3118+                free(G.buildpathHPFS);
3119+                free(G.buildpathFAT);
3120+                /* path didn't exist, tried to create, failed */
3121+                return MPN_ERR_SKIP;
3122+            }
3123+            G.created_dir = TRUE;
3124+        } else if (!S_ISDIR(G.statbuf.st_mode)) {
3125+            Info(slide, 1, ((char *)slide,
3126+              "checkdir error:  %s exists but is not directory\n   \
3127+              unable to process %s.\n",
3128+              FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
3129+            free(G.buildpathHPFS);
3130+            free(G.buildpathFAT);
3131+            /* path existed but wasn't dir */
3132+            return MPN_ERR_SKIP;
3133+        }
3134+        if (too_long) {
3135+            Info(slide, 1, ((char *)slide,
3136+              "checkdir error:  path too long: %s\n",
3137+               FnFilter1(G.buildpathHPFS)));
3138+            free(G.buildpathHPFS);
3139+            free(G.buildpathFAT);
3140+            /* no room for filenames:  fatal */
3141+            return MPN_ERR_TOOLONG;
3142+        }
3143+        *G.endHPFS++ = '/';
3144+        *G.endFAT++ = '/';
3145+        *G.endHPFS = *G.endFAT = '\0';
3146+        Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now =  [%s]\n",
3147+          FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
3148+        return MPN_OK;
3149+
3150+    } /* end if (FUNCTION == APPEND_DIR) */
3151+
3152+/*---------------------------------------------------------------------------
3153+    GETPATH:  copy full FAT path to the string pointed at by pathcomp (want
3154+    filename to reflect name used on disk, not EAs; if full path is HPFS,
3155+    buildpathFAT and buildpathHPFS will be identical).  Also free both paths.
3156+  ---------------------------------------------------------------------------*/
3157+
3158+    if (FUNCTION == GETPATH) {
3159+        Trace((stderr, "getting and freeing FAT path [%s]\n",
3160+          FnFilter1(G.buildpathFAT)));
3161+        Trace((stderr, "freeing HPFS path [%s]\n",
3162+          FnFilter1(G.buildpathHPFS)));
3163+        strcpy(pathcomp, G.buildpathFAT);
3164+        free(G.buildpathFAT);
3165+        free(G.buildpathHPFS);
3166+        G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
3167+        return MPN_OK;
3168+    }
3169+
3170+/*---------------------------------------------------------------------------
3171+    APPEND_NAME:  assume the path component is the filename; append it and
3172+    return without checking for existence.
3173+  ---------------------------------------------------------------------------*/
3174+
3175+    if (FUNCTION == APPEND_NAME) {
3176+        char *p = pathcomp;
3177+        int error = MPN_OK;
3178+
3179+        Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
3180+        /* The buildpathHPFS buffer has been allocated large enough to
3181+         * hold the complete combined name, so there is no need to check
3182+         * for OS filename size limit overflow within the copy loop.
3183+         */
3184+        while ((*G.endHPFS = *p++) != '\0') {   /* copy to HPFS filename */
3185+            ++G.endHPFS;
3186+        }
3187+        /* Now, check for OS filename size overflow.  When detected, the
3188+         * mapped HPFS name is truncated and a warning message is shown.
3189+         */
3190+        if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
3191+            G.buildpathHPFS[FILNAMSIZ-1] = '\0';
3192+            Info(slide, 1, ((char *)slide,
3193+              "checkdir warning:  path too long; truncating\n \
3194+              %s\n                -> %s\n",
3195+              FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
3196+            error = MPN_INF_TRUNC;  /* filename truncated */
3197+        }
3198+
3199+        /* The buildpathFAT buffer has the same allocated size as the
3200+         * buildpathHPFS buffer, so there is no need for an overflow check
3201+         * within the following copy loop, either.
3202+         */
3203+        if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
3204+            /* copy to FAT filename, too */
3205+            p = pathcomp;
3206+            while ((*G.endFAT = *p++) != '\0')
3207+                ++G.endFAT;
3208+        } else
3209+            /* map into FAT fn, update endFAT */
3210+            map2fat(pathcomp, &G.endFAT);
3211+
3212+        /* Check that the FAT path does not exceed the FILNAMSIZ limit, and
3213+         * truncate when neccessary.
3214+         * Note that truncation can only happen when the HPFS path (which is
3215+         * never shorter than the FAT path) has been already truncated.
3216+         * So, emission of the warning message and setting the error code
3217+         * has already happened.
3218+         */
3219+        if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ)
3220+            G.buildpathFAT[FILNAMSIZ-1] = '\0';
3221+        Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
3222+          FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
3223+
3224+        return error;  /* could check for existence, prompt for new name... */
3225+
3226+    } /* end if (FUNCTION == APPEND_NAME) */
3227+
3228+/*---------------------------------------------------------------------------
3229+    INIT:  allocate and initialize buffer space for the file currently being
3230+    extracted.  If file was renamed with an absolute path, don't prepend the
3231+    extract-to path.
3232+  ---------------------------------------------------------------------------*/
3233+
3234+    if (FUNCTION == INIT) {
3235+        Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
3236+#ifdef ACORN_FTYPE_NFS
3237+        if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+
3238+                                              (uO.acorn_nfs_ext ? 5 : 1)))
3239+#else
3240+        if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1))
3241+#endif
3242+            == NULL)
3243+            return MPN_NOMEM;
3244+#ifdef ACORN_FTYPE_NFS
3245+        if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+
3246+                                             (uO.acorn_nfs_ext ? 5 : 1)))
3247+#else
3248+        if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1))
3249+#endif
3250+            == NULL) {
3251+            free(G.buildpathHPFS);
3252+            return MPN_NOMEM;
3253+        }
3254+        if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
3255+/* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
3256+            if (G.renamed_fullpath && pathcomp[1] == ':')
3257+                *G.buildpathHPFS = (char)ToLower(*pathcomp);
3258+            else if (!G.renamed_fullpath && G.rootlen > 1 &&
3259+                     G.rootpath[1] == ':')
3260+                *G.buildpathHPFS = (char)ToLower(*G.rootpath);
3261+            else {
3262+                char tmpN[MAX_PATH], *tmpP;
3263+                if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
3264+                { /* by definition of MAX_PATH we should never get here */
3265+                    Info(slide, 1, ((char *)slide,
3266+                      "checkdir warning: current dir path too long\n"));
3267+                    return MPN_INF_TRUNC;   /* can't get drive letter */
3268+                }
3269+                G.nLabelDrive = *tmpN - 'a' + 1;
3270+                *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
3271+            }
3272+            G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
3273+            if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
3274+                || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
3275+                free(G.buildpathHPFS);
3276+                free(G.buildpathFAT);
3277+                return MPN_VOL_LABEL;  /* skipping with message */
3278+            }
3279+            *G.buildpathHPFS = '\0';
3280+        } else if (G.renamed_fullpath) /* pathcomp = valid data */
3281+            strcpy(G.buildpathHPFS, pathcomp);
3282+        else if (G.rootlen > 0)
3283+            strcpy(G.buildpathHPFS, G.rootpath);
3284+        else
3285+            *G.buildpathHPFS = '\0';
3286+        G.endHPFS = G.buildpathHPFS;
3287+        G.endFAT = G.buildpathFAT;
3288+        while ((*G.endFAT = *G.endHPFS) != '\0') {
3289+            ++G.endFAT;
3290+            ++G.endHPFS;
3291+        }
3292+        Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
3293+        return MPN_OK;
3294+    }
3295+
3296+/*---------------------------------------------------------------------------
3297+    ROOT:  if appropriate, store the path in rootpath and create it if neces-
3298+    sary; else assume it's a zipfile member and return.  This path segment
3299+    gets used in extracting all members from every zipfile specified on the
3300+    command line.  Note that under OS/2 and MS-DOS, if a candidate extract-to
3301+    directory specification includes a drive letter (leading "x:"), it is
3302+    treated just as if it had a trailing '/'--that is, one directory level
3303+    will be created if the path doesn't exist, unless this is otherwise pro-
3304+    hibited (e.g., freshening).
3305+  ---------------------------------------------------------------------------*/
3306+
3307+#if (!defined(SFX) || defined(SFX_EXDIR))
3308+    if (FUNCTION == ROOT) {
3309+        Trace((stderr, "initializing root path to [%s]\n",
3310+          FnFilter1(pathcomp)));
3311+        if (pathcomp == NULL) {
3312+            G.rootlen = 0;
3313+            return MPN_OK;
3314+        }
3315+        if (G.rootlen > 0)      /* rootpath was already set, nothing to do */
3316+            return MPN_OK;
3317+        if ((G.rootlen = strlen(pathcomp)) > 0) {
3318+            int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
3319+            char *tmproot;
3320+
3321+            if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) {
3322+                G.rootlen = 0;
3323+                return MPN_NOMEM;
3324+            }
3325+            strcpy(tmproot, pathcomp);
3326+            if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
3327+                has_drive = TRUE;   /* drive designator */
3328+            if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') {
3329+                tmproot[--G.rootlen] = '\0';
3330+                had_trailing_pathsep = TRUE;
3331+            }
3332+            if (has_drive && (G.rootlen == 2)) {
3333+                if (!had_trailing_pathsep)   /* i.e., original wasn't "x:/" */
3334+                    add_dot = TRUE;    /* relative path: add '.' before '/' */
3335+            } else if (G.rootlen > 0) {   /* need not check "x:." and "x:/" */
3336+                if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
3337+                {
3338+                    /* path does not exist */
3339+                    if (!G.create_dirs /* || iswild(tmproot) */ ) {
3340+                        free(tmproot);
3341+                        G.rootlen = 0;
3342+                        /* treat as stored file */
3343+                        return MPN_INF_SKIP;
3344+                    }
3345+                    /* create directory (could add loop here scanning tmproot
3346+                     * to create more than one level, but really necessary?) */
3347+                    if (MKDIR(tmproot, 0777) == -1) {
3348+                        Info(slide, 1, ((char *)slide,
3349+                          "checkdir:  cannot create extraction directory: %s\n",
3350+                          FnFilter1(tmproot)));
3351+                        free(tmproot);
3352+                        G.rootlen = 0;
3353+                        /* path didn't exist, tried to create, failed: */
3354+                        /* file exists, or need 2+ subdir levels */
3355+                        return MPN_ERR_SKIP;
3356+                    }
3357+                }
3358+            }
3359+            if (add_dot)                    /* had just "x:", make "x:." */
3360+                tmproot[G.rootlen++] = '.';
3361+            tmproot[G.rootlen++] = '/';
3362+            tmproot[G.rootlen] = '\0';
3363+            if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
3364+                free(tmproot);
3365+                G.rootlen = 0;
3366+                return MPN_NOMEM;
3367+            }
3368+            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
3369+        }
3370+        return MPN_OK;
3371+    }
3372+#endif /* !SFX || SFX_EXDIR */
3373+
3374+/*---------------------------------------------------------------------------
3375+    END:  free rootpath, immediately prior to program exit.
3376+  ---------------------------------------------------------------------------*/
3377+
3378+    if (FUNCTION == END) {
3379+        Trace((stderr, "freeing rootpath\n"));
3380+        if (G.rootlen > 0) {
3381+            free(G.rootpath);
3382+            G.rootlen = 0;
3383+        }
3384+        return MPN_OK;
3385     }
3386-} /* end function map2fat() */
3387 
3388+    return MPN_INVALID; /* should never reach */
3389+
3390+} /* end function checkdir() */
3391 
3392 
3393 
3394-/***********************/       /* Borrowed from os2.c for UnZip 5.1.        */
3395-/* Function checkdir() */       /* Difference: no EA stuff                   */
3396-/***********************/       /*             HPFS stuff works on NTFS too  */
3397+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
3398 
3399-int checkdir(__G__ pathcomp, flag)
3400+/* WIN32 wide version */
3401+
3402+int checkdirw(__G__ pathcompw, flag)
3403     __GDEF
3404-    char *pathcomp;
3405+    wchar_t *pathcompw;
3406     int flag;
3407 /*
3408@@ -2126,16 +3345,20 @@
3409 
3410     if (FUNCTION == APPEND_DIR) {
3411-        char *p = pathcomp;
3412+        wchar_t *pw = pathcompw;
3413         int too_long = FALSE;
3414-
3415-        Trace((stderr, "appending dir segment [%s]\n", FnFilter1(pathcomp)));
3416-        while ((*G.endHPFS = *p++) != '\0')     /* copy to HPFS filename */
3417-            ++G.endHPFS;
3418-        if (!IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
3419-            p = pathcomp;
3420-            while ((*G.endFAT = *p++) != '\0')  /* copy to FAT filename, too */
3421-                ++G.endFAT;
3422+        char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all);
3423+        char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
3424+        /* Could use G.filename from the standard path, but may
3425+           not work well on this port */
3426+        char *fn = wchar_to_local_string(G.unipath_widefilename, G.unicode_escape_all);
3427+
3428+        while ((*G.endHPFSw = *pw++) != '\0')     /* copy to HPFS filename */
3429+            ++G.endHPFSw;
3430+        if (!IsVolumeOldFATw(__G__ G.buildpathHPFSw)) {
3431+            pw = pathcompw;
3432+            while ((*G.endFATw = *pw++) != '\0')  /* copy to FAT filename, too */
3433+                ++G.endFATw;
3434         } else
3435-            map2fat(pathcomp, &G.endFAT);   /* map into FAT fn, update endFAT */
3436+            map2fatw(pathcompw, &G.endFATw);   /* map into FAT fn, update endFAT */
3437 
3438         /* GRR:  could do better check, see if overrunning buffer as we go:
3439@@ -2145,5 +3368,5 @@
3440 
3441         /* next check:  need to append '/', at least one-char name, '\0' */
3442-        if ((G.endHPFS-G.buildpathHPFS) > FILNAMSIZ-3)
3443+        if ((G.endHPFSw-G.buildpathHPFSw) > FILNAMSIZ-3)
3444             too_long = TRUE;                    /* check if extracting dir? */
3445 #ifdef FIX_STAT_BUG
3446@@ -2153,8 +3376,11 @@
3447          * than console. The code below attempts to work around this problem.
3448          */
3449-        if (access(G.buildpathFAT, 0) != 0) {
3450+        if (_waccess(G.buildpathFATw, 0) != 0) {
3451             if (!G.create_dirs) { /* told not to create (freshening) */
3452-                free(G.buildpathHPFS);
3453-                free(G.buildpathFAT);
3454+                free(buildpathHPFS);
3455+                free(buildpathFAT);
3456+                free(fn);
3457+                free(G.buildpathHPFSw);
3458+                free(G.buildpathFATw);
3459                 /* path doesn't exist:  nothing to do */
3460                 return MPN_INF_SKIP;
3461@@ -2163,28 +3389,40 @@
3462                 Info(slide, 1, ((char *)slide,
3463                   "checkdir error:  path too long: %s\n",
3464-                  FnFilter1(G.buildpathHPFS)));
3465-                free(G.buildpathHPFS);
3466-                free(G.buildpathFAT);
3467+                  FnFilter1(fn)));
3468+                free(buildpathHPFS);
3469+                free(buildpathFAT);
3470+                free(fn);
3471+                free(G.buildpathHPFSw);
3472+                free(G.buildpathFATw);
3473                 /* no room for filenames:  fatal */
3474                 return MPN_ERR_TOOLONG;
3475             }
3476-            if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
3477-                Info(slide, 1, ((char *)slide,
3478-                  "checkdir error:  cannot create %s\n\
3479-                 unable to process %s.\n",
3480-                  FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
3481-                free(G.buildpathHPFS);
3482-                free(G.buildpathFAT);
3483-                /* path didn't exist, tried to create, failed */
3484-                return MPN_ERR_SKIP;
3485-            }
3486-            G.created_dir = TRUE;
3487+			{
3488+				int i = MKDIRW(G.buildpathFATw, 0777);
3489+				if (i == -1) { /* create the directory */
3490+					Info(slide, 1, ((char *)slide,
3491+					  "checkdir error:  cannot create %s\n\
3492+					 unable to process %s.\n",
3493+					  FnFilter2(buildpathFAT), FnFilter1(fn)));
3494+					free(buildpathHPFS);
3495+					free(buildpathFAT);
3496+					free(fn);
3497+					free(G.buildpathHPFSw);
3498+					free(G.buildpathFATw);
3499+					/* path didn't exist, tried to create, failed */
3500+					return MPN_ERR_SKIP;
3501+				}
3502+				G.created_dir = TRUE;
3503+			}
3504         }
3505 #endif /* FIX_STAT_BUG */
3506-        if (SSTAT(G.buildpathFAT, &G.statbuf))   /* path doesn't exist */
3507+        if (SSTATW(G.buildpathFATw, &G.statbuf))   /* path doesn't exist */
3508         {
3509             if (!G.create_dirs) { /* told not to create (freshening) */
3510-                free(G.buildpathHPFS);
3511-                free(G.buildpathFAT);
3512+                free(buildpathHPFS);
3513+                free(buildpathFAT);
3514+                free(fn);
3515+                free(G.buildpathHPFSw);
3516+                free(G.buildpathFATw);
3517                 /* path doesn't exist:  nothing to do */
3518                 return MPN_INF_SKIP;
3519@@ -2193,28 +3431,41 @@
3520                 Info(slide, 1, ((char *)slide,
3521                   "checkdir error:  path too long: %s\n",
3522-                  FnFilter1(G.buildpathHPFS)));
3523-                free(G.buildpathHPFS);
3524-                free(G.buildpathFAT);
3525+                  FnFilter1(buildpathHPFS)));
3526+                free(buildpathHPFS);
3527+                free(buildpathFAT);
3528+                free(fn);
3529+                free(G.buildpathHPFSw);
3530+                free(G.buildpathFATw);
3531                 /* no room for filenames:  fatal */
3532                 return MPN_ERR_TOOLONG;
3533             }
3534-            if (MKDIR(G.buildpathFAT, 0777) == -1) { /* create the directory */
3535-                Info(slide, 1, ((char *)slide,
3536-                  "checkdir error:  cannot create %s\n\
3537-                 unable to process %s.\n",
3538-                  FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
3539-                free(G.buildpathHPFS);
3540-                free(G.buildpathFAT);
3541-                /* path didn't exist, tried to create, failed */
3542-                return MPN_ERR_SKIP;
3543-            }
3544-            G.created_dir = TRUE;
3545+            {
3546+				char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all);
3547+				int i = MKDIRW(G.buildpathFATw, 0777);
3548+				if (i == -1) { /* create the directory */
3549+					Info(slide, 1, ((char *)slide,
3550+					  "checkdir error:  cannot create %s\n\
3551+					 unable to process %s.\n",
3552+					  FnFilter2(buildpathFAT), FnFilter1(fn)));
3553+					free(buildpathHPFS);
3554+					free(buildpathFAT);
3555+					free(fn);
3556+					free(G.buildpathHPFSw);
3557+					free(G.buildpathFATw);
3558+					/* path didn't exist, tried to create, failed */
3559+					return MPN_ERR_SKIP;
3560+				}
3561+				G.created_dir = TRUE;
3562+			}
3563         } else if (!S_ISDIR(G.statbuf.st_mode)) {
3564             Info(slide, 1, ((char *)slide,
3565               "checkdir error:  %s exists but is not directory\n   \
3566               unable to process %s.\n",
3567-              FnFilter2(G.buildpathFAT), FnFilter1(G.filename)));
3568-            free(G.buildpathHPFS);
3569-            free(G.buildpathFAT);
3570+              FnFilter2(buildpathFAT), FnFilter1(fn)));
3571+              free(buildpathHPFS);
3572+              free(buildpathFAT);
3573+              free(fn);
3574+              free(G.buildpathHPFSw);
3575+              free(G.buildpathFATw);
3576             /* path existed but wasn't dir */
3577             return MPN_ERR_SKIP;
3578@@ -2223,15 +3474,23 @@
3579             Info(slide, 1, ((char *)slide,
3580               "checkdir error:  path too long: %s\n",
3581-               FnFilter1(G.buildpathHPFS)));
3582-            free(G.buildpathHPFS);
3583-            free(G.buildpathFAT);
3584+               FnFilter1(buildpathHPFS)));
3585+                free(buildpathHPFS);
3586+                free(buildpathFAT);
3587+                free(fn);
3588+                free(G.buildpathHPFSw);
3589+                free(G.buildpathFATw);
3590             /* no room for filenames:  fatal */
3591             return MPN_ERR_TOOLONG;
3592         }
3593-        *G.endHPFS++ = '/';
3594-        *G.endFAT++ = '/';
3595-        *G.endHPFS = *G.endFAT = '\0';
3596+        *G.endHPFSw++ = '/';
3597+        *G.endFATw++ = '/';
3598+        *G.endHPFSw = *G.endFATw = '\0';
3599         Trace((stderr, "buildpathHPFS now = [%s]\nbuildpathFAT now =  [%s]\n",
3600-          FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
3601+          FnFilter1(buildpathHPFS), FnFilter2(buildpathFAT)));
3602+        free(buildpathHPFS);
3603+        free(buildpathFAT);
3604+        free(fn);
3605+        //free(G.buildpathHPFSw);
3606+        //free(G.buildpathFATw);
3607         return MPN_OK;
3608 
3609@@ -2245,12 +3504,16 @@
3610 
3611     if (FUNCTION == GETPATH) {
3612+        char *buildpathFAT = wchar_to_local_string(G.buildpathFATw, G.unicode_escape_all);
3613+        char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
3614         Trace((stderr, "getting and freeing FAT path [%s]\n",
3615-          FnFilter1(G.buildpathFAT)));
3616+          FnFilter1(buildpathFAT)));
3617         Trace((stderr, "freeing HPFS path [%s]\n",
3618-          FnFilter1(G.buildpathHPFS)));
3619-        strcpy(pathcomp, G.buildpathFAT);
3620-        free(G.buildpathFAT);
3621-        free(G.buildpathHPFS);
3622-        G.buildpathHPFS = G.buildpathFAT = G.endHPFS = G.endFAT = NULL;
3623+          FnFilter1(buildpathHPFS)));
3624+        wcscpy(pathcompw, G.buildpathFATw);
3625+        free(buildpathFAT);
3626+        free(buildpathHPFS);
3627+        free(G.buildpathFATw);
3628+        free(G.buildpathHPFSw);
3629+        G.buildpathHPFSw = G.buildpathFATw = G.endHPFSw = G.endFATw = NULL;
3630         return MPN_OK;
3631     }
3632@@ -2262,6 +3525,8 @@
3633 
3634     if (FUNCTION == APPEND_NAME) {
3635-        char *p = pathcomp;
3636+        wchar_t *pw = pathcompw;
3637         int error = MPN_OK;
3638+        char *pathcomp = wchar_to_local_string(pathcompw, G.unicode_escape_all);
3639+        char *fn = wchar_to_local_string(G.unipath_widefilename, G.unicode_escape_all);
3640 
3641         Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
3642@@ -2270,16 +3535,19 @@
3643          * for OS filename size limit overflow within the copy loop.
3644          */
3645-        while ((*G.endHPFS = *p++) != '\0') {   /* copy to HPFS filename */
3646-            ++G.endHPFS;
3647+        while ((*G.endHPFSw = *pw++) != '\0') {   /* copy to HPFS filename */
3648+            ++G.endHPFSw;
3649         }
3650         /* Now, check for OS filename size overflow.  When detected, the
3651          * mapped HPFS name is truncated and a warning message is shown.
3652          */
3653-        if ((G.endHPFS-G.buildpathHPFS) >= FILNAMSIZ) {
3654-            G.buildpathHPFS[FILNAMSIZ-1] = '\0';
3655+        if ((G.endHPFSw-G.buildpathHPFSw) >= FILNAMSIZ) {
3656+            char *buildpathHPFS;
3657+            G.buildpathHPFSw[FILNAMSIZ-1] = '\0';
3658+            buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
3659             Info(slide, 1, ((char *)slide,
3660               "checkdir warning:  path too long; truncating\n \
3661               %s\n                -> %s\n",
3662-              FnFilter1(G.filename), FnFilter2(G.buildpathHPFS)));
3663+              FnFilter1(fn), FnFilter2(buildpathHPFS)));
3664+            free(buildpathHPFS);
3665             error = MPN_INF_TRUNC;  /* filename truncated */
3666         }
3667@@ -2289,12 +3557,12 @@
3668          * within the following copy loop, either.
3669          */
3670-        if (G.pInfo->vollabel || !IsVolumeOldFAT(__G__ G.buildpathHPFS)) {
3671+        if (G.pInfo->vollabel || !IsVolumeOldFATw(__G__ G.buildpathHPFSw)) {
3672             /* copy to FAT filename, too */
3673-            p = pathcomp;
3674-            while ((*G.endFAT = *p++) != '\0')
3675-                ++G.endFAT;
3676+            pw = pathcompw;
3677+            while ((*G.endFATw = *pw++) != '\0')
3678+                ++G.endFATw;
3679         } else
3680             /* map into FAT fn, update endFAT */
3681-            map2fat(pathcomp, &G.endFAT);
3682+            map2fatw(pathcompw, &G.endFATw);
3683 
3684         /* Check that the FAT path does not exceed the FILNAMSIZ limit, and
3685@@ -2305,8 +3573,16 @@
3686          * has already happened.
3687          */
3688-        if ((G.endFAT-G.buildpathFAT) >= FILNAMSIZ)
3689-            G.buildpathFAT[FILNAMSIZ-1] = '\0';
3690-        Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
3691-          FnFilter1(G.buildpathHPFS), FnFilter2(G.buildpathFAT)));
3692+        if ((G.endFATw-G.buildpathFATw) >= FILNAMSIZ)
3693+            G.buildpathFATw[FILNAMSIZ-1] = '\0';
3694+        {
3695+          char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
3696+          char *buildpathFAT = wchar_to_local_string(G.buildpathFATw,G.unicode_escape_all);
3697+          Trace((stderr, "buildpathHPFS: %s\nbuildpathFAT:  %s\n",
3698+            FnFilter1(buildpathHPFS), FnFilter2(buildpathFAT)));
3699+          free(buildpathHPFS);
3700+          free(buildpathFAT);
3701+        }
3702+        free(fn);
3703+        free(pathcomp);
3704 
3705         return error;  /* could check for existence, prompt for new name... */
3706@@ -2321,33 +3597,23 @@
3707 
3708     if (FUNCTION == INIT) {
3709-        Trace((stderr, "initializing buildpathHPFS and buildpathFAT to "));
3710-#ifdef ACORN_FTYPE_NFS
3711-        if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+
3712-                                              (uO.acorn_nfs_ext ? 5 : 1)))
3713-#else
3714-        if ((G.buildpathHPFS = (char *)malloc(G.fnlen+G.rootlen+1))
3715-#endif
3716+        Trace((stderr, "initializing buildpathHPFSw and buildpathFATw to "));
3717+        if ((G.buildpathHPFSw = (wchar_t *)malloc((G.fnlen+G.rootlen+1) * sizeof(wchar_t)))
3718             == NULL)
3719             return MPN_NOMEM;
3720-#ifdef ACORN_FTYPE_NFS
3721-        if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+
3722-                                             (uO.acorn_nfs_ext ? 5 : 1)))
3723-#else
3724-        if ((G.buildpathFAT = (char *)malloc(G.fnlen+G.rootlen+1))
3725-#endif
3726+        if ((G.buildpathFATw = (wchar_t *)malloc((G.fnlen+G.rootlen+1) * sizeof(wchar_t)))
3727             == NULL) {
3728-            free(G.buildpathHPFS);
3729+            free(G.buildpathHPFSw);
3730             return MPN_NOMEM;
3731         }
3732         if (G.pInfo->vollabel) { /* use root or renamed path, but don't store */
3733 /* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
3734-            if (G.renamed_fullpath && pathcomp[1] == ':')
3735-                *G.buildpathHPFS = (char)ToLower(*pathcomp);
3736+            if (G.renamed_fullpath && pathcompw[1] == ':')
3737+                *G.buildpathHPFSw = (wchar_t)towlower(*pathcompw);
3738             else if (!G.renamed_fullpath && G.rootlen > 1 &&
3739-                     G.rootpath[1] == ':')
3740-                *G.buildpathHPFS = (char)ToLower(*G.rootpath);
3741+                     G.rootpathw[1] == ':')
3742+                *G.buildpathHPFSw = (wchar_t)towlower(*G.rootpathw);
3743             else {
3744-                char tmpN[MAX_PATH], *tmpP;
3745-                if (GetFullPathNameA(".", MAX_PATH, tmpN, &tmpP) > MAX_PATH)
3746+                wchar_t tmpNw[MAX_PATH], *tmpPw;
3747+                if (GetFullPathNameW(L".", MAX_PATH, tmpNw, &tmpPw) > MAX_PATH)
3748                 { /* by definition of MAX_PATH we should never get here */
3749                     Info(slide, 1, ((char *)slide,
3750@@ -2355,28 +3621,33 @@
3751                     return MPN_INF_TRUNC;   /* can't get drive letter */
3752                 }
3753-                G.nLabelDrive = *tmpN - 'a' + 1;
3754-                *G.buildpathHPFS = (char)(G.nLabelDrive - 1 + 'a');
3755+                G.nLabelDrive = (char)(*tmpNw - 'a' + 1);
3756+                *G.buildpathHPFSw = (wchar_t)(G.nLabelDrive - 1 + 'a');
3757             }
3758-            G.nLabelDrive = *G.buildpathHPFS - 'a' + 1; /* save for mapname() */
3759-            if (uO.volflag == 0 || *G.buildpathHPFS < 'a' /* no labels/bogus? */
3760+            G.nLabelDrive = (char)(*G.buildpathHPFSw - 'a' + 1); /* save for mapname() */
3761+            if (uO.volflag == 0 || *G.buildpathHPFSw < 'a' /* no labels/bogus? */
3762                 || (uO.volflag == 1 && !isfloppy(G.nLabelDrive))) { /* !fixed */
3763-                free(G.buildpathHPFS);
3764-                free(G.buildpathFAT);
3765+                free(G.buildpathHPFSw);
3766+                free(G.buildpathFATw);
3767                 return MPN_VOL_LABEL;  /* skipping with message */
3768             }
3769-            *G.buildpathHPFS = '\0';
3770+            *G.buildpathHPFSw = '\0';
3771         } else if (G.renamed_fullpath) /* pathcomp = valid data */
3772-            strcpy(G.buildpathHPFS, pathcomp);
3773+            wcscpy(G.buildpathHPFSw, pathcompw);
3774         else if (G.rootlen > 0)
3775-            strcpy(G.buildpathHPFS, G.rootpath);
3776+            wcscpy(G.buildpathHPFSw, G.rootpathw);
3777         else
3778-            *G.buildpathHPFS = '\0';
3779-        G.endHPFS = G.buildpathHPFS;
3780-        G.endFAT = G.buildpathFAT;
3781-        while ((*G.endFAT = *G.endHPFS) != '\0') {
3782-            ++G.endFAT;
3783-            ++G.endHPFS;
3784+            *G.buildpathHPFSw = '\0';
3785+        G.endHPFSw = G.buildpathHPFSw;
3786+        G.endFATw = G.buildpathFATw;
3787+        while ((*G.endFATw = *G.endHPFSw) != '\0') {
3788+            ++G.endFATw;
3789+            ++G.endHPFSw;
3790         }
3791-        Trace((stderr, "[%s]\n", FnFilter1(G.buildpathHPFS)));
3792+        {
3793+          char *buildpathHPFS = wchar_to_local_string(G.buildpathHPFSw, G.unicode_escape_all);
3794+          Trace((stderr, "[%s]\n", FnFilter1(buildpathHPFS)));
3795+          free(buildpathHPFS);
3796+        }
3797+
3798         return MPN_OK;
3799     }
3800@@ -2395,7 +3666,9 @@
3801 #if (!defined(SFX) || defined(SFX_EXDIR))
3802     if (FUNCTION == ROOT) {
3803+        char *pathcomp = wchar_to_local_string(pathcompw, G.unicode_escape_all);
3804         Trace((stderr, "initializing root path to [%s]\n",
3805           FnFilter1(pathcomp)));
3806-        if (pathcomp == NULL) {
3807+        free(pathcomp);
3808+        if (pathcompw == NULL) {
3809             G.rootlen = 0;
3810             return MPN_OK;
3811@@ -2403,17 +3676,17 @@
3812         if (G.rootlen > 0)      /* rootpath was already set, nothing to do */
3813             return MPN_OK;
3814-        if ((G.rootlen = strlen(pathcomp)) > 0) {
3815+        if ((G.rootlen = wcslen(pathcompw)) > 0) {
3816             int had_trailing_pathsep=FALSE, has_drive=FALSE, add_dot=FALSE;
3817-            char *tmproot;
3818+            wchar_t *tmprootw;
3819 
3820-            if ((tmproot = (char *)malloc(G.rootlen+3)) == (char *)NULL) {
3821+            if ((tmprootw = (wchar_t *)malloc((G.rootlen+3) * sizeof(wchar_t))) == (wchar_t *)NULL) {
3822                 G.rootlen = 0;
3823                 return MPN_NOMEM;
3824             }
3825-            strcpy(tmproot, pathcomp);
3826-            if (isalpha((uch)tmproot[0]) && tmproot[1] == ':')
3827+            wcscpy(tmprootw, pathcompw);
3828+            if (iswalpha(tmprootw[0]) && tmprootw[1] == ':')
3829                 has_drive = TRUE;   /* drive designator */
3830-            if (tmproot[G.rootlen-1] == '/' || tmproot[G.rootlen-1] == '\\') {
3831-                tmproot[--G.rootlen] = '\0';
3832+            if (tmprootw[G.rootlen-1] == '/' || tmprootw[G.rootlen-1] == '\\') {
3833+                tmprootw[--G.rootlen] = '\0';
3834                 had_trailing_pathsep = TRUE;
3835             }
3836@@ -2422,9 +3695,9 @@
3837                     add_dot = TRUE;    /* relative path: add '.' before '/' */
3838             } else if (G.rootlen > 0) {   /* need not check "x:." and "x:/" */
3839-                if (SSTAT(tmproot, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
3840+                if (SSTATW(tmprootw, &G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
3841                 {
3842                     /* path does not exist */
3843                     if (!G.create_dirs /* || iswild(tmproot) */ ) {
3844-                        free(tmproot);
3845+                        free(tmprootw);
3846                         G.rootlen = 0;
3847                         /* treat as stored file */
3848@@ -2433,12 +3706,15 @@
3849                     /* create directory (could add loop here scanning tmproot
3850                      * to create more than one level, but really necessary?) */
3851-                    if (MKDIR(tmproot, 0777) == -1) {
3852+                    if (MKDIRW(tmprootw, 0777) == -1) {
3853+                        char *tmproot = wchar_to_local_string(tmprootw, G.unicode_escape_all);
3854                         Info(slide, 1, ((char *)slide,
3855                           "checkdir:  cannot create extraction directory: %s\n",
3856                           FnFilter1(tmproot)));
3857                         free(tmproot);
3858+                        free(tmprootw);
3859                         G.rootlen = 0;
3860                         /* path didn't exist, tried to create, failed: */
3861                         /* file exists, or need 2+ subdir levels */
3862+                        free(pathcomp);
3863                         return MPN_ERR_SKIP;
3864                     }
3865@@ -2446,13 +3722,17 @@
3866             }
3867             if (add_dot)                    /* had just "x:", make "x:." */
3868-                tmproot[G.rootlen++] = '.';
3869-            tmproot[G.rootlen++] = '/';
3870-            tmproot[G.rootlen] = '\0';
3871-            if ((G.rootpath = (char *)realloc(tmproot, G.rootlen+1)) == NULL) {
3872-                free(tmproot);
3873+                tmprootw[G.rootlen++] = '.';
3874+            tmprootw[G.rootlen++] = '/';
3875+            tmprootw[G.rootlen] = '\0';
3876+            if ((G.rootpathw = (wchar_t *)realloc(tmprootw, (G.rootlen+1) * sizeof(wchar_t))) == NULL) {
3877+                free(tmprootw);
3878                 G.rootlen = 0;
3879                 return MPN_NOMEM;
3880             }
3881-            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(G.rootpath)));
3882+            {
3883+              char *rootpath = wchar_to_local_string(G.rootpathw, G.unicode_escape_all);
3884+              Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
3885+              free(rootpath);
3886+            }
3887         }
3888         return MPN_OK;
3889@@ -2467,5 +3747,5 @@
3890         Trace((stderr, "freeing rootpath\n"));
3891         if (G.rootlen > 0) {
3892-            free(G.rootpath);
3893+            free(G.rootpathw);
3894             G.rootlen = 0;
3895         }
3896@@ -2475,6 +3755,7 @@
3897     return MPN_INVALID; /* should never reach */
3898 
3899-} /* end function checkdir() */
3900+} /* end function checkdirw() */
3901 
3902+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
3903 
3904 
3905@@ -2809,4 +4090,99 @@
3906 }
3907 
3908+
3909+
3910+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
3911+
3912+int zstat_win32w(__W32STAT_GLOBALS__ const wchar_t *pathw, z_stat *buf)
3913+{
3914+    if (!zstatw(pathw, buf))
3915+    {
3916+        char *path = wchar_to_local_string((wchar_t *)pathw, G.unicode_escape_all);
3917+        /* stat was successful, now redo the time-stamp fetches */
3918+#ifndef NO_W32TIMES_IZFIX
3919+        int fs_uses_loctime = FStampIsLocTimeW(__G__ pathw);
3920+#endif
3921+        HANDLE h;
3922+        FILETIME Modft, Accft, Creft;
3923+
3924+        TTrace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
3925+        h = CreateFileW(pathw, GENERIC_READ,
3926+                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
3927+                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3928+        if (h != INVALID_HANDLE_VALUE) {
3929+            BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
3930+            CloseHandle(h);
3931+
3932+            if (ftOK) {
3933+                FTTrace((stdout, "GetFileTime returned Modft", 0, &Modft));
3934+                FTTrace((stdout, "GetFileTime returned Creft", 0, &Creft));
3935+#ifndef NO_W32TIMES_IZFIX
3936+                if (!fs_uses_loctime) {
3937+                    /*  On a filesystem that stores UTC timestamps, we refill
3938+                     *  the time fields of the struct stat buffer by directly
3939+                     *  using the UTC values as returned by the Win32
3940+                     *  GetFileTime() API call.
3941+                     */
3942+                    NtfsFileTime2utime(&Modft, &(buf->st_mtime));
3943+                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
3944+                        NtfsFileTime2utime(&Accft, &(buf->st_atime));
3945+                    else
3946+                        buf->st_atime = buf->st_mtime;
3947+                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
3948+                        NtfsFileTime2utime(&Creft, &(buf->st_ctime));
3949+                    else
3950+                        buf->st_ctime = buf->st_mtime;
3951+                    TTrace((stdout,"NTFS, recalculated modtime %08lx\n",
3952+                            buf->st_mtime));
3953+                } else
3954+#endif /* NO_W32TIMES_IZFIX */
3955+                {
3956+                    /*  On VFAT and FAT-like filesystems, the FILETIME values
3957+                     *  are converted back to the stable local time before
3958+                     *  converting them to UTC unix time-stamps.
3959+                     */
3960+                    VFatFileTime2utime(&Modft, &(buf->st_mtime));
3961+                    if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
3962+                        VFatFileTime2utime(&Accft, &(buf->st_atime));
3963+                    else
3964+                        buf->st_atime = buf->st_mtime;
3965+                    if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
3966+                        VFatFileTime2utime(&Creft, &(buf->st_ctime));
3967+                    else
3968+                        buf->st_ctime = buf->st_mtime;
3969+                    TTrace((stdout, "VFAT, recalculated modtime %08lx\n",
3970+                            buf->st_mtime));
3971+                }
3972+            }
3973+        }
3974+        free(path);
3975+
3976+        return 0;
3977+    }
3978+#ifdef W32_STATROOT_FIX
3979+    else
3980+    {
3981+        DWORD flags;
3982+
3983+        flags = GetFileAttributesW(pathw);
3984+        if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
3985+            char *path = wchar_to_local_string((wchar_t *)pathw, G.unicode_escape_all);
3986+            Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
3987+                   FnFilter1(path)));
3988+            free(path);
3989+            memset(buf, 0, sizeof(z_stat));
3990+            buf->st_atime = buf->st_ctime = buf->st_mtime =
3991+              dos_to_unix_time(DOSTIME_MINIMUM);        /* 1-1-80 */
3992+            buf->st_mode = S_IFDIR | S_IREAD |
3993+                           ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
3994+            return 0;
3995+        } /* assumes: stat() won't fail on non-dirs without good reason */
3996+    }
3997+#endif /* W32_STATROOT_FIX */
3998+    return -1;
3999+}
4000+
4001+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
4002+
4003 #endif /* W32_STAT_BANDAID */
4004 
4005@@ -2939,6 +4315,5 @@
4006 
4007 
4008-#if 0
4009-#ifdef UNICODE_SUPPORT
4010+#if defined(UNICODE_SUPPORT) && defined(WIN32_WIDE)
4011 wchar_t *utf8_to_wchar_string(utf8_string)
4012   char *utf8_string;       /* path to get utf-8 name for */
4013@@ -3030,22 +4405,40 @@
4014   return qw;
4015 }
4016-#endif /* UNICODE_SUPPORT */
4017-#endif /* 0 */
4018 
4019+int has_win32_wide()
4020+{
4021+  int is_win32_wide;
4022 
4023+  /* test if we have wide function support */
4024 
4025-/* --------------------------------------------------- */
4026-/* Large File Support
4027- *
4028- * Initial functions by E. Gordon and R. Nausedat
4029- * 9/10/2003
4030- * Lifted from Zip 3b, win32.c and place here by Myles Bennett
4031- * 7/6/2004
4032- *
4033- * These implement 64-bit file support for Windows.  The
4034- * defines and headers are in win32/w32cfg.h.
4035- *
4036- * Moved to win32i64.c by Mike White to avoid conflicts in
4037- * same name functions in WiZ using UnZip and Zip libraries.
4038- * 9/25/2003
4039- */
4040+  /* first guess: On "real" WinNT, the WIN32 wide API >>is<< supported. */
4041+  is_win32_wide = IsWinNT();
4042+
4043+  if (!is_win32_wide)
4044+  {
4045+    /* On a non-WinNT environment (Win9x or Win32s), wide functions
4046+     * might although supported when program is linked against the
4047+     * Win9x Unicode support library.
4048+     * => run a check whether a needed API function is supported.
4049+     */
4050+    DWORD r;
4051+    /* get attributes for this directory */
4052+    r = GetFileAttributesA(".");
4053+
4054+    /* r should be 16 = FILE_ATTRIBUTE_DIRECTORY */
4055+    if (r == FILE_ATTRIBUTE_DIRECTORY) {
4056+      /* now see if it works for the wide version */
4057+      r = GetFileAttributesW(L".");
4058+      /* if this fails then we probably don't have wide functions */
4059+      if (r == 0xFFFFFFFF) {
4060+        /* error is probably "This function is only valid in Win32 mode." */
4061+      } else if (r == FILE_ATTRIBUTE_DIRECTORY) {
4062+        /* worked, so assume we have wide support */
4063+        is_win32_wide = TRUE;
4064+      }
4065+    }
4066+  }
4067+  return is_win32_wide;
4068+}
4069+
4070+#endif /* defined(UNICODE_SUPPORT) && defined(WIN32_WIDE) */
4071diff -ru2 unz60d10/windll/vc6/dll/unz32dll.dsp unz60d10_w32w/windll/vc6/dll/unz32dll.dsp
4072--- unz60d10/windll/vc6/dll/unz32dll.dsp	Wed Dec 27 23:25:00 2006
4073+++ unz60d10_w32w/windll/vc6/dll/unz32dll.dsp	Mon Feb 11 02:38:32 2008
4074@@ -46,5 +46,5 @@
4075 # PROP Target_Dir ""
4076 # ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
4077-# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /YX /FD /c
4078+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /YX /FD /c
4079 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
4080 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
4081@@ -72,5 +72,5 @@
4082 # PROP Target_Dir ""
4083 # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
4084-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /YX /FD /c
4085+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /YX /FD /c
4086 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
4087 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
4088@@ -98,5 +98,5 @@
4089 # PROP Target_Dir ""
4090 # ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
4091-# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "ASM_CRC" /YX /FD /c
4092+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../.." /D "NDEBUG" /D "ASM_CRC" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /YX /FD /c
4093 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
4094 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
4095@@ -124,5 +124,5 @@
4096 # PROP Target_Dir ""
4097 # ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /YX /FD /c
4098-# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "ASM_CRC" /YX /FD /c
4099+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "../../.." /D "_DEBUG" /D "ASM_CRC" /D "_WINDOWS" /D "_MBCS" /D "WIN32" /D "WINDLL" /D "DLL" /D "USE_EF_UT_TIME" /D "UNICODE_SUPPORT" /D "WIN32_WIDE" /FR /YX /FD /c
4100 # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
4101 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
4102