Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. diff -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 */
  1149. diff -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 */
  1333. diff -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 */
  1345. diff -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.  
  1373. diff -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)
  1470. diff -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 */
  1553. diff -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,
  1697. diff -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.  
  1725. diff -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"
  1756. diff -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"
  1787. diff -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"
  1818. diff -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"
  1849. diff -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__
  1905. diff -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) */
  4071. diff -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.