summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 19:30:57 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 19:30:57 +0100
commit04664087ad66f5614f82a2cfba3ae4eda15e792b (patch)
tree332090b15fd2db1b93abf40dccf06211d9aba297
downloadzip-04664087ad66f5614f82a2cfba3ae4eda15e792b.tar.gz
Tarball conversion
-rw-r--r--BUGS6
-rw-r--r--Betas_Readme.txt17
-rw-r--r--CHANGES3460
-rw-r--r--INSTALL368
-rw-r--r--LICENSE60
-rw-r--r--README234
-rw-r--r--README.CR119
-rw-r--r--TODO142
-rw-r--r--USexport.msg75
-rw-r--r--WHATSNEW333
-rw-r--r--WHERE261
-rw-r--r--acorn/GMakefile130
-rw-r--r--acorn/ReadMe85
-rw-r--r--acorn/ReadMe.GMakefile16
-rw-r--r--acorn/RunMe1st23
-rw-r--r--acorn/acornzip.c592
-rw-r--r--acorn/makefile115
-rw-r--r--acorn/match.s217
-rw-r--r--acorn/osdep.h28
-rw-r--r--acorn/riscos.c394
-rw-r--r--acorn/riscos.h119
-rw-r--r--acorn/sendbits.s105
-rw-r--r--acorn/srcrenamebin0 -> 6175 bytes
-rw-r--r--acorn/swiven.h59
-rw-r--r--acorn/swiven.s276
-rw-r--r--acorn/zipsfx9
-rw-r--r--acorn/zipup.h16
-rw-r--r--amiga/LMKfile117
-rw-r--r--amiga/README1
-rw-r--r--amiga/amiga.c138
-rw-r--r--amiga/amiga.h54
-rw-r--r--amiga/amigazip.c507
-rw-r--r--amiga/crc_68.a144
-rw-r--r--amiga/deflate.a1053
-rw-r--r--amiga/filedate.c599
-rw-r--r--amiga/makefile.azt304
-rw-r--r--amiga/match.a182
-rw-r--r--amiga/match_68.a273
-rw-r--r--amiga/osdep.h119
-rw-r--r--amiga/smakefile662
-rw-r--r--amiga/stat.c293
-rw-r--r--amiga/z-stat.h95
-rw-r--r--amiga/zipup.h25
-rw-r--r--aosvs/aosvs.c659
-rw-r--r--aosvs/make.cli5
-rw-r--r--api.c718
-rw-r--r--api.h184
-rw-r--r--atari/Makefile111
-rw-r--r--atari/README5
-rw-r--r--atari/atari.c681
-rw-r--r--atari/make_all.mup7
-rw-r--r--atari/make_zip.mup7
-rw-r--r--atari/osdep.h20
-rw-r--r--atari/zipup.h19
-rw-r--r--atheos/Makefile146
-rw-r--r--atheos/README21
-rw-r--r--atheos/atheos.c885
-rw-r--r--atheos/osdep.h64
-rw-r--r--atheos/zipup.h24
-rw-r--r--beos/Contents14
-rw-r--r--beos/Makefile182
-rw-r--r--beos/README31
-rw-r--r--beos/beos.c945
-rw-r--r--beos/osdep.h59
-rw-r--r--beos/zipup.h19
-rw-r--r--bzip2/install.txt258
-rw-r--r--cmsmvs/README.CMS434
-rw-r--r--cmsmvs/README.MVS92
-rw-r--r--cmsmvs/README.MVS.LE286
-rw-r--r--cmsmvs/cczip.exec123
-rw-r--r--cmsmvs/cms.c34
-rw-r--r--cmsmvs/cmsmvs.c442
-rw-r--r--cmsmvs/cmsmvs.h123
-rw-r--r--cmsmvs/cstat.h53
-rw-r--r--cmsmvs/mc.exec95
-rw-r--r--cmsmvs/mvs.c221
-rw-r--r--cmsmvs/mvs.h40
-rw-r--r--cmsmvs/mvs.mki125
-rw-r--r--cmsmvs/pipzip.rexx27
-rw-r--r--cmsmvs/zip.exec66
-rw-r--r--cmsmvs/zip.makefile21
-rw-r--r--cmsmvs/zipcloak.exec66
-rw-r--r--cmsmvs/zipmvsc.job89
-rw-r--r--cmsmvs/zipname.conven200
-rw-r--r--cmsmvs/zipnote.exec66
-rw-r--r--cmsmvs/zipsplit.exec66
-rw-r--r--cmsmvs/zipup.h18
-rw-r--r--cmsmvs/zipvmc.exec48
-rw-r--r--crc32.c732
-rw-r--r--crc32.h60
-rw-r--r--crc_i386.S304
-rw-r--r--crypt.c690
-rw-r--r--crypt.h169
-rw-r--r--deflate.c929
-rw-r--r--ebcdic.h328
-rw-r--r--file_id.diz15
-rw-r--r--fileio.c4903
-rw-r--r--globals.c253
-rw-r--r--human68k/Makefile95
-rw-r--r--human68k/Makefile.gcc78
-rw-r--r--human68k/crc_68.s144
-rw-r--r--human68k/deflate.s1076
-rw-r--r--human68k/human68k.c371
-rw-r--r--human68k/match.s163
-rw-r--r--human68k/osdep.h28
-rw-r--r--human68k/zipup.h16
-rw-r--r--macos/Contents63
-rw-r--r--macos/HISTORY.TXT600
-rw-r--r--macos/README.TXT569
-rw-r--r--macos/ZipLib.h166
-rw-r--r--macos/ZipSx.h167
-rw-r--r--macos/ZpPrj.hqx455
-rw-r--r--macos/osdep.h118
-rw-r--r--macos/readme.1st16
-rw-r--r--macos/source/VolWarn.h69
-rw-r--r--macos/source/charmap.h380
-rw-r--r--macos/source/extrafld.c920
-rw-r--r--macos/source/getenv.c398
-rw-r--r--macos/source/helpers.c479
-rw-r--r--macos/source/helpers.h57
-rw-r--r--macos/source/macglob.h86
-rw-r--r--macos/source/macopen.c363
-rw-r--r--macos/source/macopen.h21
-rw-r--r--macos/source/macos.c1079
-rw-r--r--macos/source/macstuff.c1724
-rw-r--r--macos/source/macstuff.h18
-rw-r--r--macos/source/mactime.c451
-rw-r--r--macos/source/mactime.h61
-rw-r--r--macos/source/pathname.c726
-rw-r--r--macos/source/pathname.h64
-rw-r--r--macos/source/recurse.c442
-rw-r--r--macos/source/recurse.h129
-rw-r--r--macos/source/unixlike.c313
-rw-r--r--macos/source/unixlike.h86
-rw-r--r--macos/source/zip_rc.hqx43
-rw-r--r--macos/zipup.h25
-rw-r--r--man/zip.12840
-rw-r--r--man/zipcloak.1111
-rw-r--r--man/zipnote.185
-rw-r--r--man/zipsplit.169
-rw-r--r--match.S407
-rw-r--r--msdos/README.DOS132
-rw-r--r--msdos/crc_i86.asm497
-rw-r--r--msdos/makebz2.dj2148
-rw-r--r--msdos/makefile.bor197
-rw-r--r--msdos/makefile.dj1126
-rw-r--r--msdos/makefile.dj2136
-rw-r--r--msdos/makefile.emx169
-rw-r--r--msdos/makefile.msc209
-rw-r--r--msdos/makefile.tc177
-rw-r--r--msdos/makefile.wat256
-rw-r--r--msdos/match.asm477
-rw-r--r--msdos/msdos.c1126
-rw-r--r--msdos/osdep.h218
-rw-r--r--msdos/zipup.h16
-rw-r--r--novell/MAKEINIT71
-rw-r--r--novell/Makefile142
-rw-r--r--novell/Netware.c970
-rw-r--r--novell/README9
-rw-r--r--novell/m.cmd9
-rw-r--r--novell/osdep.h205
-rw-r--r--novell/signal.c49
-rw-r--r--novell/zip.lnk25
-rw-r--r--novell/zipup.h16
-rw-r--r--os2/makefile.os2563
-rw-r--r--os2/match32.asm175
-rw-r--r--os2/os2.c481
-rw-r--r--os2/os2acl.c385
-rw-r--r--os2/os2acl.h34
-rw-r--r--os2/os2zip.c1213
-rw-r--r--os2/os2zip.h84
-rw-r--r--os2/osdep.h173
-rw-r--r--os2/zip.def3
-rw-r--r--os2/zipup.h16
-rw-r--r--proginfo/3rdparty.bug114
-rw-r--r--proginfo/ZipPorts285
-rw-r--r--proginfo/algorith.txt68
-rw-r--r--proginfo/ebcdic.msg63
-rw-r--r--proginfo/extrafld.txt1372
-rw-r--r--proginfo/fileinfo.cms231
-rw-r--r--proginfo/infozip.who242
-rw-r--r--proginfo/ntsd.txt111
-rw-r--r--proginfo/perform.dos183
-rw-r--r--proginfo/timezone.txt85
-rw-r--r--proginfo/txtvsbin.txt112
-rw-r--r--proginfo/ziplimit.txt243
-rw-r--r--qdos/IZREADME.SMS600
-rw-r--r--qdos/Makefile.qdos145
-rw-r--r--qdos/Makefile.qlzip141
-rw-r--r--qdos/config.s153
-rw-r--r--qdos/crc68.s99
-rw-r--r--qdos/match.s138
-rw-r--r--qdos/osdep.h33
-rw-r--r--qdos/qdos.c879
-rw-r--r--qdos/qfileio.c233
-rw-r--r--qdos/zipup.h19
-rw-r--r--revision.h139
-rw-r--r--tailor.h887
-rw-r--r--tandem/HISTORY97
-rw-r--r--tandem/README95
-rw-r--r--tandem/commacs94
-rw-r--r--tandem/doit21
-rw-r--r--tandem/macros571
-rw-r--r--tandem/make130
-rw-r--r--tandem/tandem.c889
-rw-r--r--tandem/tandem.h236
-rw-r--r--tandem/tannsk.h19
-rw-r--r--tandem/tanzip.c723
-rw-r--r--tandem/tanzip.h43
-rw-r--r--tandem/zipup.h26
-rw-r--r--theos/Makefile138
-rw-r--r--theos/README34
-rw-r--r--theos/_chmod.c21
-rw-r--r--theos/_fprintf.c26
-rw-r--r--theos/_isatty.c26
-rw-r--r--theos/_rename.c83
-rw-r--r--theos/_setargv.c140
-rw-r--r--theos/_stat.c461
-rw-r--r--theos/charconv.h93
-rw-r--r--theos/osdep.h58
-rw-r--r--theos/stat.h106
-rw-r--r--theos/theos.c556
-rw-r--r--theos/zipup.h19
-rw-r--r--timezone.c815
-rw-r--r--timezone.h83
-rw-r--r--tops20/make.mic35
-rw-r--r--tops20/osdep.h31
-rw-r--r--tops20/rename.mic6
-rw-r--r--tops20/tops20.c574
-rw-r--r--tops20/zipup.h18
-rw-r--r--trees.c1474
-rw-r--r--ttyio.c702
-rw-r--r--ttyio.h229
-rw-r--r--unix/Makefile329
-rw-r--r--unix/Packaging/README44
-rw-r--r--unix/Packaging/pkginfo.in13
-rw-r--r--unix/Packaging/postinstall29
-rw-r--r--unix/Packaging/preinstall.in29
-rw-r--r--unix/Packaging/prototype29
-rw-r--r--unix/README.OS39085
-rw-r--r--unix/configure695
-rw-r--r--unix/osdep.h80
-rw-r--r--unix/unix.c1100
-rw-r--r--unix/zipup.h24
-rw-r--r--util.c1450
-rw-r--r--vms/NOTES.TXT382
-rw-r--r--vms/VMS_ZIP.RNH1467
-rw-r--r--vms/build_zip.com690
-rw-r--r--vms/bzlib.h21
-rw-r--r--vms/cmdline.c1802
-rw-r--r--vms/collect_deps.com89
-rw-r--r--vms/cvthelp.tpu182
-rw-r--r--vms/descrip.mms358
-rw-r--r--vms/descrip_deps.mms207
-rw-r--r--vms/descrip_mkdeps.mms247
-rw-r--r--vms/descrip_src.mms373
-rw-r--r--vms/find_bzip2_lib.com71
-rw-r--r--vms/hlp_lib_next.com17
-rw-r--r--vms/install_vms.txt158
-rw-r--r--vms/mod_dep.com33
-rw-r--r--vms/osdep.h178
-rw-r--r--vms/stream_lf.fdl3
-rw-r--r--vms/unixio_gcc.h27
-rw-r--r--vms/unixlib_gcc.h16
-rw-r--r--vms/vms.c1007
-rw-r--r--vms/vms.h354
-rw-r--r--vms/vms_im.c926
-rw-r--r--vms/vms_msg_gen.c91
-rw-r--r--vms/vms_pk.c600
-rw-r--r--vms/vmsdefs.h320
-rw-r--r--vms/vmsmunch.c434
-rw-r--r--vms/vmsmunch.h55
-rw-r--r--vms/vmszip.c1444
-rw-r--r--vms/zip.opt1
-rw-r--r--vms/zip_cli.cld168
-rw-r--r--vms/zip_cli.help1636
-rw-r--r--vms/zip_msg.msg57
-rw-r--r--vms/zipup.h56
-rw-r--r--win32/README.NT17
-rw-r--r--win32/README.TZ7
-rw-r--r--win32/README.txt10
-rw-r--r--win32/crc_i386.asm330
-rw-r--r--win32/crc_i386.c310
-rw-r--r--win32/crc_lcc.asm166
-rw-r--r--win32/gvmat64.asm513
-rw-r--r--win32/lm32_lcc.asm174
-rw-r--r--win32/makefile.a64134
-rw-r--r--win32/makefile.bor189
-rw-r--r--win32/makefile.dj112
-rw-r--r--win32/makefile.emx304
-rw-r--r--win32/makefile.gcc159
-rw-r--r--win32/makefile.ibm123
-rw-r--r--win32/makefile.lcc125
-rw-r--r--win32/makefile.w10197
-rw-r--r--win32/makefile.w32224
-rw-r--r--win32/makefile.wat197
-rw-r--r--win32/makenoas.w32219
-rw-r--r--win32/match32.asm192
-rw-r--r--win32/nt.c492
-rw-r--r--win32/nt.h75
-rw-r--r--win32/osdep.h617
-rw-r--r--win32/readme.a6442
-rw-r--r--win32/rsxntwin.h173
-rw-r--r--win32/vc6/ReadmeVC.txt10
-rw-r--r--win32/vc6/zip.dsp337
-rw-r--r--win32/vc6/zip.dsw65
-rw-r--r--win32/vc6/zipcloak.dsp264
-rw-r--r--win32/vc6/zipnote.dsp248
-rw-r--r--win32/vc6/zipsplit.dsp248
-rw-r--r--win32/vc6bz2/ReadVCBZ.txt19
-rw-r--r--win32/vc6bz2/zip.dsp381
-rw-r--r--win32/vc6bz2/zip.dsw65
-rw-r--r--win32/win32.c1488
-rw-r--r--win32/win32i64.c115
-rw-r--r--win32/win32zip.c1980
-rw-r--r--win32/win32zip.h42
-rw-r--r--win32/zip.def4
-rw-r--r--win32/zip.rc53
-rw-r--r--win32/zipup.h48
-rw-r--r--windll/VBz64/VBZIP.VBP33
-rw-r--r--windll/VBz64/VBZIP.vbw2
-rw-r--r--windll/VBz64/VBZipBas.bas737
-rw-r--r--windll/VBz64/Vbzipfrm.frm183
-rw-r--r--windll/VBz64/readVB64.txt25
-rw-r--r--windll/Vb/VBZIP.vbw2
-rw-r--r--windll/Vb/VBZipBas.bas458
-rw-r--r--windll/Vb/Vbzip.vbp34
-rw-r--r--windll/Vb/Vbzipfrm.frm130
-rw-r--r--windll/Vb/readmeVB.txt34
-rw-r--r--windll/contents42
-rw-r--r--windll/example.c375
-rw-r--r--windll/example.h54
-rw-r--r--windll/structs.h30
-rw-r--r--windll/visualc/dll/zip32z64.dsp168
-rw-r--r--windll/visualc/dll/zip32z64.dsw29
-rw-r--r--windll/visualc/lib/zip32z64.dsp158
-rw-r--r--windll/visualc/lib/zip32z64.dsw29
-rw-r--r--windll/windll.apsbin0 -> 1652 bytes
-rw-r--r--windll/windll.c176
-rw-r--r--windll/windll.h63
-rw-r--r--windll/windll.rc57
-rw-r--r--windll/windll.txt147
-rw-r--r--windll/windll16.def15
-rw-r--r--windll/windll32.def14
-rw-r--r--windll/ziplib.def15
-rw-r--r--zbz2err.c61
-rw-r--r--zip.c6018
-rw-r--r--zip.h1081
-rw-r--r--zip.txt2027
-rw-r--r--zip30.ann95
-rw-r--r--zip30f.ann61
-rw-r--r--zip30g.ann33
-rw-r--r--zip30h.ann47
-rw-r--r--zipcloak.c771
-rw-r--r--zipcloak.txt75
-rw-r--r--ziperr.h115
-rw-r--r--zipfile.c6820
-rw-r--r--zipnote.c699
-rw-r--r--zipnote.txt63
-rw-r--r--zipsplit.c978
-rw-r--r--zipsplit.txt53
-rw-r--r--zipup.c1922
362 files changed, 119106 insertions, 0 deletions
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..21a9013
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,6 @@
+- zip sometimes crashes on some versions of NetBSD (0.8, 0.9 and early
+ 0.9-current), FreeBSD (<= 1.1) and BSDI (< 1.1) . This is due to a
+ bug in stdio.
+ Upgrading the stdio package in /usr/src/lib/libc/stdio should
+ fix the problem. See *BSD mirrors in src/lib/libc/stdio
+ You must at least replace setvbuf.o in all the libc's with a newer version.
diff --git a/Betas_Readme.txt b/Betas_Readme.txt
new file mode 100644
index 0000000..26e965e
--- /dev/null
+++ b/Betas_Readme.txt
@@ -0,0 +1,17 @@
+Betas are works in progress. When a beta has a seemingly stable set
+of features, we may post a public beta so outside developers can see
+where the code is going and make contributions or comment.
+
+A Release Candidate is a beta that we believe has the full feature
+set that will be released. It's still being tested, and things can
+still change, but we thought it close when we posted it.
+
+We take suggestions, bug fixes, and patches at any time, so send them in.
+
+We make no guarantees as to the state of betas so use at your own risk.
+All code, including releases, are released under the Info-ZIP license.
+
+Enjoy!
+
+Ed Gordon
+20 April 2008
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..751695f
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,3460 @@
+------------------------- August 7th 1996 version 2.2a ------------------
+ 1. QDOS port (Jonathan Hudson)
+ 2. win32 volumelabel handling (Paul)
+ 3. VM/CMS clean up (Greg Hartwig)
+ 4. leading "../" in internal filenames are allowed (Paul)
+ 5. System V packages support (John Bush)
+ 6. Fix handling of atx in zipup() (Onno, Greg)
+ 7. Fixed typo that caused zip -R to dump core (Onno)
+ 8. msdos/makefile.dj2: fix for command line too long when linking zip.exe
+ 9. win95 long filename support with djgpp v2 (Onno, Kimio Itoh)
+------------------------- August 9th 1996 version 2.2b ------------------
+ 1. windll: use wiz instead of wizip (Mike)
+ 2. use z->name NOT z->zname to open files (Onno, Mike)
+------------------------ September 1st 1996 version 2.2c ------------------
+ 1. windll: use fprintf instead of putc to send data to std{out,err} (Mike)
+ 2. os2: make borlandc version detection equal to unzip 5.30d (Kai Uwe)
+ 3. use #elif constructions for msdos,os2 and win32 compiler detection (Onno)
+ 4. fix for incorrect free in zip.c (Onno, Mike, Steve)
+ 5. BeBox port from Chris
+ 6. unix/{configure,Makefile} fixes for SCO Xenix 286 (Tom Schmidt)
+ 7. remove zilog entry from unix/Makefile (Onno)
+ 8. man page fixes (Tom Schmidt)
+ 9. SCO ODT {3,5} fixes (Bill Davidsen)
+------------------------ October 8th 1996 version 2.2d ------------------
+ 1. Fix bug in QDOS patch that broke zipsplit.c (Onno, Paul)
+ 2. Fix a couple of warnings from BorlandC (Mike)
+ 3. msdos/makefile.wat: Delete some more files when cleaning up (Paul)
+ 4. store msdos volumelabels without a dot in them (Paul)
+ 5. clean up of unix/{Makefile,configure,packaging} (Tom Schmidt)
+ 6. make QDOS port case independent (Jonathan Hudson)
+ 7. new amiga SASC makefile (Walter Haidinger)
+ 8. don't truncate filenames in win32's in2ex() (Paul)
+ 9. os2/makefile.os2 update for emx 0.9c (Kai Uwe)
+10. password() function for QDOS (Jonathan)
+11. fix the last(?) free() related bug (Mike)
+12. win32: security descriptors operations (Scott Field)
+13. win32: FILE_SHARE_DELETE is not defined in some win32 compilers (Onno)
+14. win32: fix makefile.wat to include nt.c (Onno)
+------------------------ January 17th 1997 version 2.2e ------------------
+ 1. define USE_CASE_MAP in osdep.h for those ports that need it (Onno)
+ 2. define PROCNAME in osdep.h for those ports that need it (Onno)
+ 3. wild() prototype decl only if PROCNAME defined => delete MSVMS define (Onno)
+ 4. add DOS EMX makefile (E-Yen Tan)
+ 5. include <qdos.h> a little earlier in qdos/qdos.c (Jonathan)
+ 6. add ttyio.o to OBJZ in qdos/Makefile.qdos (Jonathan)
+ 7. remove unused fprintebc define from zip.c (Onno)
+ 8. use the right password routine in ttyio.c for unzip (Mike)
+ 9. BeOS update from Chris
+10. Fix for 'zip -r foo x:' (Paul)
+11. Fix library bug on beos (Chris)
+12. Fix calculating version number (kitoh_@mix.or.jp, Walter Haidinger)
+13. IsWinNT always returned TRUE (Mike)
+14. Windll update from Mike
+15. Improved crc routines for x86 from Scott Field
+16. Detect in unix/configure if we can use crc_i386.S (Onno)
+17. Fix spurious internal logic error (Paul)
+18. Fix to include directory names on the Acorn when needed (Sergio)
+19. include zip.h in mvs.h (Onno, George Carr)
+20. add workaround for AZTEC C compiler bug to revision.h (Paul, Walter)
+21. MVS doesn't have rmdir (George Carr)
+22. define and use USE_ZIPMAIN for WINDLL en VM_CMS (Onno)
+23. Fixes from Greg Hartwig to make CMS standalone versions possible.
+24. Move OS specific encryption stuff to the os specific directories (Christian)
+25. Change password fetching interface in ttyio and crypt (Christian)
+26. Update emx support for 0.9c (Christian)
+27. Define WINDLL instead of MSWIN (Christian)
+28. Extended time stamp extra field format support (Christian)
+29. Support for rsxnt-emx 0.9c win32 compiler (Christian)
+30. Use izshr017b (Christian)
+------------------------ March 11th 1997 version 2.2f ------------------
+ 1. Move makefile.emx, rsxwinnt.h and zip.def to win32 subdir (Kai Uwe)
+ 2. Add win32 target to makefile.os2 to allow cross compilation (Kai Uwe)
+ 3. Fix NTSD_EAS link time failures with win32 (Paul)
+ 4. Fix buffer freed too early in password verification code (Mike)
+ 5. Remove unix/zipgrep and man/zipgrep.1 (sanvila@ctv.es)
+ 6. Only use crc_i386.o when we're using an x86 (Onno, Mark)
+ 7. Remove carriage returns from amiga/crc_68.a (Paul)
+ 8. New windll from Mike
+ 9. Fix typo in os2/os2zip.c (Kai Uwe)
+10. Don't use ctime (last file status change) for unix and qdos cross compile
+ (Greg)
+11. added gccwin32 crosscompilation target (RSXNT) to os2/makefile.os2 (Kai Uwe)
+12. fixed the OS/2 file attribute and time stamp generation for zipping
+ stdin ("-") (Kai Uwe)
+13. fixed the atime and ctime stat fields for the OS/2 Watcom C library
+ (Kai Uwe)
+14. added atime and ctime support for the UT extra field when generated under
+ OS/2, the atime and ctime values are only stored when zipping (Kai Uwe)
+15. qdos patches from Jonathan Hudson mainly for extended time flag handling
+16. amiga aztec compiler bug workaround (Paul)
+17. fix -v output of zipcloak, zipnote and zipsplit (Paul)
+18. new amiga/makefile.azt with targets for debug versions (Paul)
+------------------------ March 31st 1997 version 2.2g ------------------
+ 1. remove -I/usr/local/include from unix/Makefile (Chris)
+ 2. Update versinfolines in revision.h (Greg)
+ 3. change 1U to 0x1 to accomodate non ANSI compilers (Onno, Rodney Brown)
+ 4. win32zip.c: cast buffer parameter in memcompress() to char * (Mike)
+ 5. remove beos/zipgrep (Chris)
+ 6. correct the -e password verification check in zip.c (Christian)
+ 7. use ZCONST instead of const in the generic code. (Christian)
+ 8. fix mktime timezone correction when time is near to daylight/nodaylight
+ switch points. (Christian)
+ 9. correct dependencies in makefile.os2 (Christian)
+10. use a more sensible default for iztime.ctime than "0" when system does not
+ not support creation time stamps. (Christian)
+11. fix VMS_PK_EXTRA function interface declarations. (Christian)
+12. implement atime/ctime support in win32. (Christian)
+13. win32/win32.c: replacement getch() for Watcom. (Paul)
+14. win32/makefile.wat: debug object files kept separate. (Paul)
+15. msdos/makefile.wat: debug object files kept separate. (Paul)
+16. Fix extended time defines for the acorn. (Sergio)
+17. Define PROCNAME() in acorn/osdep.h (Sergio)
+18. Ignore exit status of ${INSTALL_D} in unix/Makefile (Chris)
+19. Add Metroworks and BEOS info to version() in several files (Chris)
+20. Move defines for the password fetch to zip.h (Christian)
+21. Support the obsolete version rsxnt 1.1 / emx 0.9b (Christian)
+22. Remove obsolete "#define PROCNAME ..." from cmsmvs/cmsmvs.h (Christian)
+23. Fix extended time defines for qdos (Jonathan Hudson)
+24. Use watcom getch() from unz530q in win32/win32.c (Onno)
+25. Don't install zipgrep via the unix package tools (John Bush)
+26. use izshr021 (Onno)
+27. Fix zipnote: use iname not zname in zipnote.c (Onno)
+28. Create proginfo directory (Christian)
+------------------------ May 5th 1997 version 2.2h --------------------
+ 1. Fix vms/zipup.h: iztime --> iztimes (Onno, Mike Freeman)
+ 2. Remove windll/wizdll.def (Mike)
+ 3. Add a couple of external variable declaration to windll.h (Mike)
+ 4. Remove zipgrep from install in unix/Makefile (Onno)
+ 5. Make updating .zip files with extended time fields possible (Kai Uwe)
+ 6. Delete beos/Makefile.gcc, beos/Makefiles handles both compilers (Chris)
+ 7. Fixes for unused variables (Chris)
+ 8. Added very simplistic example how to load and call the windll (Mike)
+ 9. Updated windll documentation to note this example (Mike)
+10. Removed an unused memeber of a structure in windll (Mike)
+11. Add BUGS instead of infozip.who and algorith.doc with the packaging
+ tools (John Bush)
+12. tailor.h: increment NUM_HOSTS to keep in sync with UnZip (Christian)
+13. win32/osdep.h: remove NO_SECURE_TESTS define (Christian)
+14. zip.h: add declaration for free_crc_table() (Christian)
+15. windll: move everything that's not windows specific into api.* (Mike)
+16. use iname when checking for directory names in zipfile.c (Sergio)
+17. improved mktime.c with better error checking (Christian)
+18. improved crc routines (Christian, Rodney Brown)
+19. get the -z option working again (Onno, Brad Clarke)
+20. define BROKEN_FSEEK and seekable() for those systems where fseek()
+ always returns 0 (== OK) (Onno, Jeffrey Altman)
+------------------------ May 10th 1997 version 2.2i --------------------
+ 1. win32's seekable should only check for FILE_TYPE_DISK (Onno, Jeffrey Altman)
+ 2. add (ulg) cast to zipbeg = ~0 in zipfile.c (Steve)
+ 3. seekable() *really* belongs in flush_block, keep it there (Onno)
+ 4. seekable() calls fseekable(FILE *) (Onno)
+ 5. define HAVE_FSEEKABLE if a port has their own fseekable (Onno)
+ 6. WatCom doesn't have _get_osfhandle, use _os_handle instead (Paul)
+ 7. upgrade to Mike's latest windll sources (Mike)
+ 8. add -P option so you can specify a password on the commandline (Onno)
+ 9. Get -@ working again (Onno)
+10. emx+RSXNT doesn't know about _get_osfhandle() (Kai Uwe)
+11. fix a couple of typos in the OS/2 makefiles (Kai Uwe)
+12. fix initialization bug in windll code (Mike)
+13. tweak deletedir for RISC OS (Sergio)
+14. RISCOS doesn't know about fstat() (Sergio)
+15. Remove acorn/acorn (Sergio)
+16. Delete debugging statements from version_local() in msdos.c (Greg)
+17. Fix huge bug in readzipfile() (Onno)
+------------------------ May 18th 1997 version 2.2j --------------------
+ 1. Add missing ';' after return ZE_PARMS in zip.c (Mike)
+ 2. Remove obsolete 'struct stat st' in zipfile.c (Onno)
+ 3. Get Amiga SFX handling working again (Paul)
+ 4. Get zip -A working again (Onno)
+ 5. Change an && to & in zipfile.c (Johnny)
+ 6. Fix handling of empty sfx archives (Onno, Mike)
+ 7. Remove experimental entries from the makefiles (Jean-loup)
+ 8. Add exit codes to the manual page (Onno)
+ 9. Remove lines from the help screen that contain lesser used options (Onno)
+------------------------ June 8th 1997 version 2.2k --------------------
+ 1. use zip -t ddmmyyyy for year 2000 stuff (Greg)
+ 2. zip -@ only handles ONE filename per line (Jean-loup)
+ 3. beos support for DR9 filesystem and symlinks (Chris)
+ 4. VB support for windll (Mike)
+------------------------ June 10th 1997 version 2.2l -------------------
+ 1. beos filetype support (Chris)
+ 2. fill the buffer in getnam() to get it working again (Onno)
+ 3. implement -x@filename and -i@filename (Onno)
+------------------------ June 22nd 1997 version 2.2m -------------------
+ 1. Add a ; after de nextarg label in main() (Onno, Erik Baatz)
+ 2. Initialize p to NULL in get_filters() (Onno, Frank Donahoe)
+ 3. Fix typo in first if statement in filetypes() (Johnny Lee)
+ 4. zip -A works again (Onno, Greg)
+ 5. don't free zipbuf for VMS and CMS_MVS in main() (Onno, Mike Freeman)
+ 6. fix make_zip.com, link_zip.com and vmsdefs.h for gcc 2.6.3 on VMS (Onno)
+ 7. clarify -g option in the man page (Jean-loup)
+------------------------ July 6th 1997 version 2.2n -------------------
+ 1. use local in readzipfile2() declaration (Onno, Mike Freeman)
+ 2. return values with windll in get_filters() (Mike)
+ 3. a couple of minor patches for BEOS (Chris)
+ 4. zip -g works again (Onno, Chris)
+ 5. Some more Visual Basic dll support (Mike)
+ 6. Fix stack overflow in readzipfile() for DOS (Onno, Michael Mauch)
+------------------------ August 19th 1997 version 2.2o -------------------
+ 1. beos README and Makefile tweaks from Chris.
+ 2. Syntax corrections for README and man/zip.1 (Frank Donahoe)
+ 3. Use name not iname when deleting directories in trash() (Christian)
+ 4. change several wkuvx1 to lists in e-mail addresses (Christian)
+ 5. default to PK style extra fields for VMS (Christian)
+ 6. use izshr023 (Christian)
+ 7. replace buggy time library functions (Walter Haidinger, Paul, Christian)
+ 8. in2ex() and stat() are needed also when UTIL isn't defined (Greg Hartwig)
+ 9. don't use type=record in fopen() for MVS and CMS (Greg Hartwig)
+10. Change P and K literals to hex for EBCDIC systems (Greg Hartwig)
+11. Add output path support for CMS and MVS (Greg Hartwig)
+12. Add memtoasc and memtoebc for EBCDIC systems (Greg Hartwig)
+13. Handle comments correctly to fix zipnote for CMS and MVS (Greg Hartwig)
+14. Add -tt option (do not operate on files after date mmddyy) (Christian)
+15. move alloc routines for DOS into the !UTIL block (Christian)
+16. move UTIL blocks and version_local() functions to a more logical place
+ (Christian)
+17. Handle -P, -R, -x@, -i@ and -tt for the VMS CLI (Christian)
+18. Update VMS help file with the new options (Christian)
+19. Use iname in MATCH, not zname (Jonathan Hudson)
+20. windll: more Visual Basic support (Mike)
+21. windll: more project makefiles (Mike)
+22. windll: insert Zip in front of global variable names (Mike)
+------------------------ August 25th 1997 version 2.2p -------------------
+ 1. Remove unused flags from LFLAGS2 in unix/Makefile (Onno)
+ 2. SunOS make bug: change unix_.o rule in unix/Makefile (Onno, Mike Freeman)
+ 3. ZipIsWinNT() instead of IsWinNT() in zip.h (Mike)
+ 4. Fix -t and -tt behaviour for windll (Mike)
+ 5. Remove windll makefiles that are now elsewhere (Mike)
+ 6. BEOS: preserve file attributes associated with symbolic links (Chris)
+ 7. No need to use in2ex() for ziputils (Christian)
+ 8. Fix comment handling for EBCDIC systems (Christian)
+ 9. EBCDIC conversion for entry names read from zipfile in UTIL mode (Christian)
+10. Fix "fatal" error messages on EBCDIC systems (Christian)
+11. zipnote.c: Fix handling of entry name changes for EBCDIC systems (Christian)
+12. removed a large part of "dead" code from ziputils version (Christian)
+13. use z->iname in comparison functions for sorting (Christian)
+14. new installation utils for the acorn (Sergio)
+15. use LSSTAT in set_extra_field for unix and beos (Onno)
+16. perror(z->zname) instead of perror("zip warning") (Onno, Geoff Pennington)
+17. Amiga SFX should work again (Paul)
+18. refer to zip22 in install.doc (Frank Donahoe)
+------------------------ September 10th 1997 version 2.2q -------------------
+ 1. Change .doc to .txt, these aren't MS-Word documents (John D. Mitchell)
+ 2. Change msdos$_(OBJ) to msdos_$(OBJ) (Kai Uwe)
+ 3. Fix a couple of amiga related glitches (Paul)
+ 4. Support for DOS packed .exe files in makefile.dj2 (Frank Donahoe)
+ 5. Change warning message for zip -A (Greg)
+------------------------ September 29th 1997 version 2.2r -------------------
+ 1. Fix make svr4package (Eric Baatz)
+ 2. Fix VMS warning (Mike Freeman, Christian)
+ 3. Clean up beos gcc port and beos README (Chris)
+-------------------------- October 6th 1997 version 2.2s --------------------
+ 1. Change lpPrint to lpZipPrint for windll (Mike)
+ 2. Change lpPassword to lpZipPassword for windll (Mike)
+ 3. Amiga timezone fixes (Paul)
+ 4. WatCom C 11.0 makefile fixes (Paul)
+ 5. Tandem port from Dave Smith
+ 6. Corrections and updates for install.txt (Christian)
+ 7. Minor VMS README update (Christian)
+-------------------------- October 12th 1997 version 2.2t --------------------
+ 1. qdos compiler bug workaround (Jonathan)
+ 2. prevent storing qdos specific filenames that exceed filesystem limits
+ (Jonathan)
+ 3. fix undelimited comment in fileio.c (Frank Donahoe)
+ 4. disable storing of symlinks in BEOS until OS support is available (Chris)
+ 5. Init hash_head to 0 in amiga/deflate.a (Paul)
+ 6. Upgrade to izshr025 (Christian)
+ 7. don't add ".zip" to ZIP name for TANDEM (Dave Smith)
+ 8. use zipup.h not tandem.h in zipup.c (Dave Smith)
+ 9. rename history to CHANGES (Onno)
+10. rename install.txt to INSTALL (Onno)
+11. rename zip.txt to ZIPMAN (Onno)
+12. create WHATSNEW (Onno)
+-------------------------- October 15th 1997 version 2.2u --------------------
+ 1. Use Info-ZIP instead of Info-Zip (Christian)
+ 2. Note recent filename changes in several files (Christian)
+ 3. Remove a couple of items from the TODO list (Christian, Onno)
+ 4. Add windll port, zip -t yyyymmdd and zip -R to WHATSNEW (Christian)
+ 5. VMS documentation cleanups and clarifications (Christian)
+ 6. dist entry in unix/Makefile (Onno)
+ 7. remove duplicate amiga/timezone.txt (Christian)
+ 8. rename ZIPMAN to MANUAL and update a couple of files regarding this (Onno)
+-------------------------- October 24th 1997 version 2.2v --------------------
+ 1. izshr026: in WHERE wiz40 instead of wiz30 (Christian)
+ 2. izshr026: another couple of Info-ZIP spelling fixes (Christian)
+ 3. Remove zipgrep from the makefiles that still had it (Christian)
+ 4. Update makefiles to handle the MANUAL renaming change (Christian)
+ 5. Fix the last daylight savings bug on the Amiga (Paul)
+ 6. Fix the SCO Unix specialty detection in unix/configure (Onno,
+ bug reported by Bo Kullmar for Solaris 2.6 and with uname -X output
+ for SCO Unix from ken@apisys.com and dgsmith@vnet.ibm.com)
+ 7. Update WHERE and amiga/time_lib.c from unzip 5.32g (Greg)
+-------------------------- October 26th 1997 version 2.2w --------------------
+ 1. Additional +Onolimit check in unix/configure (Onno, Peter Jones)
+ 2. Use ZIPERR macro instead of ziperr (Christian)
+ 3. initialize z->lflg for zip entries without extra field (Christian)
+ 4. "local (+ locextend)" vs. "central" header consistency check (Christian)
+ 5. Override local header values with central header values with -A
+ and differences between these headers (Christain)
+ 6. made "deltaoff" signed long; offset adjustment may be negative (Christian)
+ 7. fix a number of "wild" deallocation bugs (Christian)
+ 8. When zipping from a FAT drive (only 8.3 DOS names) under OS/2 or
+ WIN32, set z->vem to "OS_DOS | <real zip version number>".
+ Mark as "made by DOS PKZIP 2.0" only when dosify was requested. (Christian)
+ 9. DOS port should not store fake unix style external attributes. (Christian)
+10. amiga/time_lib.c from izshr028 (Christian)
+-------------------------- October 31st 1997 version 2.2y --------------------
+ 1. amiga/time_lib.c from izshr029 (Christian)
+ 2. Turbo C++ version code clarification (E-Yen Tan)
+ 3. Fix spelling in cmsvms/zipname.conven (Rodney Brown)
+ 4. Fix memset check in unix/configure for Unixware 2.1.1 (Rodney Brown)
+ 5. Forward declaration fixes for HP-UX bundled compiler (Rodney Brown)
+-------------------------- November 3rd 1997 version 2.2 --------------------
+ 1. Update WHERE (Greg).
+-------------------------- January 4th 1998 version 2.21a -------------------
+ 1. BSD friendly version of version_local() in unix/unix.c (Onno)
+ 2. No NT versions in DOS version_local() (Steve Salisbury)
+ 3. -t mmddyyyy instead of -t ddmmyyyy in WHATSNEW (Walter Haidinger)
+ 4. use generic fseekable() for rsxnt (Christian)
+ 5. Fix MSC 8.x warnings (Christian, Steve Salisbury)
+ 6. win32 Borland C++ makefile (E-Yen Tan)
+ 7. Tandem doesn't know about extensions like .zip,.arj, ... (Dave Smith)
+ 8. Use dosmatch for EMX and DJGPP too (Christian)
+ 9. dummy djgpp startup functions to remove command line globbing and
+ recognition of environment variables from djgpp.env (Christian)
+10. include DJGPP_MINOR in DOS version_local() (Christian)
+11. TC 2.0 doesn't have mktime() (Christian, mmp@earthling.net)
+12. VMS: rename opendir() to zopendir() so avoiding name clash with
+ VMS 7.x POSIX libraries (Christian, Martin Zinser)
+13. Add support for VMS DEC C V 5.6 features (Christian)
+14. Use iname for comparison in check_dup (Christian Spieler, Christian Michel)
+15. Fix access to uninitialized ioctx records in vms_get_attributes()
+ Christian, Robert Nielsen)
+16. Parenthesis around MAX_MATCH>>1 in match.S (Greg)
+17. Use strchr() not strrchr() for -i and -x to get -i@ and -x@ really
+ working (Onno, Kai Uwe)
+18. add chmod statements to unix/Makefile (Quentin Barnes)
+19. Windll: handle both -r and -R (Mike)
+20. Windll: general error handler in main() via setjmp/longjmp (Mike)
+21. Don't allow zip -i@x.lst foo.zip (Onno)
+22. vms/link_zip.com: use .eqs. not .nes. when checking with f$search
+ for the zip AXP object library (David Dachtera)
+23. rsxnt 1.3.1 fixes (E-Yen Tan)
+-------------------------- January 20th 1998 version 2.21b -------------------
+ 1. Bigger PATH_MAX for win32's windll (Mike)
+ 2. Update windll.txt w.r.t. PATH_MAX (Mike)
+ 3. Amiga SAS/C fixes (Walter, Paul)
+ 4. zip -i@ and -x@ should *really* work now ...... (Onno)
+-------------------------- February 20th 1998 version 2.21c -------------------
+ 1. make -f unix/Makefile qnx needs LN=ln in its options (Chris)
+ 2. Support Metroworks Codewarrior/x86 on BEOS (Chris)
+ 3. Add Norbert Pueschel to proginfo/infozip.who (Walter)
+ 4. Use big endian for Be types (Chris)
+ 5. zip -i and -x were broken by the -i@ fix last time around (Christian)
+ 6. win32 stat bandaid (Paul)
+ 7. acorn filetype and timestamp fixes (Sergio, D. Krumbholz)
+ 8. update to izshr30 (Christian)
+ 9. Support for NTSD in the RSXNT environment (Christian)
+10. restructure readzipfile() (Christian)
+11. Where needed define MATCH in osdep.h (Christian)
+12. version_local() fixes for RSXNT (Christian)
+13. New vmsmunch.c (Christian)
+-------------------------- March 15th 1998 version 2.3a -------------------
+ 1. Fixes for the windll API (Mike)
+ 2. Use CPUTYPE in BorlandC Makefile for DOS (E-Yen Tan)
+ 3. BEOS: -rostr not available for the x86 compiler (Chris)
+ 4. preserve file attributes of a symlink on BEOS (Chris)
+ 5. New VM/CMS README.CMS and version_local() (Ian Gorman)
+ 6. INSTALL fixes from Takahiro Watanabe
+ 7. OS/390 port from Paul von Behren
+ 8. new api.h from Mike
+-------------------------- April 19th 1998 version 2.3b -------------------
+ 1. Improve Tandem file I/O performance (Dave Smith)
+ 2. New VM/CMS README.CMS and version_local() (Ian Gorman)
+ 3. cygwin32 port from Cosmin Truta
+ 4. Workaround for tasm32 5.0 bug in win32/crc_i386.asm (Cosmin Truta)
+ 5. win32/match32.asm fixes for tasm 5.0 (Cosmin Truta)
+ 6. simplify OS/390 port (Christian)
+ 7. win32 timezone handling fixes (Christian)
+ 8. fix 40-bit time conversion on the acorn (Sergio and Christian)
+ 9. strip network part from UNC type filenames (Christian)
+10. Makefile for OpenMVS (Ian Gorman)
+11. Use the Watcom getch() for cygwin32 (Christian)
+12. Borland C++ 5.x added to win32's version_local() (Cosmin Truta)
+13. Borland C++ needs tzset() in win32 (Christian, Cosmin Truta)
+-------------------------- May 21st 1998 version 2.3c -------------------
+ 1. Better error messages for -i and -x (Christian)
+ 2. Win32 stat() wrapper needs dos2unixtime (Christian,Paul,Mike)
+ 3. DJGPP: use _chmod to handle LFN attributes correctly (Michael Mauch)
+ 4. Fix Borlandc warnings (Mike)
+ 5. win32/makefile.bor fixes from Michael Mauch
+ 6. win32/makefile.{dj,emx} fixes from E-Yen Tan
+ 7. Use izshr031 (Christian)
+ 8. CMS: use RECFM=V LRECL=32760 by adding "byteseek" (Greg Hartwig)
+ 9. Check external name for trailing "/" (Greg Hartwig)
+10. More specific info in CMS version_local() (Greg Hartwig)
+11. Changed usage info to refer to "fm" rather than "path" on CMS (Greg Hartwig)
+12. No more "extra data" messages when using the same OS (Greg Hartwig)
+13. Rewritten README.CMS, one version for ZIP and UNZIP (Greg Hartwig)
+14. DOS/OS2/WIN32/UNIX: ex2in() strips off "//host/share/" from UNC names (SPC)
+-------------------------- June 23rd 1998 version 2.3d -------------------
+ 1. Fixed Win32's stat() bandaid handling of time stamps (SPC)
+ 2. General fix of file selections for DELETE and FRESHEN action (SPC)
+ 3. CMS_MVS: Use ASCII coding for TIME extra field ID (SPC)
+ 4. EBCDIC: Repaired bogus CMS_MVS fix in zipup.c; check the internal
+ name for trailing (ASCII) '/' to detect directory entries (SPC)
+ 5. Use explicit ASCII coding when comparing or setting chars in iname (SPC)
+ 6. Fixed win32/makefile.bor, win32/makefile.dj (support NTSD),
+ win32/makefile.emx (SPC)
+ 7. Replaced win32/makefile.cyg by win32/makefile.gcc, containing new
+ support for mingw32 GCC environment (SPC)
+ 8. Use izshr032 (SPC)
+ 9. Modified zipup.c to hold (un)compressed lengths in "ulg" variables, in
+ an attempt to support handling of huge (>2GByte) files. (SPC)
+10. Removed some duplicate #defines from api.h, they are now in crypt.h (SPC)
+11. Reenabled "extra data size" info messages in noisy mode for all systems
+ except RISCOS and CMS_MVS (SPC)
+12. For EMX 0.9c, the runtime lib contains a working mktime(), use it (SPC)
+13. Miscellanous cosmetic changes (SPC)
+14. Move win32/makefile.emx to msdos (E-Yen Tan)
+15. make api.h work with zcrypt2.8 (Mike)
+16. define ydays differently in api.h to avoid linking problems (Mike)
+17. New windll.txt (Mike)
+18. win32 lcc patches (E-Yen Tan)
+19. win32 lcc makefile (E-Yen Tan)
+20. Multiple inclusion bug: no malloc.h when using lcc-win32 (E-Yen Tan)
+21. New VB support files for windll (Mike Le Voi, Raymond King)
+22. MacOS port by Dirk Haase
+-------------------------- August 1st 1998 version 2.3e -------------------
+ 1. Generalized check for validy of TZ timezone setup info, similar to
+ UnZip; use it on AMIGA and MSDOS, as before. (SPC)
+ 2. Apply TZ validy check on OS/2 and enable creation of UT e.f. (SPC)
+ 3. BEOS: New Makefile, updates for README and Contents (Chris Herborth)
+ 4. beos/beos.c: declare some private functions as "local" (SPC)
+ 5. Include memcompress() code only for ports that make use of it, controlled
+ by preprocessor symbol ZP_NEED_MEMCOMPR (SPC)
+ 6. cmsmvs/README.CMS fix: Zip archive entries to be extracted into var-length
+ records CMS files should >>NOT<< contain binary data ... (SPC)
+ 7. crc32.c, crctab.c: the crc polynom table is ZCONST (SPC)
+ 8. trees.c: fixed a bug in the deflate algorithm that limited the compressed
+ size of an archive member to 512 MByte (SPC)
+ 9. deflate.c: Integrated the changes found in zlib that are neccessary to make
+ the deflate algorithm deterministic; modified msdos/match.asm to take
+ care of the "nice_match" global no longer being constant. (SPC)
+10. deflate.c, trees.c, zipup.c: Reorganized and simplified deflate's
+ compressed output buffer handling. I/O and compression code are now
+ separated more cleanly. (SPC)
+11. Killed bits.c by moving its contents into trees.c resp. zipup.c;
+ synchronized all Makefiles and Make procedures with this change. (SPC)
+12. Integrated support for optionally replacement of deflate and crc32 by
+ public domain zlib code. (SPC)
+13. Synchronize the different variants (UNIX/GNU C, OS/2, WIN32) of i386
+ assembler replacement for deflate's longest_match() (SPC)
+14. Moved the EMX+rsxnt Makefile.emx from msdos/ back into win32/ (SPC)
+15. Restored a separate Makefile.emx for DOS; on DOS, some make programs may
+ have difficulties with recursive invokation (SPC)
+16. Fixed the "include header mess" of the new MACOS port and removed the
+ "work-around hacks" caused by these bad MACOS .h-file includes (SPC)
+17. Integrated Dirk Haase's beta4 (27-Jun-98) release of MacZIP (Dirk Haase)
+18. Added support for MS Quick C in the MSDOS version_local() report (SPC)
+19. Added WIN32 rsxnt targets linking against the emx crtl DLL to Makefile.emx
+ in os2/ and win32/ (SPC)
+20. Fixed typo in os2/os2.c wild() function. (Kai Uwe Rommel)
+21. Removed ChangeNameForFAT() from os2/os2.c in2ex() to fix problem with
+ long filename support. (Kai Uwe Rommel)
+22. os2/os2zip.[ch]: correct type of DOS-style timestamp data is "ulg" (SPC)
+23. vms/cmdline.c: Removed wrong ';' behind if condition (Johnny Lee)
+24. VMS: Preliminary preparations in C code for supporting GNU C on OpenVMS
+ Alpha (Onno van der Linden, Christian Spieler)
+25. VMS: Fixed check against adding zipfile to itself in fileio.c (SPC)
+26. WIN32: Added lcc-Win32 variants of i386 assembler code for crc32() and
+ longest_match(). (SPC)
+27. WIN32: Removed bogus type-cast in assignment to statb st_mode member (SPC)
+28. zip.c: Fixed MACOS-related typo that broke "-@" command option (SPC)
+29. zipup.c: Fixed messed-up expression for assignment to z->ver (SPC)
+30. MACOS extra fields: check realloc return values (Onno, Johnny Lee)
+31. Fix the PUTBYTE macro in trees.c: >= instead of < (Onno)
+-------------------------- September 6th 1998 version 2.3f -------------------
+ 1. Add zp_tz_is_valid to globals.c (Onno, Frank Donahoe)
+ 2. Updated tandem files from Dave Smith
+ 3. Windll: allow comments to zip archive with VB (Mike)
+ 4. Windll: add support for -b and update the documentation (Mike)
+ 5. win32: use wbS for FOPW to handle large zip files better (Steve Miller)
+ 6. MVS fix: use fseek();clearerr() instead of rewind() (Onno, Lee Burton)
+ 7. Updated VB examples for windll (Mike)
+ 8. Tandem: use UTC timestamps and GID/UID in extra field (Dave Smith)
+ 9. Tandem: handle -o option (Dave Smith)
+10. default for ZCONST is const in tailor.h, override in osdep.h (Onno)
+11. additional Macintosh options in zip.c (Dirk Haase)
+12. additional Macintosh options in zip.1 and MANUAL (Onno, Dirk Haase)
+13. Integrate Beta 5 of the Macintosh Port (Dirk Haase)
+-------------------------- October 27th 1998 version 2.3g -------------------
+ 1. zip_tz_is_valid should be zp_tz_is_valid (Kai Uwe)
+ 2. MVS native (not OE) beta fixes (Keith Owens)
+ 3. LynxOS support from Giuseppe Guerrini
+ 4. MVS already has stat() and fstat() so use 'em (Keith Owens)
+ 5. MVS fix in readzipfile() for new, unopened dataset without EOF marker
+ (Keith Owens)
+ 6. Remove 16-bit stuff from windll/windll.rc (Mike)
+ 7. Windll: Use hCurrentInst not hInst (Mike)
+ 8. In util.c compare strchr() return value with NULL (Onno, Frank Donahoe)
+ 9. unix/unix.c: initialize variable t in ex2in() (Onno, Frank Danahoe)
+10. Remove windll/borland subdirectory (Mike)
+11. Really fix extra field realloc() for BeOS and MacOS (Christian)
+12. Fix the dj2 LFN related access violation bug (Christian, Joe Forster)
+13. proginfo/3rdparty.bug: Added more info about other Zip clone's bugs.
+14. The global copyright definitions in revision.h now depend on DEFCPYRT
+ (Christian).
+15. tandem/macros: removed obsolete object file references (Christian)
+16. fix memory leak with the "filter" patterns (Christian, Leah Kramer)
+17. zip.c: completed the support for MacOS specific -N (Christian)
+18. reorganized the Mac specific help screen code (Christian)
+19. zipup.c: corrected the USE_ZLIB code to emit "stored" entries under
+ the same conditions as the "native deflate" code (Christian)
+20. A couple of vars that will never be negative should be unsigned (Christian)
+-------------------------- November 18th 1998 version 2.3h -------------------
+ 1. DJGPP: When compressing from stdin don't set binary mode if stdin is
+ a terminal (E-Yen Tan)
+ 2. Fix signed/unsigned comparisons in fileio.c, util.c and zipcloak.c
+ (Frank Donahoe)
+ 3. Move macgetch() prototype from macos/source/macos.c to macos/osdep.h
+ (Christian)
+ 4. _doserrno should have type int, not unsigned int (Christian)
+ 5. In zipfile.c init a file pointer with NULL to fix gcc warning (Christian)
+ 6. Upgrade to MacOS beta 7 (Dirk Haase)
+ 7. Move the #pragma statements from generic sources to cmsmvs.h (Christian)
+ 8. Support for QNX/Neutrino 2.0 (Chris)
+ 9. Default to -r in help screen add -R at the bottom (Chris)
+10. Clean up Makefile for BeOS R4 on x86 (Chris)
+11. Beos: If not storing symlinks store attributes of symlink target (Chris)
+12. Use izshr037 (Christian)
+13. Remove ZIPERR() macro from in {msdos,win32}/osdep.h (Christian)
+14. win32/win32.c: Fix 1-day offset in non-64bit FileTime2utime() (Christian)
+15. win32: enable 64-bit FileTime2utime() for MS VC++ >= 5.0 (Christian)
+16. cygwin32 only has _P_WAIT (Thomas Klausner)
+17. msname() should *really* ignore illegal characters (Thomas Klausner)
+18. Fix a missing ')' in Opendir() from win32zip.c (Thomas Klausner)
+-------------------------- December 5th 1998 version 2.3i -------------------
+ 1. Remove the #pragma statements that were forgotten the first time (Ian)
+ 2. Remove obsolete macos/source/CharMap.h (Steve Salisbury)
+ 3. isatty(fileno(zstdin)) in zipup.c should be isatty(zstdin)
+ (Onno, E-Yen Tan)
+ 4. several "shut up warnings from compiler" fixes (Christian)
+ 5. several cosmetic source changes (Christian)
+ 6. win32: make NTSD handling to be robust against alignment and structure
+ padding problems (Christian)
+ 7. Apply don't set binary mode when stdin is a terminal in zipup.c for
+ MSDOS and human68k (Christian)
+ 8. Upgrade to MacOS beta 8 (Dirk Haase)
+ 9. Add callback for WINDLL to handle user termination (Mike)
+10. Fix typo in acornzip.c (Darren Salt)
+11. acorn/sendbits.s: pass correct parameters to flush_outbuf() (Darren Salt)
+12. Fixes for IBM C/C++ 3.6 where time_t is a double (Kai Uwe)
+13. Fixes for IBM Visual Age C++ for win32 (Douglas Hendrix)
+14. man/zip.1: some version numbers in the text were still "2.2" (Christian)
+15. win32/makefile.emx: added a compilation variant that generates
+ standalone executables (Christian)
+16. change __CYGWIN32__ into __CYGWIN__ and add compatiblity definition for
+ B19 and older (Cosmin Truta)
+17. create uniform win32 getch() replacement (Christian)
+18. put back in define of USE_EF_UT_TIME in tandem.h (Dave Smith)
+19. put back in define of USE_CASE_MAP in tandem.h (Dave Smith)
+20. updates to make/macros to allow the object to be licensed (Dave Smith)
+21. updates to macros/doit to remove mktime.c (Dave Smith)
+22. updates to tandem.c for in2ex/mapname/chmod amendments to match Unzip
+ (Dave Smith)
+23. Use izshr039.zip (Christian)
+24. Init filenotes to 0 for the amiga too (Onno)
+25. get_filters(): remove one flag=0 statement to make -R work again (Onno)
+-------------------------- December 17th 1998 version 2.3j ------------------
+ 1. FOPWT defines opening a temp file for writing (Ian)
+ 2. Remove handling of bits.c from a couple of tandem files (Christian)
+ 3. A couple of "shut up warnings from compiler" fixes (Christian)
+ 4. win32/osdep.h: removed duplicate "IZ_PACKED" definition (Christian)
+ 5. win32/zipup.h: remove invalid "elseif" preprocessor token (Christian)
+ 6. sync MacOS help screen with other ports (Christian)
+ 7. get_filters(): set flag to 0 when -R isn't used (Christian)
+ 8. "local extra != central extra" now has "info" status (Christian)
+ 9. use windll directory as "home" directory for builds (Mike)
+10. CMS/MVS: define FOPWT (Ian)
+11. Upgrade to MacOS beta 9 (Dirk Haase)
+-------------------------- January 17th 1999 version 2.3k ------------------
+ 1. Change FOPW into FOPW_TMP (Christian)
+ 2. win32: #include uses paths relative to the parent directory (Christian)
+ 3. Use forward slashes as path separator in #include statements (Christian)
+ 4. windll: fix descriptions of f{In,Ex}cludeDate (Christian)
+ 5. win32/makefile.lcc: add some -I<path> options to find files in the
+ right places (Christian)
+ 6. Supply default empty IZ_PACKED define (Christian)
+ 7. windll: Fix some typos, descriptions (Christian)
+ 8. windll project files: use relative paths, no specific root directory
+ (Christian)
+ 9. windll project files: remove link references to import libraries that
+ are not used by the zip library (Christian)
+10. windll: fix potential infinite loop in a VB sample (Mike)
+11. windll/windll.txt: remove "may not work with VB" statement (Mike)
+12. Multibyte character set support from Yoshioka Tsuneo
+13. Theos port from Jean-Michel Dubois
+14. Tandem: added simple handling of Enscribe files by converting them into
+ text type files (Dave Smith)
+15. Tandem Extra Field ("TA") containing Tandem File Attributes (Dave Smith)
+16. Tandem history file showing background info to (UN)ZIP ports (Dave Smith)
+17. create ZIP file on tandem with special file code (1001) (Dave Smith)
+18. made tandem.c & tandem.h code completely the same as UNZIP (Dave Smith)
+19. unix/configure: move +Onolimit and -Olimit into the machine specific
+ section (Onno, John Wiersba)
+-------------------------- February 21st 1999 version 2.3l ------------------
+ 1. Fix qdos Makefile (Jonathan Hudson)
+ 2. fgets instead of gets in zipnote to fix linker warnings (Jonathan Hudson)
+ 3. Theos: remove _setargv.c and a reference in zip.c (Jean-Michel Dubois)
+ 4. Theos README (Jean-Michel Dubois)
+ 5. interchanged the fRecurse flag values for "-R" and "-r" (Christian)
+ 6. add "z" pr prefix to MBCS functions to avoid name clashes (Christian)
+ 7. Whenever the position of the increment operator does not matter, the
+ INCSTR variant is used, which has been mapped to the {PRE|POS}INCSTR
+ variant that is more efficient. (Christian)
+ 8. fixed the "-R" handling in fileio.c, filter() function (Christian)
+ 9. simplified some THEOS specific code additions (Christian)
+10. changed the line break of the compiler version message in version_local()
+ for MSDOS and Win32 to take into account some verbose compilers (Christian)
+11. removed the THEOS changes from ttyio.c. Instead, a THEOS specific
+ setup was added to ttyio.h (Christian)
+12. sync vms/link_zip.com with the corresponding make_zip.com (Christian)
+13. added compatibility settings for support of MBCS on Win32 with all tested
+ compilers to win32/osdep.h
+14. added type-casts to isalpha() macro calls (Christian)
+15. fixed win32's wild_match which was clobbered by the MBCS addition
+ (Christian)
+16. finished up the "potential infinite loop" problems in the VB sample
+ that Mike started to repair (Christian)
+17. in ziperr.h, AZTEK C might require the false comma that was removed
+ to satisfy THEOS C (Christian)
+18. removed the bogus THEOS specific isdir check in zipup.c (Christian)
+19. modified the code for line ending translation to be independent
+ of the local system's convention for '\n' and '\r'; this allowed
+ the removal of the THEOS specialities (Christian)
+20. Tandem: -B option to zip Enscribe files with no record delimiters
+ (Dave Smith)
+21. Tandem: attempt to catch Large Transfer mode failure (Dave Smith)
+22. Theos: Fixed keyboard entry functions. (Jean-Michel Dubois)
+23. Theos: workaround for the argument wild card expansion that is bugged
+ in the standard library. Managed by MAINWA_BUG flag. (Jean-Michel Dubois)
+24. Theos: support for filenames and notes with accented characters.
+ (Jean-Michel Dubois)
+25. Upgrade to MacOS final (Dirk Haase)
+-------------------------- March 31st 1999 version 2.3m -------------------
+ 1. Theos: for relative paths to root directory cause open, fopen and stat
+ failure, workaround this. (Jean-Michel Dubois)
+ 2. Theos: when no path is indicated in a file or directory name and the
+ file or directory doesn't exist in the current directory it looks for
+ the file or directory in the root directory, workaround this.
+ (Jean-Michel Dubois)
+ 3. Corrected some typos and spelling error in macos/HISTORY.TXT; skipped
+ off invisible trailing whitespace (Christian)
+ 4. proginfo/extra.fld: added documentation for Tandem and Theos extra
+ field layout (Christian with Dave D Smith resp. Jean-Michel Dubois)
+ 5. qdos/Makefile.qdos: The build of ZipCloak requires inclusion of
+ the crctab object module; qfileio_.o compilation requires the -DUTIL
+ flag (Christian)
+ 6. win32: fix incorrect MB_CUR_MAX macro for mingw32 and lcc (Christian)
+ 7. theos/_fprintf.c, theos/_rename.c, theos/osdep.h: Some function
+ parameters require the "const" attribute to achieve compatibility
+ with ANSI C requirements (Christian)
+ 8. theos/theos.c: map Theos' (No)Hidden file attribute to MSDOS Hidden
+ bit in the MSDOS part of zipentry header's external attribute field;
+ 9. theos/stat.h: prevent multiple inclusions
+10. Theos: Fixed wild card management for options other than adding
+ (Jean-Michel Dubois)
+11. Theos: Removed modifications of const strings (Jean-Michel Dubois)
+12. Split tandem.c up into separate zip/unzip parts (Dave Smith, Christian)
+13. Move inclusion of OS specific zipup.h files to tailor.h (Onno)
+-------------------------- August 14th 1999 version 2.3n -------------------
+ 1. Move inclusion of OS specific zipup.h files back to zipup.c (Onno)
+ 2. Remove getline() from zipnote.c and use gets() again (Onno)
+ 3. BeOS PowerPC R4.1 support (Chris)
+ 4. New DOIT and MACROS files for the tandem port (Dave Smith)
+ 5. Don't switch the console to binary mode (Michel de Ruiter)
+ 6. In some circumstances undosm could be freed twice (Mike)
+ 7. Also define const in tailor.h for ultrix (Onno, Foppa Uberti Massimo)
+ 8. Tandem: Change zopen in TANZIPC to allow opening of files with missing
+ alt keys (err 4) (Dave Smith)
+ 9. Tandem: Assume not DST if can't resolve time (no DST table available)
+ (Dave Smith)
+10. WIN32: skip trailing dots and spaces in getnam (Onno, Dan Kegel)
+11. Use ZE_NONE when nothing to freshen or update (Onno, Yuri Sidorenko)
+12. Remove tabs from files that don't need them (Onno)
+13. Remove tabs and spaces from the end of a text line (Onno)
+14. Upgrade macos to 1.04b2 (Dirk)
+15. Add -Q documentation to manual page (Jonathan Hudson)
+16. Copy hiperspace files instead of renaming them (Keith Owens)
+17. Disallow some more characters to appear in DOS filenames when using -k
+ (Onno, Thomas Klausner)
+18. Document missing options and environment variables in the manual (Onno)
+19. New acorn/GMakefile to compile with gcc on RISCOS (Darren Salt)
+20. ISO 8601 date format support for -t and -tt (Rodney Brown)
+-------------------------- September 21st 1999 version 2.3o -------------------
+ 1. Sync zip.h license with LICENSE (Onno)
+ 2. Add copyright notice to README, os2zip.c and os2.zip.h (Onno, Greg)
+ 3. Fix the ASM variable in acorn/GMakefile (Darren Salt)
+ 4. Add another requirement to acorn/ReadMe.GMakefile (Darren Salt)
+ 5. Fix unbalanced parenthesis in vms_get_attributes declaration in zip.h
+ and move it to vms/zipup.h (Onno, Mike Freeman)
+ 6. Make a couple of os2 files public domain (Kai Uwe)
+ 7. Change and rename disclaimer array in revision.h (Onno)
+ 8. Change copyright array in revision.h (Onno)
+ 9. macstuff.c copyright is the same as macstuff.h (Christian)
+10. WHATSNEW: add ISO 8601 dates supported (Christian)
+11. fileio.c - msname(): strip off leading dots, these are illegal for
+ MSDOS compatible names (Christian)
+13. fileio.c - replace(): deactivate "dead" code for CMS_MVS (Christian)
+14. man/zip.1: "-$" option is also used for WIN32 ports
+15. msdos/msdos.c - version_local(): break the version line for
+ GNU compilers too (Christian)
+16. tailor.h: added typecasts to MBCS macros, to suppress "type mismatch"
+ warnings (Christian)
+17. util.c, zip.h, zipfile.c: ZCONSTify several pointers (Christian)
+18. util.c - recmatch(), zip.c - version_info(): add compile time option
+ WILD_STOP_AT_DIR (Christian, Darren Salt)
+19. util.c - envargs(): MBCS related fixes (Christian)
+20. win32/lm32_lcc.asm: add TAB characters that are required by the lcc
+ assembler source parser (Christian)
+21. zip.c: fix the "is a console" check (Christian)
+22. zipnote.c: use getline() (Christian)
+23. zipup.c: use zclose() in case of I/O errors (Christian)
+24. zipup.c: use ZE_WRITE when a write error occurs (Christian)
+25. win32/win32.c: HAVE_INT64 is used by mingw32 (Cosmin Truta)
+26. update shared sources to match izshr041 (Christian)
+-------------------------- November 29th 1999 version 2.3 ------------------
+ 1. Missing parenthesis in win32/win32.c (Steve Salisbury)
+ 2. Add Cosmin Truta to proginfo/infozip.who (Onno)
+ 3. Remove one parenthesis pair too many from vms_get_attributes() declaration
+ in vms/zipup.h (Mike Freeman)
+ 4. qdos .s are expected to start with a #, work around it (Jonathan Hudson)
+ 5. tandem: -B0 should be deflating not storing (Dave Smith)
+ 6. human68k updates from Shimazaki Ryo
+ 7. beos Makefile cleanup (Chris)
+ 8. workaround for fseek to negativate offset behaviour of the RISC OS
+ SharedCLibrary (Darren Salt)
+ 9. set file type for RISC OS in zipcloak.c (Darren Salt)
+10. change tandem zgetch() to allow crypt version to work (Dave Smith)
+11. fix a comment typo in acorn/riscos.c (Christian)
+12. fileio.c: two type-cast to shut up noisy compilers (Christian)
+13. human68k: fix missing case_flag argmument (Christian)
+14. win32/win32.c: remove HAVE_INT64 completely (Christian)
+15. zip.c: raise "cannot zip to console" error when stdout IS a tty (Christian)
+16. zip.h: don't use dummy argument names in declarations (Christian)
+17. Add missing semicolon in fileio.c (Shimazaki Ryo)
+18. win32.c: IBMC compiler >= 3.50 have int64 (Kai Uwe)
+19. Handle initialization error return value from MVS stat() in procname()
+ (Keith Owens)
+20. Use RISC OS instead of RiscOS in the manual (Darren Salt)
+21. Use # instead of ? as single character wildcard on RISC OS (Darren Salt)
+22. New windll example.c (Mike)
+23. Correct storage of 8-bit char filenames with RSXNT (Burkhard Hirzinger)
+24. fix install in unix/Makefile (Santiago Vila, Onno)
+25. Fix zip -L output (Santiago Vila, Onno)
+26. Ignore unix special files (Jonathan O'Brien)
+27. Upgrade to izshr042 (Onno)
+28. Make copyright notice the same as in izshr042 (Onno)
+29. Make copyright notice in zip.h the same as LICENSE (Christian)
+30. Set tempzf to NULL _after_ it has been closed (Chris Kacher)
+31. Change email address for Jonathan Hudson (Jonathan Hudson)
+32. Remove win32/winzip.c.orig (Steve Salisbury)
+33. Use 'Steve Salisbury' throughout the documentation (Steve Salisbury)
+34. Change email address for Steve Salisbury (Steve Salisbury)
+35. Change email address for Chris Herborth (Chris Herborth)
+36. Use zip23 in INSTALL (Roger Cornelius)
+37. Use zcrypt28 in INSTALL (Onno)
+38. New acorn/srcrename (Darren Salt)
+39. amiga/makefile.azt: make clean should remove some more items (Paul)
+40. Change email address for Cosmin Truta (Cosmin Truta)
+-------------------------- February 11th 2001 version 2.4a ------------------
+ 1. Identify newer Borland compilers (Brad Clarke)
+ 2. Detect Turbo C 2.01 which doesn't have mktime (Brian Lindholm)
+ 3. Fix the use of -@ together with -i -x (Christian)
+ 4. Update msdos/README.DOS to match reality (Christian)
+ 5. win32: use assembler crc32 code (Christian)
+ 6. windll: _CRTIMP is needed in several function declarations (Christian)
+ 7. back to zip 2.2 memcompress() behaviour (Kelly Anderson)
+ 8. new amiga time code based on nih public domain code (Paul Kienitz)
+ 9. Detect some more Borland C++ builder versions (Brad Clarke)
+10. Fix OS/2's extended file attributes compression code (Christian, Kai Uwe)
+11. Correct translation of EBCDIC passwords to ASCII (Christian)
+12. Attempt at integrating novell patches from Roger Foss (Onno)
+13. Use izshr043 (Christian)
+-------------------------- July 3rd 2001 version 2.4b ------------------
+ 1. Fix OS/2's ACL compression code (Christian, Kai Uwe)
+ 2. Rename netware subdir to novell (Christian)
+ 3. Remove -dNETWARE -dDOS from novell Makefile (Christian)
+ 4. Remove defined(NETWARE) from the sources (Christian)
+ 5. printf is a macro in glibc 2.2, fix version_local function
+ (Christian, Matthew Wilcox)
+-------------------------- January 13th 2002 version 2.4c ------------------
+ 1. Use klist_items when initilizating koff[] in tandem.c (Dave Smith)
+ 2. Only call NLMsignals() in zip.c when NLM is defined (Mike, Onno)
+ 3. include riscos.h instead of acorn/riscos.h in acorn/osdep.h (Andy Wingate)
+ 4. Use izshr044 (Christian)
+-------------------------- January 13th 2002 version 2.4d ------------------
+ 1. Don't use mmap for stored entries (Christian)
+ 2. BIG_MEM and MMAP cannot be defined at the same time (Christian)
+ 3. Allow redirection of version screen to file (Christian)
+ 4. Fix for OS/2 output redirection bug (Christian, Kai Uwe)
+ 5. Acorn script for creating self extracting zips (Darren Salt)
+ 6. Update amiga makefiles to support revised timezone routines (Christian)
+ 7. Correct memcompress calculation for allocation size (Christian)
+ 8. Fix FORCE_METHOD debug option for level 1 and 2 (Christian)
+ 9. Whitespace cleanup in man/zip.1 (Christian)
+10. Define IZ_IMP to specify compiler declaration prefixes (Christian)
+11. make win32 and msdos version_local() "stdio-macro-safe" (Christian)
+12. move tandem's zip specific zipopen to tanzip.c (Christian)
+13. first parm is void * in external scope of vms_get_attributes() (Christian)
+14. use right novell subdirectory in zipup.c (Christian)
+15. update copyright for files modified in 2002 (Onno)
+-------------------------- January 19th 2002 version 2.4e ------------------
+ 1. Add MacOS X to version_local() (Mark)
+ 2. unix/configure: Init LFLAGS1 to "", MacOS X doesn't like -s (Onno, Mark)
+ 3. rename errors array to ziperrors to avoid MacOS X library clash (Mark)
+ 4. Support for the upx executable packer in DOS makefiles (Christian)
+ 5. remove obsolete -m486 switch from dos djgpp makefile (Christian)
+ 6. When using DOS, force the use of msdos style external attributes when
+ updating zip entries created under another OS (Christian)
+ 7. os2/makefile.os2: fixed ASFLAGS for watcom16dos (Christian)
+ 8. Update copyright and ftp address in several files (Christian)
+ 9. The RISCOS port uses '.' as directory separator, not '/' (Christian)
+10. win32/makefile.bor: more options to compile the asm CRC code (Christian)
+11. win32: use registry to handle timezones with MS C rtl (Christian)
+12. acorn: use recommended practice for calling the linker (Andy Wingate)
+13. unix/configure: check if CPP works else use ${CC} -E (Onno, Mark)
+14. update versioninfolines in revision.h to match reality (Onno)
+-------------------------- February 10th 2002 version 2.4f ------------------
+ 1. vms: Zip -V is now able to handle file sizes up to 4Gb (Christian)
+ 2. vms: Include target environment detection for MMS/MMK (Christian)
+ 3. Change dummy message from zipcloak (Christian)
+ 4. acorn: add riscos specific -/ option (Darren)
+ 5. Update acorn's WILD_STOP_AT_DIR feature (Christian)
+ 6. acorn: Fix buffer allocation for -/ option (Christian, Darren)
+ 7. acorn: fix make clean (Andy Wingate)
+ 8. acorn: use tabs for GMakefile to make GNU make happy (Andy Wingate)
+ 9. tandem: use nskopen not zipopen (Dave Smith)
+10. tandem: allow passing of CRYPT define (Dave Smith)
+11. use izshr045 (Christian)
+-------------------------- April 1st 2002 version 2.4g ------------------
+ 1. acorn: fix assembler and compiler options in makefile (Darren)
+ 2. use izshr046 (Christian)
+ 3. MVS: define isatty to 1 to fix screen output (Christian)
+ 4. tandem: encryption really works now (Dave Smith)
+ 5. win32: detect Borland C++ builder 6 (Brad Clarke)
+-------------------------- April 30th 2003 version 2.4h ------------------
+ 1. tandem: fix temporary file contention (Dave Smith)
+ 2. cmsmvs: generate better filenames with -j (Owen Leibman)
+ 3. tandem: fix temporary file leftovers (Dave Smith)
+ 4. solaris: enable large file I/O to break 2G barrier (Rick Moakley, Onno)
+
+Note: Zip 2.4 was never released. That code was the start of the Zip 3.0
+effort below. Some changes and fixes also made it to the Zip 2.3x releases.
+
+---------------------- January 21st 2004 version 3.0a ----------------------
+Initial work on Zip 3.0 by Ed Gordon and Rainer Nausedat
+ 1. Changed some comments to update copyrights (Ed)
+ 2. Changed text in command line messages from zip 2.4 to zip 3.0 (Ed)
+ 3. Changes to many files for Zip64 wrapped in ifdef ZIP64_SUPPORT (Rainer)
+ 4. Attempt to fix buggy Win32 buffered 64-bit calls (Ed)
+ 5. Add functions to zipfile.c for Little-Endian memory writes (Rainer)
+ 6. Add functions to zipfile.c for writing Zip64 extra fields (Rainer)
+ 7. Major changes to putlocal, putcentral, and putend (Rainer)
+ 8. Fixing -F and -FF for Zip64 postponed (Ed and Rainer)
+ 9. Command line code replaced. Global table sets options, long options now
+ supported. Permutes so order of arguments can vary (Ed)
+10. Fix bug where not allowed to use -@ with stdout but was with stdin.
+ Now can read filenames from stdin using -@ and output to stdout and
+ no longer am allowed to use -@ if reading from stdin (Ed)
+11. Replace stat() with zstat(), fstat() with zfstat() and struct
+ stat with z_stat in Zip64 blocks. Put 64-bit file calls in ifdef
+ LARGE_FILE_SUPPORT blocks. Can implement Zip64 without > 4 GB
+ file support but for now need large files for Zip64 support (Ed)
+12. Move port-specific code to osdep.h and win32.c (port specific) and
+ tailor.h (generic) and remove temporary os_io.c. As OF() is
+ not defined until after osdep.h includes in tailor.h function
+ prototypes for zfseeko, zftello, and zstat after that in tailor.h (Ed)
+13. Settings of ZIP64_SUPPORT and LARGE_FILE_SUPPORT automatic based on
+ port and version of compiler. Defining NO_ZIP64_SUPPORT or
+ NO_LARGE_FILE_SUPPORT overrides this (Ed)
+14. Bugs compiling scanzipf_fix(...) in zipfile.c and the fix functions could
+ use rewrite (Rainer and Ed)
+15. Add prototype for zfopen for mapping to 64-bit fopen on ports using
+ inodes but not implemented (Ed)
+16. More work on extended local headers and encypted archives (Rainer)
+17. Fix DLL files so now compiles (Ed)
+18. File size in dll limited to 32-bit in structure. A new DLL api is needed
+ to return 64-bit file sizes. Current api fixed to return max 32-bit if
+ more than that (Ed)
+19. Add local header Zip64 support and local extra field. Fixed cast
+ to ulg missed previously that forced zstat to return value mod 4 GB in
+ zipup.c which kept local header code from seeing actual file size (Ed)
+20. Add new option --force-zip64 to force use of zip64 fields. Could
+ be temporary (Ed)
+21. Fix for VB added to api.c that just store the passed strings internally.
+ Should update api to optionally return file sizes as 64-bit in call back
+ and to accept RootDir and other strings in same call that zips (Ed)
+22. Readme updated to describe new features and mention updated mail group
+ web links (Ed)
+23. Minor bugs in output format found and fixed. Now can add
+ files > 4 GB to archive and unzip using major unzippers (Ed)
+24. If zip used as filter (zip - -) and sizes exceed limits of extended
+ local header (data descriptor) then set max 32-bit values there. Major
+ unzippers ignore and use central directory values which are correct. Can
+ create Zip64 data descriptor using --force-zip64 option but seems no need
+ for it (Ed)
+25. A few bugs in how headers are handled prevented zipping large numbers
+ of files. Fixed (Rainer)
+26. A bit of an attempt to fix -F and -FF. Seems to work but not that
+ robust. More work needed (Ed)
+27. After some cast and other fixes zip compiles on Linux Red Hat 9 using Unix
+ generic. Added automatic detection of fseeko64 and if detected
+ sets LARGE_FILE_SUPPORT and setting that sets ZIP64_SUPPORT. Works but
+ could not test large files on the small system (Ed)
+28. Tried to fix bug that prevents zipnotes from compiling when ZIP64_SUPPORT
+ is set. Still broke. This crashes the Unix Makefile but after
+ zip is compiled (Ed)
+---------------------- May 8th 2004 version 3.0b ----------------------
+ 1. Update license headers on more files (Ed)
+ 2. Change many ZIP64_SUPPORT ifdefs to LARGE_FILE_SUPPORT where appropriate.
+ Now can test ports using three stages, compile with NO_LARGE_FILE_SUPPORT
+ (which disables ZIP64_SUPPORT) to test base code, compile with
+ NO_ZIP64_SUPPORT to test the 64-bit file calls (assuming port sets
+ LARGE_FILE_SUPPORT) but otherwise use the base code, and without either
+ to test Zip64 if enabled on port (Ed)
+ 3. Fix zipnotes bug by moving a ZIP64_SUPPORT block in zipfile.c (Ed)
+ 4. Add Large File Summit (LFS) code to Unix port to enable 64-bit calls.
+ Update configure to include test for all needed 64-bit file calls before
+ enabling LARGE_FILE_SUPPORT for unix port (Ed)
+ 5. Merge encryption code from zcrypt29 (files from unzip) into zip and
+ enable by default (Ed)
+ 6. New man pages for zipnote, zipsplit, and zipcloak (Greg, Ed)
+ 7. Add encryption notice to crypt.c comments and to version information
+ in zip.c (Greg, Ed)
+ 8. Add Russian OEM EBCDIC support when OEM_RUSS defined in ebcdic.h but
+ Dmitri reports that 0x2F not '/' so make recommended change in cutpath
+ call in zipfile.c used by -D option (Dmitri - Nov 10 2003 email)
+ 9. ToDo30 file added to list what's left to do in this release (Ed)
+10. Change fopen to zfopen for large file code and map to fopen64 for
+ Unix (Ed)
+11. ftello64 seems broken in zipup.c on Linux (kernel 2.4), returning
+ negatives past the 2 GB barrier, though ftello64 works in a test program.
+ Likely error in defines. For now skip ftello64 check for Unix with
+ LARGE_FILE_SUPPORT.
+12. A few updates in Readme. Needs overhaul likely. Also verified mxserver
+ is gone and replaced with list addresses (Ed)
+13. First iterations at updating WinDLL for Zip64 (Mike)
+14. Decide to drop backward dll compatibility in favor of a cleaner
+ dll interface. Decide to add string interfaces for VB (Ed, Mike)
+15. Add string interfaces to dll interface to bypass array limitations
+ imposed by VB and add -x and -i to interface (Mike)
+16. Create new VB example using new Zip64 dll interface (Ed)
+17. Add O_LARGEFILE define for zopen in unix/zipup.h to enable reading
+ large files in unix (Ed)
+18. Combine ZpSetOptions and ZpArchive dll calls to allow removing all VB kluges
+ in api.c to work around VB garbage collecting passed strings (Mike)
+19. Change new VBz64 example to use updated interface. All works without
+ kluges (Ed)
+---------------------- August 15th 2004 version 3.0c ----------------------
+ 1. Add date formats in -t and -tt date errors (Ed)
+ 2. Add -so to display all available options (Ed)
+ 3. Many fixes from Dan Nelson to fix some large file support problems and
+ add large file support to a few ports. Main change is rather than use
+ explicit 64-bit calls like fopen64 now set 64-bit environment and use
+ standard calls. Also add a define for 64-bit printf format used to
+ print 64-bit stats (Dan, Ed)
+ 4. Changes to Unix config based on suggestions from Dan Nelson. Check
+ if off_t is at least 64 bit (Dan, Ed)
+ 5. Add -- to get_option. Any arguments after -- on command line now
+ read as paths and not options (Ed)
+ 6. Add extended help (Ed)
+ 7. Change add_filter flag parameter from char to int as some compilers have
+ problems with char arguments (Ed)
+ 8. Changed filter() to do R and i separately so i has precedence over R (Ed)
+ 9. Split variable t in zip.c into t (off_t) and tf (ulg) (Ed)
+10. Add quotes to zipname in check_zipfile for MSDOS to allow spaces in
+ archive path given to unzip to test ( , Ed)
+11. Move zip.h include before ctype.h include in trees.c and zipup.c as
+ when ctype.h is first and using 64-bit environment at least on unix port
+ found it defines off_t as 4 bytes in those files as off_t is defined as
+ 8 bytes in other files and this changes the size of the zlist structure
+ which is not good (Ed)
+12. Add default 64-bit file environment to tailor.h if LARGE_FILE_SUPPORT
+ is set but no port 64-bit file defines are set up earlier in the file.
+ Should allow other ports to set LARGE_FILE_SUPPORT on the compiler
+ command line to test if the standard defines work (Ed)
+13. Adjust binary detection in trees.c by changing 20% binary (4 out of 5
+ ascii) that used >> 2 to 2% (64 out of 65) using >> 6 instead.
+ trees.c (Ed)
+---------------------- November 12th 2004 version 3.0d ----------------------
+ 1. Add global variable for EncryptionPassword in VBz64 example and
+ some other password callback cleanup (Ed)
+ 2. Add -W option to turn on WILD_STOP_AT_DIR where wildcards will not
+ include directory boundaries in matches (Ed)
+ 3. Add -nw option "no wild" to completely disable wildcards in MATCH
+ function. Allows a list of files to be read in without worrying about
+ wildcards or escapes (Ed)
+ 4. Add -s option split-size but not implemented (Ed)
+ 5. Add -sp option split-pause but not implemented (Ed)
+ 6. Add changes for WiZ including moving Win32 64-bit wrappers into
+ win32i64.c to avoid naming conflict between libraries in WiZ (Mike, Ed)
+ 7. Some large file fixes in crypt.c (Ed)
+ 8. Add new error code ZE_UNSUP for unsupported compiler options. Add
+ check of size of zoff_t in zip.c when LARGE_FILE_SUPPORT enabled (Ed)
+ 9. Changed ZE_UNSUP to ZE_COMPERR to avoid conflict with unzip (Ed)
+10. On VMS (sufficiently recent, non-VAX), DECC$ARGV_PARSE_STYLE is set
+ automatically to preserve case of the command line if the user has
+ SET PROCESS /PARSE = EXTEND. This obviates quoting upper-case
+ options, like -V, when enabled. VMS.C (Steven Schweda (SMS))
+11. On VMS, building with macro VMS_PRESERVE_CASE defined preserves case
+ of names in archive, instead of forcing lower-case (the former and
+ current default behavior). VMSZIP.C (SMS)
+12. On VMS, in some of the simplest cases, ODS5 extended file name
+ escape characters ("^") are removed from names in archive.
+ VMSZIP.C (SMS)
+13. On VMS, fixed a problem in some cases with mixed-case directory
+ names, where too much of the directory hierarchy was included in the
+ path names in the archive. VMSZIP.C (SMS)
+14. On VMS, minor changes for large file support (long -> zoff_t).
+ VMSZIP.C (SMS)
+15. On VMS, changed some structure declarations to typedefs, and
+ rearranged to simplify #if's and reduce potential name conflicts.
+ VMS.H, VMS_IM.C, VMS_PK.C (SMS)
+16. On VMS, reformed -V (/VMS) processing. Added -VV (/VMS=ALL).
+ Removed some sign bits to accomodate files bigger than 2GB.
+ CMDLINE.C, VMS_IM.C, VMS_PK.C, ZIP.C, ZIP_CLI.CLD, ZIP_CLI.HELP,
+ ZIPUP.H (SMS)
+17. Update command line options to support -VV as distinct option (Ed)
+18. More VMS changes (SMS)
+19. Add zoff_t format function (SMS)
+20. On VMS, when -b was not used, temporary archive files were always
+ created in the current default directory, rather than in the archive
+ file destination directory. VMS now uses its own tempname()
+ function. FILEIO.C, VMS.C (SMS)
+21. Remove using FNMAX for path size in a few places including filetime.c
+ to avoid exceeding limit (based on fixes from Greg and others) (Ed)
+22. Add port atheos (Ruslan Nickolaev, Ed)
+23. Bug fix adds different extra fields for local and central in VMS (SMS)
+24. Now short options also take optional values as next argument (Ed)
+25. Change -dd to control -v dots (SMS, Ed)
+26. On VMS, a new open callback function senses (where supported) the
+ process RMS_DEFAULT values for file extend quantity (deq),
+ multi-block count (mbc), and multi-buffer count (mbf), and sets the
+ FAB/RAB parameters accordingly. The default deq is now much larger
+ than before (16384, was none), and the default mbc is now 127
+ (up from 64), speeding creation of a large archive file. Explicitly
+ set RMS_DEFAULT values override built-in defaults. OSDEP.H, VMS.C
+ (SMS)
+27. VMS CLI definitions and CLI help have been updated, and may be
+ approximately correct. CMDLINE.C, ZIP_CLI.CLD, ZIP_CLI.HELP (SMS)
+28. The man file zip.1 updated and Makefile updated to generate manual
+ pages for zipcloak.1, zipnote.1, and zipsplit.1 (Ed)
+---------------------- July 23rd 2005 version 3.0e ----------------------
+ 1. Debian patch 004 - apply 2.4i configure changes from Onno to remove
+ need for -fno-builtin in unix/configure (Onno, Ed)
+ 2. Debian patch 005 for bug 279867 - fix bug that could crash on large paths
+ and create security problem. Apply patch changes from Greg (Greg, Ed)
+ 3. SourceForge patch 1074363 - add win32i64.c to win32/makefile.w32 (Ed)
+ 4. Add check when not ZIP64_SUPPORT in scanzipf_reg() in zipfile.c if
+ Zip64 archive being read (Ed)
+ 5. Renamed fzofft() used to format zoff_t values to zip_fzofft() to remove
+ conflict when combined with UnZip in WiZ (Mike)
+ 6. Add check in scanzipf_reg() in zipfile.c if Zip64 archive being read (Ed)
+ 7. Fixes for amiga/makefile.azt to define directory for object files (Paul)
+ 8. Define prototypes for local functions optionerr, get_shortopt and
+ get_longopt in fileio.c. Define err argument of optionerr as ZCONST (Paul)
+ 9. Add help_extended and DisplayRunningStats prototypes, fix other prototypes
+ in zip.c (Paul)
+10. Split int kk off of k for argument types (Paul)
+11. Aztec #endif quirk fix in zip.c for Amiga (Paul)
+12. Add detection of binary in first buffer read from file in zipup.c to avoid
+ a -l or -ll translation on binary file. Not perfect but at least should
+ catch some binary files (Ed)
+13. Remove check for >= 128 from binary check in zipup.c as <= 6 enough for
+ signed char (SMS, Ed)
+14. SF Bug 1074368 - check for empty zip file in readzipfile() in zipfile.c
+ (Christian d'Heureuse, Ed)
+15. Add error exit to prevent archive corruption when updating a large-file
+ archive with a small-file program. Add ZE_ZIP64 error.
+ ziperr.h, zipfile.c (SMS)
+16. Change percent() in zipup.c to do rounding better, handle cases near limits
+ while rounding, and allow negative percent returns (SMS, Ed)
+17. Add function ffile_size() in zipfile.c but in #if 0 block until determine
+ if works on all ports under all conditions. Currently only used for size
+ check for Zip64 archive detection if compiled without ZIP64_SUPPORT and
+ this check may already be handled in scanzipf_reg() and should be added to
+ scanzipf_fix() when that is updated (SMS, Ed)
+18. Change >>1 to /2 in zipsplit.c to allow for negative percent returns (SMS)
+19. Add type uzoff_t for unsigned zoff_t things. Should clean up some casting
+ (Ed)
+20. Based on discussions with other development groups, when data descriptors
+ (extended local headers) are used, force to Zip64. This is compatible
+ with other unzips and does not require a change of the AppNote, but the
+ resulting archive requires Zip64 to read. Using standard data descriptors
+ would mean that the zip operation would fail if a Zip64 entry was
+ encountered. See zipfile.c (Ed)
+21. Add define SPLIT_SUPPORT to enable splits. The command line options are
+ done and the globals are set up but nothing more. globals.c, zip.h, and
+ zip.c mainly (Ed)
+22. Create spanning signature at beginning of archive when splitting enabled.
+ If reading a split archive skip the spanning signature unless creating a
+ split archive. zip.c, globals.c (Ed)
+23. Start implementing split archives. Define two methods. split_method = 1
+ updates local headers and is the most compatible but requires updating
+ previous splits. split_method = 2 uses data descriptors and should work
+ for streams and removable media but may not be as compatible with other
+ zip applications. (In part based on previous discussions with Rainer.)
+ Updated global variables to include bytes written to just the current
+ entry in the current split. zipfile.c (Ed)
+24. Add note about output redirection to zip.1 (?, Ed)
+25. Remove num < 0 check as num now unsigned. util.c (SMS, Ed)
+26. Change lastchar to lastchr in fileio.c in places to avoid function by same
+ name (SMS, Ed)
+27. Moved #endif /* !WINDLL */ in zip.c (Mike)
+28. Account for vms directory version being ;1. vmszip.c (SMS)
+29. Fix Zip64 check in scanzipf_reg to use the buffer. zipfile.c (Ed)
+30. Default define size_t (for use by Steve's ffile_size() function). tailor.h (Ed)
+31. Enable Steve's ffile_size() function and enable large file check. It
+ currently does not allow file sizes over 2 GB but the code is not supporting
+ it anyway without large file support. Should remove that part of the check
+ when the casts are fixed. zipfile.c (Ed)
+32. Fixes for djgpp. Now compiles with djgpp 2 (Ed)
+33. Add new VC6 projects for win32 and windll (Cosmin)
+34. Convert some variables in zipsplit.c from ulg to zoff_t so compiles (Ed)
+35. Add wildcards to extended help. zip.c (Ed)
+36. For optional option value now '-' is same as missing value. fileio.c (Ed)
+37. Remove extra free() from -dd option switch. zip.c (Ed)
+38. Change write_unsigned_to_mem() to write_ulong_to_mem() and write_short_to_mem()
+ to write_ushort_to_mem(). zipfile.c (Ed)
+39. Create new append to mem functions. zipfile.c (Ed)
+40. Change zlist nam and ext from extent to ushort as that is what gets written.
+ zipfile.c (Ed)
+41. Change GetSD to use ush instead of size_t. win32/win32zip.c (Ed)
+42. Change PutLocal(), PutExtended(), PutCentral(), and PutEnd() to write to
+ memory and then write the block at once to the file. zipfile.c (Ed)
+43. Change zcomlen from extent to ush, other extent conversions. zipfile.c,
+ globals.c, zip.h (Ed)
+44. Add is_seekable() and global output_is_seekable. Do seekable check
+ when output file is opened. zipup.c, globals.c, zip.h, zip.c (Ed)
+45. Do not increment files_so_far and bytes_so_far if file could not be read.
+ zip.c (Ed)
+46. If force_zip64 set, only force compressed size in central directory to Zip64
+ instead of all entries (csize, usize, off, disk) in Zip64 extra field. This
+ fixes inconsistent handling of disk numbers. zipfile.c (Ed)
+47. Add end status if displaying running stats and not all files were read.
+ zip.c (Ed)
+48. Change force_zip64 to zip64_archive in putend(). zipfile.c (Ed)
+49. Enable the i686-optimized code by default. crc_i386.S,
+ win32/crc_i386.asm, win32/crc_i386.c (Cosmin)
+50. Document and implement a new text detection scheme provided by Cosmin in
+ set_file_type(). Should be able to handle UTF-8 and some other character sets.
+ proginfo/txtvsbin.txt, trees.c (Cosmin, Johnny, Christian)
+51. Update binary detection for -l and -ll to use Cosmin black list. zipup.c (Ed)
+52. Change ZE_BIG to include read and write. ziperr.h (Ed)
+53. If archive not seekable then use data descriptors. If ZIP64_SUPPORT always
+ create Zip64 data descriptors and add a Zip64 extra field to flag it is
+ a Zip64 data descriptor. This is klugy but should be compatible with other
+ unzips. See the note in zipfile.c for details. (Ed)
+54. Use ush for comment length in putend(). Instead of extent use ush for
+ zcount and fcount same as in zip file. zip.h (Ed)
+55. Update VB readme. windll/VB/readmeVB.txt (Ed)
+56. Change (INSTALL) to (INSTALL_PROGRAM). unix/Makefile (, Ed)
+57. During update the file and byte status counts were off. Fixed by not coun-
+ ting files copied from old to new as those are not in totals. zip.c (Ed)
+58. Change from -b to -bx for nroff of manuals to text files. unix/Makefile (Ed)
+59. Add cygwin to makefile. unix/Makefile (, Ed)
+60. Fix bug where files to delete not added to list. zip.c (Ed)
+61. Fix delete stats. zip.c (Ed)
+62. Increment version of crypt to 2.10. Update default behavior notes.
+ crypt.c, crypt.h (Paul, Christian)
+63. Format changes, add parentheses to zfseeko(), fix output bytes, add ifdef
+ blocks for ZIP10, fzofft formatting, casts. crypt.c (Christian)
+64. Cast block_start to unsigned. deflate.c (Christian)
+65. Let -R patterns match in subdirectories. Update filter() to use switch,
+ use global icount and Rcount, handle subdirectories, update icount and
+ RCount in filterlist_to_patterns(). fileio.c, zip.c, zip.h, globals.c
+ (Christian)
+66. Enclose option -! and use_privileges under NTSD_EAS guard. globals.c,
+ zip.c, zip.h (Cosmin)
+67. Updates to version, copyright, license. [I did not split the copyright
+ to 2 lines as it already takes up space on the help screen. Ed]
+ revision.h (Christian)
+68. Add ZCONST to some read-only string pointer arguments in function
+ declarations. zipcloak.c, zipnote.c, zipsplit.c, zip.c, zip.h (Christian)
+69. Fix byte counts on exit in zipcloak() and zipbare() to fix zipcloak bug
+ (Christian)
+70. Modified zipnote.c to use WRBUFSIZ to handle line widths of at least 2047
+ characters in write mode (Christian)
+71. Change simple() and greedy() from zoff_t to uzoff_t. zipsplit.c (Christian)
+72. Remove duplicate copyright notices. zipsplit.c (Christian)
+73. Remove export notice from help page. Move notice to bottom of license
+ page. zipcloak.c (Ed)
+74. File USexport.msg export history added. (Greg)
+75. Added support for VMS ODS5 extended file names. (Eight-bit only, no
+ Unicode.) VMS name character "/" is mapped to Zip name character
+ "?". New command-line options -C[2|5][-] (/PRESERVE_CASE[=opts])
+ control name case preservation and/or down-casing. globals.c,
+ zip.c, zip.h, vms/cmdline.c, vms/vms_im.c, vms/vms_pk.c, vms/vms.c,
+ vms/vmszip.c, vms/vms.h (SMS)
+76. New VMS option -ww (/DOT_VERSION) stores version numbers as ".nnn"
+ instead of ";nnn" [changed from -Y to -ww (Ed)]. zip.c (SMS)
+77. Changes to vms_open(). vms/vms_im.c, vms/vms_pk.c
+78. Changes to vms_read(). vms/vms_pk.c (SMS)
+79. Documentation updates. vms/vms_zip.rnh (SMS)
+80. Minor updates. vms/zip_cli.help, vms/cmdline.c, vms/vms_zip.rnh (Ed)
+81. Changes to vmsmunch(). vms/vmsmunch.c (SMS)
+82. Do some updating of VMS options. vms/zip_cli.cld (SMS)
+83. Moved the VMS-specific ziptyp() function from zipfile.c to vms/vms.c
+ to segregate better the RMS stuff. (SMS)
+84. Put 64-bit calls in ZIP64_SUPPORT ifdef blocks, change some long parameters
+ for append to memory block functions to ulg, remove redundant includes,
+ add OFT protos to some functions with parameter types that get promoted
+ like ush to avoid warnings in VMS. zipfile.c (SMS)
+85. Use zip_fzofft() to format number. zipsplit.c (SMS)
+86. Add file_id.diz from Zip 2.31 (?, Ed)
+87. Update install from Zip 2.31 (?, Ed)
+88. Update license from Zip 2.31. License (?, Ed)
+89. Update Readme.cr from Zip 2.31 (?, Ed)
+90. Add 64-bit assembler for Win32 from Zip 2.31. win32/makefile.a64,
+ win32/readme.a64, win32/gvmat64.asm (?, Ed)
+91. Update Readme (Ed)
+92. Update headers. crctab.c, crc32.c, deflate.c, ebcdic.h, fileio.h (Ed)
+93. Option for extra verbose VMS, change DIAG_FLAG from verbose to
+ (verbose >= 2). vms/vms.c (SMS)
+94. Update copyright header. qdos/qdos.c (Christian, Ed)
+95. Change exit(0) to exit(ZE_OK). qdos/qdos.c (Christian)
+96. Change ulg to unsigned long. tailor.h (, Christian)
+97. Default uzoff_t to unsigned long long if LARGE_FILE_SUPPORT manually
+ enabled for an otherwise unsupported port. tailor.h (Ed)
+98. Update copyright header. tailor.h (Ed)
+99. Change EXIT(0) to EXIT(ZE_LOGIC) for ziperr recursion. zip.c (Christian)
+100. Change EXIT(0) to EXIT(ZE_OK) for successful returns. zip.c,
+ zipcloak.c (Christian)
+101. Update license. zip.h (Christian)
+102. Initialized mesg in zipcloak.c, zipnote.c, zipsplit.c to fix access
+ violation crashes. (Christian)
+103. Added -q (Quiet mode) option to zipcloak, zipnote, zipsplit. (Christian)
+104. Add proto of mb_clen(). fileio.c (Cosmin)
+105. Synchronize ttyio.c and ttyio.h with the unzip-5.52 source. (Cosmin)
+106. Control the POSIX emulation provided by some Unix-on-Windows compiler
+ distributions, such as Cygwin, via the FORCE_WIN32_OVER_UNIX macro.
+ tailor.h, win32/Makefile.gcc (Cosmin)
+107. Remove getenv() declaration. util.c (Cosmin)
+108. Fix definitions of zopen and zstdin. unix/zipup.h (Cosmin)
+109. Enable binary file operations for DJGPP and Cygwin. unix/osdep.h (Cosmin)
+110. Remove -DMSDOS from CFLAGS; use correct dependency in target crc_i386.obj.
+ win32/makefile.w32, win32/makenoas.w32 (Cosmin)
+111. Update win32/makefile.bor and win32/makefile.gcc (Cosmin)
+112. Put mktemp() declaration inside the NO_PROTO guard. tailor.h (Cosmin)
+113. Use the right type (DWORD) for volSerNo, maxCompLen and fileSysFlags
+ in FSusesLocalTime(). win32/win32.c (Cosmin)
+114. Set the "zip Debug" configuration as default. win32/vc6/zip.dsp (Cosmin)
+115. Define ASM_CRC by default. win32/osdep.h (Cosmin)
+116. Avoid using file names that are distinguished solely by letter case;
+ e.g. crc_i386.S and crc_i386.s. unix/Makefile (Cosmin)
+117. Stylistic fix inside ex2in(). unix/unix.c (Cosmin)
+118. Change zlist dsk from ush to ulg to support Zip64 and added casts in
+ zipfile.c to write ush. zip.h, zipfile.c (Christian, Ed)
+119. Conditionally apply S_IFLNK to support DJGPP. unix/unix.c (Cosmin)
+120. Change -dd [siz] (display dots, set optional dot size) to the options
+ -dd (turn dots on, use 10 MB default) and -ds siz (set dot size).
+ Found that using -dd with an optional value got confusing as detection
+ of an optional argument, when the next argument was not either an option
+ or the end of the line, was easy to overlook. Easier to avoid optional
+ values. zip.c (Ed)
+121. Change text output of manual pages to zip.txt, zip.txt, zipcloak.txt,
+ zipnote.txt, zipsplit.txt. unix/Makefile (Christian, Ed)
+122. Change comments using // to /* */ format. api.c, zip.c (Christian)
+123. Add support for signals SIGABRT, SIGBREAK, SIGBUS, SIGILL, and SIGSEGV
+ to utilities. zipcloak.c, zipnote.c, zipsplit.c (Christian)
+124. Update ToDo30.txt file (Ed)
+125. Delete old Manual file (Ed)
+126. Update WHERE from Zip 2.32 (Ed)
+127. Change description of dot-size. zip.c (Ed)
+128. Change VMS to use -ds to set dotsize. vms/cmdline.c (Ed)
+129. Update manuals. man/zip.1, man/zipsplit.1, man/zipnote.1,
+ man/zipcloak.1 (Ed)
+130. Detect i586, i686 and Cygwin in version_local(). unix/unix.c (Cosmin)
+131. Add clean target. win32/makefile.w32, win32/makenoas.w32 (Cosmin)
+132. Changed most 64-bit size/offset variable declarations (like zoff_t)
+ into "unsigned" type (like uzoff_t), for better backward compatibility
+ with non-ZIP64_SUPPORT setups where "ulg" was used for these variables.
+ deflate.c, fileio.c, globals.c, trees.c, vms/vms_pk.c, win32zip.c,
+ zip.c, zip.h, zipfile.c, zipup.c (Christian)
+133. Add (ulg) cast to strstart in flush_block. deflate.c (Christian)
+134. Updated Win32 LARGE_FILE_SUPPORT setup for Watcom and MinGW.
+ tailor.h, win32/osdep.h (Christian)
+135. Add attempt count to tempname(). fileio.c (Christian)
+136. Fixed size counter handling in debug code for Zip64. trees.c (Christian)
+137. Moved cryptnote display text definition into revision.h, like was done
+ in Zip 2.31. zip.c, revision.h (Christian)
+138. Add ZCONST. fileio.c (Christian)
+139. Removed earlier change in trash() where ASCII-containing iname was
+ searched for native-coded '/' characters. [Added note but left as
+ changed 5/20/05 EG] zipfile.c (Christian)
+140. Change zipup size error message to use zip_fzofft(). zipup.c (Christian)
+141. Updated win32/makefile.wat to enable Zip64 support and use directory
+ for intermediate files. (Christian)
+142. Change fcount and zcount from ulg to extent as extent is used internally,
+ but Zip64 standard supports up to ulg. Add note to zip.h. globals.c,
+ zip.h (Christian)
+143. Define NO_W32TIMES_IZFIX in compile options when appropriate. Add
+ version information for USE_ZLIB compiler option. zip.c (Christian)
+144. Add support for SIGABRT, SIGBREAK, SIGBUS, SIGILL, and SIGSEGV signals.
+ zip.c (Christian)
+145. Add display-usize option to show uncompressed size. zip.c (Ed)
+146. Add many descriptions to options table. zip.c (Ed)
+147. Remove -R from help screen as on extended help screen. zip.c (Ed)
+148. Add basics to extended help. zip.c (Ed)
+149. Fix checks in scanzipf_reg() for empty file since cenbeg now unsigned.
+ Change buffer from t to b in small big check. Back up after small
+ zip big archive check. zipfile.c (Ed)
+150. Change Zip64 not supported warning in scanzipf_reg(). zipfile.c (Ed)
+151. Fix bug where local and central headers were not matching when compiled
+ with NO_LARGE_FILE_SUPPORT. Restored order of zlist structure elements
+ to match order of local header as scanzipf_reg() compares it as an
+ array of bytes to the local header. Gag. It needs fixing but at least
+ it works as intended now. zip.h, zipfile.c (Ed)
+152. Minor fix from 10000 to 10 K for WriteNumString(). util.c (Ed)
+153. Add overflow check to file_read(). zipup.c (SMS)
+154. Add parameter p1 product specification. vms/collect_deps.com (SMS)
+155. VMS changes. vms/descrip_mkdeps.mms (SMS)
+156. Change zoff_t to uzoff_t and unsigned int to size_t. vms/vms_im.c,
+ vms/vms_pk.c (SMS)
+157. Fix ; that was : at end of line. Fix DisplayNumString() prototype.
+ zip.h (Ed)
+158. Get rid of leading blanks in DisplayNumString(). util.c (Ed)
+159. Reset dot_count each file. zipup.c (Ed)
+160. Minor changes to extended help. zip.c (Ed)
+161. Move defines into DEFINED_ONCE block. api.h (Mike)
+162. Add Still Remaining And Planned For Zip 3.0 section. WhatsNew (Ed)
+163. Delete quotes around CHANGES. Readme (Ed)
+164. Add -lf, open file at path and use for logging, -la, append to
+ existing logfile, and -li, include informational messages, options.
+ globals.c, zip.h, zip.c (Ed)
+165. Update extended help to include logging. zip.c (Ed)
+166. Add support for required short option value in form -o=value as optional
+ does. fileio.c (Ed)
+167. If bytes_total is smaller than bytes_so_far for some reason then display
+ negative of bytes_to_go. This can happen if files grow in size after all
+ the sizes are initially added up. zip.c (Ed)
+168. Use usize from filetime for adding to bytes_total when updating instead
+ of size in old entry. zip.c (Ed)
+169. Change status counts files_so_far and bytes_so_far to include bad files
+ so the status counts end at the end but add bad_files_so_far and
+ bad_bytes_so_far to track bad files. After minor fixes it looks like
+ the counts remaining at the end are correct, even when some files are
+ not readable. Update bad file warnings. zip.c, zip.h, globals.c,
+ zipup.c (Ed)
+170. Add uq for unsigned q in zipup(). Initialize z->len in case an error
+ later so have a valid size. zipup.c (Ed)
+171. Check noisy in DisplayRunningStats() so logging is independent of it.
+ zip.c (Ed)
+172. Add check in DOS for windows and if running DOS version on Windows warn
+ user. zip.c, msdos/msdos.c, msdos/osdep.h (Johnny)
+173. Add errno.h for strerror(errno) call. zip.c, zipup.c (SMS)
+174. Fix log problem if using -q option. zipup.c (Ed)
+175. Change "Far char" to "char Far" as Far is a qualifier not for the char
+ type but the storage allocation of the array. fileio.c (Christian)
+176. Update note on extent. globals.c (Christian, Ed)
+177. Remove extra USE_ZLIB. zip.c (Christian)
+178. Add note for the OEM_RUSS '/' bug. Need to look at later as it seems
+ the Russian bug remains unfixed. zipfile.c (Christian, Ed)
+180. So byte counts always come out even, create good_bytes_so_far to
+ count bytes read in and convert bytes_so_far to use the counts
+ from the initial scan. If files change during the zip operation
+ good_bytes_so_far will change and not match bytes_so_far.
+ zip.h, globals.c, zip.c (Ed)
+181. Changes to extended help. zip.c (Ed)
+182. Update WhatsNew (Ed)
+183. Update DLL resource copyright. windll.rc, windll.aps (Ed)
+184. Add directory search improvements to Win32 (within recursion, reuse
+ attribs from directory lookup to avoid calling stat()). Add
+ getd_attribs(), procname_win32(). win32/win32zip.c (Johnny)
+185. Cache result of IsFileSystemOldFAT() to avoid repetitive system calls
+ for identical information. win32/win32.c (Johnny)
+186. Add optimization to dosmatch(): apply alternate shortcut code when the
+ pattern to match consists of one multichar wildcard ('*') followed
+ by a fixed string. util.c (Johnny)
+187. Move DOS check_for_windows() checks to Help and Version and errors
+ only. Shorten message to one line. zip.c, msdos/msdos.c (Ed)
+188. Define WIN32_OEM to enable oem ansi conversions for more than RSXNT.
+ Not yet fully implemented. win32/win32.c, win32zip.c, zip.c,
+ zipfile.c (Ed)
+189. Directory search improvements for MSDOS. msdos/msdos.c (Johnny)
+190. Add caching of directory information. If pattern is just *string no
+ need to recurse. win32/win32.c (Johnny)
+191. If wild_stop_at_dir then do recurse to handle cases like a/b/*.txt.
+ win32/win32.c (Ed)
+192. Additional improvements to directory search speedups, including
+ a) MSDOS port fixes for Turbo C++ compiler
+ b) In both Win32 and MSDOS, change getDirEntryAttr() into macro,
+ saving one function call overhead
+ e) Add explaining comment to optimized procname_{local} code
+ f) In util.c, move "*literal" pattern-matching optimization from
+ dosmatch() to recmatch(). Advantages:
+ - optimization used for all systems
+ - optimization applied to all occurences where a "*" is last wildcard
+ in pattern
+ - "dosmatch()" only preconditoning wrapper for matching workhorse
+ "recmatch()", it should not implement matching algorithms itself
+ - optimization not applied for WILD_STOP_AT_DIR option
+ g) >>>disabled<<< "*literal" optimization for all MBCS-aware environments,
+ because suspect that supplied optimization code is not MBCS-clean
+ (for details see the comment within the patch), so IS NOT USED for
+ win32 port! Can force activation of match optimization by specifying
+ conditional compilation symbol TEST_FOR_MBCS_CLEAN.
+ (Christian)
+193. Add and move comments, implement changes for directory search improvements
+ in Zip 3.0 util.c (Ed)
+194. In win32/win32.c, IsFileSystemOldFAT(), add declarations of static caching
+ variables where missing to fix win32 port compilation bug (Christian)
+195. Correct changed arguments in RSXNT-only character set conversion
+ call. win32/win32zip.c (Christian)
+196. Implement Directory Search improvements from Zip 2.32. win32/win32zip.c
+ (Johnny, Ed)
+197. Debian Bug #312090 fix. Reworded man page to give multiple examples of
+ recursion, not just zip -r foo foo. man/zip.1 (Ed)
+198. Change "-Aa -D_HPUX_SOURCE +e" to -Ae for HP. "HP-UX with the HP compiler
+ and on AIX 4.2.0. AIX 5.1 with gcc-3.4.3 (32-bit) and Darwin built fine
+ - though AIX 5.1 needed CC=gcc make -e ... to find gcc. According to the
+ HP-UX man page -Ae is equivalent to -Aa -D_HPUX_SOURCE +e it seems the
+ +e is needed and -Ae is more terse anyway." Expression generated before
+ was too long. unix/configure (Rodney Brown)
+199. Add support for osf4.0f that does not have fseeko or ftello but has 64-bit
+ fseek and ftell though. tailor.h (Rodney)
+200. Fix unsigned char to char in recmatch(), add casts for compares. util.c
+ (Ed)
+201. Fix for alpha off_t long long. unix/osdep.h (Rodney)
+202. Change shmatch() from uch to char and change parameters to recmatch().
+ Change dosmatch(). util.c (SMS, Rodney, Ed)
+203. Add local for DisplayRunningStats(). zip.c (Rodney, Ed)
+204. Disable unused append_ubyte_to_mem(). Fix error messages in other append.
+ zipfile.c (Rodney, Ed)
+205. Delete unused getDirEntryAttribs(). msdos/msdos.c (Christian)
+206. Change warning when running msdos version on Windows. msdos/msdos.c (Ed)
+207. Change recmatch() to support MBCS matching. util.c (Christian)
+208. Update WhatsNew (Ed)
+209. Update Readme (Ed)
+210. Format Readme to fit in 80 character lines (SMS, Ed)
+211. Rename install.vms to install_vms.txt. vms/install_vms.txt (SMS)
+212. Add reference to vms/install_vms.txt in INSTALL (SMS)
+213. Update INSTALL (Ed)
+214. Remove ALT_NEXTBYTE and Building UnZip sections as no longer needed.
+ vms/notes.txt (SMS, Ed)
+215. Add note to TODO (Ed)
+216. Update Makefile message to suggest using generic. unix/Makefile (Ed)
+217. Update text output of manual. zip.txt (Ed)
+218. Update VMS section. INSTALL (SMS, Ed)
+219. Minor changes in vms/install_vms.txt (SMS, Ed)
+220. Update VMS install information. INSTALL, vms/install_vms.txt (SMS, Ed)
+221. Do not use _stati64 under Cygwin. win32/osdep.h (Cosmin)
+222. Add note to Makefile to use generic first. unix/Makefile (Ed)
+223. Add Test option for VMS CLI. vms/cmdline.c (SMS, ?)
+224. Add noconfirm to deletes, define symbol edit. vms/descrip.mms (SMS)
+225. Changes to vms/install_vms.txt (SMS)
+226. Add note on symbols to VMS. INSTALL (SMS)
+227. Update license headers. vms/osdep.h, vms/vms.h, vms/vmsmunch.c,
+ vms/zipup.h, vms/vmszip.c, vms/vms.c, vms/vms_im.c, vms/vms_pk.c,
+ vms/command.c (Ed)
+228. Add stsdef.h include for VMS and convert unzip test return to VMS
+ result for VMS. zip.c (SMS)
+229. Add const to ziperr(). amiga/amiga.c (Paul)
+230. Clean up makefile. amiga/makefile.azt (Paul)
+231. Don't try Amiga large file support. amiga/osdep.h (Paul)
+232. Add note on -V and -VV. vms/notes.txt (SMS)
+233. Small update. vms/zip_cli.help (SMS)
+234. Format Windows warning message. msdos/msdos.c (Christian)
+235. Format changes. util.c (Christian)
+236. Update VMS. INSTALL (SMS)
+237. Add creation of intermediate object directories. msdos/makefile.wat
+ (Christian)
+238. Add void * cast. msdos/msdos.c (Christian)
+239. Add include for mktemp(). msdos/osdep.h (Christian)
+240. Fix __RSXNT__ and WIN32_OEM define blocks. win32/win32.c (Christian)
+241. Fix __RSXNT__ and WIN32_OEM define blocks. win32/win32zip.c (Christian)
+242. Add != NULL to check. zip.c (Christian)
+243. Fix WIN32_OEM. zipfile.c (Christian)
+---------------------- October 11th 2005 version 3.0f01 ----------------------
+(the internal betas may be merged later)
+ 1. Add DSEG for Watcom data segment. msdos/makefile.wat (Christian)
+ 2. Add -zq and use assembler. os2/makefile.os2 (Christian)
+ 3. Update header. os2/match32.asm (Christian)
+ 4. Change len from int to unsigned int. os2/os2.c (Christian)
+ 5. In GetLongPathEA() limit tempbuf to CCHMAXPATH. os2/os2.c (Christian)
+ 6. Add DWATCOM_DSEG to use data segment. win32/makefile.wat (Christian)
+ 7. Update header and add DGROUP. win32/match32.asm (Christian)
+ 8. Add UNICODE_SUPPORT define. zip.h, zip.c (Ed)
+ 9. Add oname to f and z structs for the display name to use in messages.
+ Change z->zname to z->oname in messages. fileio.c, zip.c, win32zip.c,
+ zipup.c, zipfile.c, zip.h (Ed)
+10. Move multi-byte defines to make global (they were needed with wide
+ characters but that was taken out and left them where they are).
+ fileio.c, zip.h
+11. Add copy_args(), free_args(), and insert_arg() to create copy of argv
+ that can free() and to support inserting "@" in get_option for lists.
+ fileio.c, zip.h
+12. Insert arg "@" after list if not followed by option. fileio.c
+13. Add args variable and copy argv to args so can use insert_arg(). zip.c
+14. Add MKS Korn Shell note. zip.c
+15. Change cast of option in add_filter() calls from char to int. zip.c
+16. Implement multi-byte version of Unicode support. To support Win32 NT
+ wide calls will require additional work not planned for this release.
+ Changes include (Ed):
+ - Add use_wide_to_mb_default flag. globals.c, zip.h
+ - Add compiler UNICODE_SUPPORT version information. zip.c
+ - Add uname to f and z structs for UTF-8 name. zip.c
+ - Moved some defines out of ZIP64 section. zipfile.c
+ - Add define UTF8_PATH_EF_TAG for Unicode Path extra field. Currently
+ the tag is 0x7075 which is 'u' 'p' for Unicode path and seems
+ free according to the AppNote. The extra field is
+ tag (2 bytes 'u' 'p')
+ size (2 bytes)
+ Unicode Path size (2 bytes)
+ unused (2 bytes set to 0)
+ unused (2 bytes set to 0)
+ Unicode path (variable)
+ The unused locations also serve as a check in case the tag is in
+ use already.
+ - Add add_Unicode_Path_local_extra_field() and
+ add_Unicode_Path_cen_extra_field() functions. zipfile.c
+ - Add read_Unicode_Path_entry() function. zipfile.c
+ - Set uname and oname in scanzipf_ref(). zipfile.c
+ - Add define wide_to_mb_default. Add zchar but not used. win32/osdep.h
+ - Add wide command line reading but don't use. win32/win32.c
+ - Add port functions for Unicode, including local_to_utf8_string(),
+ wide_to_escape_string() (for converting a wide character that can't be
+ converted to mb in the local character set to a reversable escape string),
+ escape_string_to_wide(), wide_to_local_string(), local_to_display_string()
+ (for creating the display version of name), utf8_to_local_string(),
+ local_to_wide_string(), wide_to_utf8_string() (NOT IMPLEMENTED), and
+ utf8_to_wide_string() (NOT IMPLEMENTED). win32/win32.c
+ - Implement attempt at escape function. Whenever a wide character can't
+ be mapped to the local character set, this function gets called.
+ Currently the wide character is converted to a string of hex digits.
+ If the wide can fit in 2 bytes then the form #1234 is used. If not,
+ the 4-byte form #L12345678 is used.
+ It compiles but needs the utf8 functions implemented. Also needs testing
+ in a multi-byte environment and only Windows is implemented so need to at
+ least do Unix. (Ed)
+17. Update freeup() to include uname and oname. zip.c
+18. Move define wide_to_mb_default so default for all is '_'. zip.h (Ed)
+19. No changes needed to osdep.h and update unix/unix.c but not tested. (Ed)
+---------------------- October 19th 2005 version 3.0f02 ----------------------
+ 1. Remove null value check for split_size as get_option() already checks.
+ zip.c (Ed)
+ 2. Update f$search(). vms/descrip.mms (SMS)
+ 3. Save parse name before search and use that on failure. Change name parsing
+ in ziptyp() to solve a problem with search-list logical name device directory
+ specs. vms/vms.c (SMS)
+ 4. Compile in UNICODE_SUPPORT if have wchar_t and mbstowcs(). unix/configure (Ed)
+ 5. Move Unicode defines to zip.h and functions to fileio.c so generic. Create
+ a new OEM function for Windows. fileio.c, zip.h, tailor.h, win32/win32.c (Ed)
+ 6. Add UTF-8 functions. fileio.c (Paul)
+ 7. Convert Unicode functions to use zwchar defined as unsigned long for wide
+ char. fileio.c, zip.h (Ed)
+ 8. Add wchar_t check for Unix. unix/configure (Ed)
+ 9. Add default when zwchar (4 bytes) is too big for wchar_t (2 bytes). zip.h (Ed)
+10. Allow for states for wide characters but surrogates not done. fileio.c (Ed)
+11. Update WhatsNew (Ed)
+---------------------- December 16th 2005 version 3.0f03 ----------------------
+ 1. Fix broke encryption when ZIP64_SUPPORT enabled by accounting for need for
+ data description when encrypting. Data description is not required for
+ encryption (WinZip does not use one) but seems needed by Zip for some reason.
+ zipfile.c (Ed)
+ 2. Add function bfwrite() to do buffered fwrite(). Most output already is
+ written by zfwrite used by crypt.c which now calls bfwrite. All splitting
+ and new byte counts are done in bfwrite. fileio.c (Ed)
+ 3. Move some functions out of ZIP64_SUPPORT defines for use with UNICODE_SUPPORT.
+ zipfile.c, zip.h (Ed)
+ 4. Add is_ascii_string() and only create Unicode extra field if z->iname is
+ not ascii. zipfile.c, zip.h, fileio.c, (Ed)
+ 5. Add parameter rewrite to putlocal() to note when rewriting bytes so the bytes
+ rewritten are not counted in output totals. zipfile.c, zip.h (Ed)
+ 6. Handle VMS ... wildcard. util.c (SMS)
+ 7. Make tempzip file name global. zip.c, globals.c, zip.h (Ed)
+ 8. Add out_path global and -O path option to allow the output archive to have a
+ different name than the input archive, if there is one. This allows
+ updating a split archive, since output to the same split name would otherwise
+ be complicated and not user friendly. Use out_path for output. zip.h,
+ zip.c, globals.c (Ed)
+ 9. Many output functions that had output file y as parameter, such as zipup(),
+ zipcopy(), putlocal(), putcentral(), and putend(), now do not as y is
+ now global. This allows changing y as splits are created. zip.c (Ed)
+10. Add function zipmessage() for writing messages like zipwarn() but are
+ informational. zip.c (Ed)
+11. Minor changes to help. zip.c (Ed)
+12. Add SPLIT_SUPPORT to version output. zip.c (Ed)
+13. Add rename_split() to rename and set attributes for a split. zip.c (Ed)
+14. Add set_filetype() to set attributes of split. zip.c (Ed)
+15. Change variable a (holds attributes) to zipfile_attributes and make global.
+ zip.c, zip.h, globals.c (Ed)
+16. Add key_needed flag for encryption and move setting key to after
+ command line processed. zip.c (SMS)
+17. Initialize dot size using default only if dot_size not set. zip.c (Ed)
+18. Change command line processing so that last -P or -e is used. zip.c
+ (Ed)
+19. Fix broke writing of 4-byte spanning signature at the beginning of the archive
+ if splitting. zip.c (Ed)
+20. Use bfcopy() instead of fcopy() to copy archive beginning. bfcopy() uses
+ global y. zip.c (Ed)
+21. It looks like tempzf is no longer used. zip.c (Ed)
+22. Account for SUNPRO_C and DECC_VER. Change SPARC to Sparc. unix/unix.c (SMS)
+23. Remove GNUC. vms/cmdline.c (SMS)
+24. Change case of system calls. vms/vms.c (SMS)
+25. Add fix for VMS ... matching, but may change Zip to avoid ex2in() and in2ex()
+ for pattern matching in future. vms/vmszip.c (SMS)
+26. Remove /NODIRNAMES and /DIRNAMES from VMS help. vms/zip_cli.help (SMS)
+27. Define new globals zip64_eocd_disk, zip64_eocd_offset, current_local_tempname,
+ bytes_this_split, and bytes_this_entry for splits. globals.c, zip.h (Ed)
+28. Add SUNPRO C and DEC C compile checks. unix/configure (SMS)
+29. Add CFLAGS_NOOPT for removing optimization for configure. unix/Makefile (SMS)
+30. Modify crypthead() to use bfwrite(). crypt.h, crypt.c (Ed)
+31. Modify zfwrite() to use global output file. crypt.h, crypt.c (Ed)
+32. Modify zfwrite() when no encryption to use bfwrite(). crypt.h (Ed)
+33. Add bfcopy() to copy to y. fileio.c (Ed)
+34. Add close_split() and bfwrite() for splits. fileio.c (Ed)
+35. Add is_ascii_string() to check if UTF-8 extra field is needed. fileio.c (Ed)
+36. Change Unicode escape of 2-byte wide from #1234 to #U1234. fileio.c (Ed)
+37. Add read_Unicode_Path_entry() to read the UTF-8 path extra field. zipfile.c (Ed)
+38. Latest Unicode Path extra field format is
+ 1 byte Version of Unicode Path Extra Field
+ 2 bytes Name Field Checksum
+ variable UTF-8 Version of Name
+39. Use CRC-32 for Unicode Path Checksum and AND halves. zipfile.c (Paul)
+40. Add Unicode Path Checksum check to make sure extra field applies to Name field
+ still. zipfile.c (Christian)
+41. Move get_extra_field() out of Zip64 block and make available for splits.
+ zipfile.c (Ed)
+42. Check in putlocal() using is_ascii_string() and don't create Unicode path
+ extra field if name is ASCII characters. zipfile.c (Ed)
+43. If local header for split is on another disk and using split method 1, close
+ that split in putlocal() after rewrite local header. zipfile.c (Ed)
+44. Fix data descriptor bug when encrypting where putextended() did not handle the
+ not Zip64 case, which mostly only happens now for encryption. zipfile.c (Ed)
+45. Check for ASCII name using is_ascii_string() in putcentral() for Unicode path
+ extra field. zipfile.c (Ed)
+46. Instead of single disk values, update putend() to use real split values for
+ current_disk, cd-start_disk, cd_entries_this_disk, cd_start_offset,
+ zip64_eocd_disk, zip64_eocd_offset, and current_disk and allow for
+ needing Zip64 if exceed standard max values for current_disk, cd_start_disk,
+ cd_entries_this_disk, total_cd_entries, and cd_start_offset. zipfile.c (Ed)
+47. Use current_local_offset and current_local_disk for z->off and z->dsk in
+ zipup(). zipup.c (Ed)
+48. Fix bug where force_zip64 was used to determine descriptor size but can have
+ Zip64 entry without force_zip64 so use zip64_entry. zipup.c (Ed)
+49. Change the p - o != s compression size test for splits to bytes_this_entry
+ != (key ? s + 12 : s) and avoid ftell() in split. zipup.c (Ed)
+50. If local header is on a previous split and split method 1 do the seek on that
+ split to update header. zipup.c (Ed)
+51. For streaming, only force Zip64 if reading stdin and writing a non-seekable
+ device. In other cases can detect either the input file size and set Zip64
+ if needed or seek in the output to update the local headers. zipup.c,
+ zipfile.c, zipup.c (Ed)
+52. Allow creation of stored archives with descriptors for testing. Currently
+ they can't reliably be read but this is planned. zipup.c, zipfile.c, zip.c
+ (Ed)
+53. Update help, adding in -e, -P, -s splitsize, -sp, and -sv options. zip.c (Ed)
+54. Spelling fix in zipsplit man page. man/zipsplit.1, zipsplit.txt (Ed)
+55. New option -sv and variable noisy_splits to enable verbose splitting.
+ Default is to quietly create splits, unless -sp set to pause between splits.
+ zip.h, zip.c, globals.c, fileio.c (Ed)
+---------------------- December 23rd 2005 version 3.0f04 ----------------------
+ 1. Move inlined text-vs-binary checks from file_read() into a separate,
+ new function named is_text_buf(). zipup.c, util.c, zip.h (Cosmin)
+ 2. Fix calls to putlocal to remove the removed dest parameter. crypt.c (Ed)
+ 3. Add get_split_path() to get the path for a split given the disk number.
+ fileio.c, zip.h (Ed)
+ 4. Change formatting of zipmessage() to remove tabbing and add formatting
+ to call to zipmessage(). fileio.c, zip.c (Ed)
+ 5. Initialize many variables such as y and tempzip. zip.c, fileio.c,
+ zipfile.c (Ed)
+ 6. Add loop to pause during split method 2 to allow changing disk or changing
+ the path for the next split. fileio.c (Ed)
+ 7. If after starting new split there is not enough room for the remaining buffer
+ for split method 1 display error and exit and for split method 2 we can
+ display a warning and user can replace disk or change path. fileio.c (Ed)
+ 8. Add list to store input file arguments using add_name() to add the name to
+ filelist_struc filelist and then process the names after the input archive
+ is read. zip.c (Ed)
+ 9. Fix infinite loop when opening a log file whose name contains multiple '/'.
+ zip.c (Cosmin)
+10. Move split size message lower and only output if option sv sets
+ noisy splits. zip.c (Ed)
+11. Set y to output file, remove output file from zipcopy(), putlocal(),
+ putcentral(), and putend(). zipsplit.c, zipnote.c, zipcloak.c (Ed)
+12. Add code for not SPLIT_SUPPORT case. zipfile.c, zipup.c (Ed)
+13. Prepend '-' to commands from target clean.
+ win32/makefile.w32, win32/makenoas.w32, win32/makefile.bor (Cosmin)
+14. Must not call putenv() in iz_w32_prepareTZenv() under Cygwin.
+ win32/osdep.h (Cosmin)
+15. Add browse info in Visual C++ 6 project. win32/vc6/zip*.dsp (Cosmin)
+---------------------- December 27th 2005 version 3.0f05 ----------------------
+ 1. Add proposed changes to License (Ed)
+ 2. Fix -l corruption bug by using memcpy() instead of wrongly changing the
+ buffer pointer. Fix was left out of last beta. zipup.c (Cosmin)
+ 3. Fix get_split_path() parameter. zip.h (SMS, Ed)
+ 4. Add -dg and display_globaldots to display dots globally for entire archive
+ instead of for each file. Is not affected by noisy flag. globals.c,
+ zip.h, zip.c, zipup.c, fileio.c (Ed)
+ 5. Make dot_count and dot_size uzoff_t, dot_count because with global dots
+ dot_count does not reset and with terabyte files the number of buffers
+ could exceed 2G, dot_size to allow use of ReadNumString() to read number.
+ zip.c, zip.h, globals.c (Ed)
+ 6. Add Deletion to help. zip.c (Ed)
+ 7. Fix delete date. zip.c (Ed)
+ 8. For streaming, need to assume Zip64 if writing a non-seekable device so
+ extra field for Zip64 is created if needed. zipup.c, zipfile.c, zipup.c (Ed)
+ 9. Add remove_local_extra_field() and remove_central_extra_field().
+ zipfile.c (Ed)
+10. Remove disabled copyright from license(). zip.c (Ed)
+11. Clean up recent changes. zip.c, zipfile.c, fileio.c, zip.h, zipup.c (Ed)
+12. Create scanzipf_regnew() for new file scan. zipfile.c (Ed)
+---------------------- December 29th 2005 version 3.0f06 ----------------------
+ 1. Change dot_size and dot_count from uzoff_t to zoff_t to allow use of
+ negative flag values. globals.c, zip.h (SMS, Ed)
+ 2. Remove file parameter to bfwrite() in putend(). zipfile.c (SMS, Ed)
+ 3. Add back code for not SPLIT_SUPPORT to putend(). zipfile.c (SMS, Ed)
+ 4. Change tag from ush to ulg in remove_local_extra_field() and
+ remove_central_extra_field() to avoid parameter problems. zipfile.c (Ed)
+ 5. Add allow_empty_archive to flag when want to create an empty archive.
+ globals.c, zip.h (Ed)
+ 6. Set allow_empty_archive when using -i and expecting an archive to be
+ created. This is in response to the 2/14/05 email. zip.c (Ed)
+ 7. Make before and after variables that hold the dates of files to
+ process or delete global so can use them in scanzipf_regnew(). zip.h,
+ zip.c, globals.c (Ed)
+ 8. Change scanzipf_regnew() to be based on scanzipf_fix() which seems closer.
+ Still have not coded the new regular zipfile reader. zipfile.c (Ed)
+ 9. For new reader first get add list and then read old archive and filter
+ as reading old entries. zip.c, zipfile.c (Ed)
+10. Define USE_NEW_READ to turn on using new reader, which is being
+ created. This allows all to work while the new reader is being worked
+ on. zip.c, zipfile.c (Ed)
+---------------------- January 9th 2006 version 3.0f07 ----------------------
+ 1. Remove dest parameter from crypthead() and zipcopy(). crypt.c (SMS, Ed)
+ 2. Change -ds to handle dots for as small as every 32 KB. zip.c (Ed)
+ 3. Add ask_for_split_write_path() and ask_for_split_read_path() for
+ asking where to put the next write split and for locating the next
+ read split. zip.h, fileio.c (Ed)
+ 4. Add in_path to track where reading splits from. zip.h, globals.c, zip.c (Ed)
+ 5. Update copyright date on changed files to include 2006 (Ed)
+ 6. Replace stderr with mesg for most output messages. deflate.c, fileio.c,
+ trees.c, util.c, zip.c, zipcloak.c, zipfile.c, zipnote.c, zipsplit.c
+ 7. Add mesg_line_started to track if need new line on mesg output and update
+ zipmessage() and zipwarn() to use it. Set mesg_line_started to 1 when
+ newline not last character written to mesg and 0 when it is. deflate.c,
+ zip.h, zip.c, globals.c, zipup(), fileio.c (Ed)
+ 8. Include base_path as parameter for get_split_path(). fileio.c (Ed)
+ 9. Account for VMS version in split path. Add vms_file_version(). fileio.c,
+ zip.c, vms/vms.c, vms/vms.h (SMS)
+10. Create crc16f() to create ANDed halves crc32 for Unicode using copy
+ of crc32() but may change to use main copy. zipfile.c, zip.h,
+ fileio.c (Ed)
+11. Close in_path and out_path in finish() and ziperr(). zip.c (Ed)
+12. Change perror() to strerror() and print to mesg in ziperr(). zip.c (Ed)
+13. Add find_next_signature() to find the next signature when reading a
+ zip file. zipfile.c (Ed)
+14. Add find_signature() to find a given signature from current point in
+ archive. zipfile.c (Ed)
+15. Add at_signature() to check if at a given signature in archive.
+ zipfile.c (Ed)
+16. Changes to scanzipf_regnew() but far from done. zipfile.c (Ed)
+17. Changes to readzipfile() to close input archive file and allow new
+ zipfile reader to open and close files as goes through splits.
+ zipfile.c (Ed)
+18. Change -s to default to MB and set minimum split size to 64k.
+ zip.c (Ed)
+19. Add link to user32.lib for CharToOem(). makefile.w32, makenoas.w32
+ (Cosmin)
+20. Remove unused Z64_EFPos. globals.c (Ed)
+---------------------- February 13th 2006 version 3.0f08 ----------------------
+ 1. Move option checks before any work is done. zip.c (Ed)
+ 2. Update bfcopy() to handle reading splits and remove input file
+ parameter and use global in_file. fileio.c (Ed)
+ 3. Change ask_for_split_read_path() to allow user aborting. fileio.c (Ed)
+ 4. Change get_split_path() to use standard file extensions from most
+ recent AppNote of .z01, .z02, ..., .z99, .z100, .z101, ... fileio.c (Ed)
+ 5. Change is_ascii_string to use 0x7F for ASCII detection. fileio.c (Ed)
+ 6. Add copy_only global for when -O is used to change the format of an
+ archive without changing the contents. This allows for converting an
+ archive to a split archive for instance. The global copy_only is used
+ to output status information for copies when normally copied files
+ have no status messages. globals.c (Ed)
+ 7. Add in_file, split_path, total_disks, current_in_disk, and
+ current_in_offset as globals to track reading splits. zip.h,
+ globals.c (Ed)
+ 8. Update copyright date. revision.h (Ed)
+ 9. Close in_file if open in finish(). zip.c (Ed)
+10. Add -O (big o) to extended help. zip.c (Ed)
+11. Remove readzipfile() from zipstdout() and use main call later down.
+ zip.c (Ed)
+12. Move archive reading and file scanning after command line checks.
+ zip.c (Ed)
+13. If -O out_zip and so have_out is set then set copy_only and allow
+ copying instead of error message *Nothing to do*. zip.c (Ed)
+14. If zipbeg is just 4 bytes and spanning then assume is spanning
+ signature and set zipbeg to 0 to ignore. zip.c (Ed)
+15. Don't open initial write test as modify if have_out is set and so have
+ a separate output file. zip.c (Ed)
+16. If zipbeg is 0 and nothing at beginning of archive to copy then don't
+ open input file until zipcopy() does. zip.c (Ed)
+17. If stuff at beginning then copy and close input file. Should be able
+ to keep it open but easier to close it and let zipcopy() reopen it.
+ zip.c (Ed)
+18. Add status message when copy_only set so something is displayed.
+ zip.c (Ed)
+19. Instead of closing x at bottom close in_file. The variable x was used
+ inconsistently and it seemed easier to make in_file global instead.
+ Then again y remains the global output variable. zip.c (Ed)
+20. Update copyright. zipnote.c, zipsplit.c, zipcloak.c (Ed)
+21. Change adjust_zip_local_entry() to return 1 if the entry is Zip64 and
+ 0 if not. This is needed to know how large the extended local header
+ is later. zipfile.c (Ed)
+22. Add read_Unicode_Path_local_entry() to read the local version of the
+ Unicode Path extra field. zipfile.c (Ed)
+23. Handle disk in adjust_zip_central_entry(). zipfile.c (Ed)
+24. Change USE_NEW_READ to SPLIT_SUPPORT as splits seems to be stable more
+ or less. zipfile.c (Ed)
+25. Add is_signature() to compate signatures. zipfile.c (Ed)
+26. Create scanzipf_fixnew(). It should look like scanzipf_regnew().
+ zipfile.c (Ed)
+27. Change scanzipf_regnew() to read the central directory and create zlist
+ and handle reading traditionally. Allows using central directory
+ information, in particular file sizes, in zipcopy() while reading
+ entries. Use global in_file instead of f for input file and set to NULL
+ when not a valid file so finish() only tries to close it if needed.
+ Check to make sure the End Of Central Directory record found is infact
+ the last one in case a stored archive is in the last 64 KB. Refuse
+ to update a split archive but recommend using -O instead. zipfile.c (Ed)
+28. Change readable check in readzipfile() to require input archive to exist
+ if using -O out_archive. zipfile.c (Ed)
+29. Change putlocal() to not create a Zip64 extra field unless needed and
+ on rewriting the local header to remove Zip64 extra field if was created
+ but not needed. Add check if assumed entry does not need Zip64 but does,
+ meaning probably the uncompressed size is less than 4 GB but the
+ compressed size is over 4 GB. zipfile.c (Ed)
+30. Change zipcopy() to use the global in_file and y files and to open and
+ close read splits as needed. Checks the local header against the
+ central directory header to verify same file, which should be as using
+ the disk and offset values from the central directory. Update disk and
+ offset in central directory. zipfile.c (Ed)
+31. Change out_path and out_len to base_path and base_len in
+ get_split_path(). fileio.c (SMS)
+32. Update command line options for VMS to include verbose splitting.
+ vms/zip_cli.cmd, vms/cmdline.c (SMS)
+33. Handle HP. unix/unix.c (SMS)
+34. Add adler16() checksum function. util.c (Cosmin)
+35. Use FILE_FLAG_BACKUP_SEMANTICS and a less demanding access mode
+ in CreateFile() when retrieving file attributes. Fixes a problem
+ when adding a directory entry from an NTFS or a CDFS partition
+ (i.e. one that stores timestamps using universal time), and the
+ directory timestamp is not the same daylight savings time setting.
+ The effect is an offset in the timestamp by one hour, if zip is
+ built using NT_TZBUG_WORKAROUND. The problem is not exposed,
+ however, if NO_W32TIMES_IZFIX is defined. win32/win32.c (Cosmin)
+---------------------- March 19th 2006 version 3.0f09 ----------------------
+ 1. Fix encryption problem where a large file with uncompressable data
+ can cause deflate to store bad data. See crypt.c for details.
+ Thanks to the nice people at WinZip for finding and providing the
+ details of this problem. crypt.c (Ed)
+ 2. Add note at top of Extended Help to refer to the Zip Manual. zip.c
+ (Ed)
+ 3. Update extended help for delete. zip.c (Ed)
+ 4. Change crypthead() to use buffer and bfwrite() which is split aware.
+ crypt.c (Ed)
+ 5. Create SPLIT_SUPPORT version of zipcloak() and zipbare() and read
+ local header rather than assume data using central header. crypt.c (Ed)
+ 6. Change zfwrite() to use global output file y. crypt.c (Ed)
+ 7. Remove in and out parameters from zipcloak() and zipbare() for
+ splits. crypt.h, zipcloak.c (Ed)
+ 8. Change get_split_path() to get_in_split_path() and get_out_split_path().
+ zipfile.c, fileio.c, zip.h (Ed)
+ 9. Change crc32f() to crc32u(). fileio.c, zip.h (Ed)
+10. Add encryption overwrite fix to copy_block() and remove from zfwrite().
+ crypt.c, tree.c (Ed, Christian)
+11. Add note on bug fix. WhatsNew (Ed)
+12. Add copy_only mode. zip.c (Ed)
+13. Make SPLIT_SUPPORT the default. zip.h (Ed)
+14. Add set_filetype(), rename_split(), and zipmessage(). zipcloak.c,
+ zipnote.c, zipsplit.c (Ed)
+15. Add long option support. zipcloak.c (Ed)
+16. Set in_path. zipcloak.c, zipnote.c, zipsplit.c (Ed)
+17. Use SPLIT_SUPPORT calls. zipcloak.c, zipnote.c, zipsplit.c (Ed)
+18. Set current_disk, cd_start_disk, and cd_entries_this_disk for use
+ by putend() and bytes_this_split for putcentral(). zipsplit.c (Ed)
+19. Include ctype.h for toupper(). zipfile.c (Ed)
+20. Add readlocal() for utilities to read local header. zipfile.c (Ed)
+21. Put Zip64 variables and code in ZIP64_SUPPORT ifdef in scanzipf_regnew().
+ zipfile.c (Ed, SMS)
+22. Use zip_fzofft() for converting offset. zipfile.c (Ed, SMS)
+23. Add casts to many append to memory calls. zipfile.c (Ed)
+24. Move handling of .zip split to get_in_split_path() and
+ get_out_split_path(). zipfile.c (Ed)
+25. Handle fix = 3 case for ZipNote that renames entries in zipcopy().
+ zipfile.c (Ed)
+26. Restore clearing of extended local header bit when not encrypting. When
+ encrypting need to output extended local header using putextended() in
+ zipcopy(). zipfile.c (Ed)
+27. Add notes on using file time for encrypting. zipup.c (Ed)
+28. Remove extended local header bit separately for z->lflg (local flags)
+ and z->flg (central directory flags). These should be the same but
+ could be different. zipup.c (Ed)
+29. Suppress command line globbing for MINGW. win32/win32.c (Christian)
+30. Add EF UT time fix for delete. zip.c (Christian)
+---------------------- April 28th 2006 version 3.0f10 ----------------------
+ 1. Add note to extended help to escape [ as [[] or use -nw. zip.c (Ed)
+ 2. Remove local declaration of tempfile as now global. zipnote.c,
+ zipcloak.c (SMS)
+ 3. Add zip_fzofft() for outputting uzoff_t bin size c. zipsplit.c (SMS)
+ 4. Add only_archive_set and clear_archive_bits to do Window archive bit
+ selection and clearing. Add -AS option to require DOS Archive bit
+ be set and -AC to clear archive bits of included files. Add
+ ClearArchiveBit() to clear archive bits after archive created.
+ Only Win32. globals.c, zip.h, zip.c, win32zip.c, win32.c (Ed)
+ 5. Change procname_win32() and readd() to check archive bit.
+ win32/win32zip.c (Ed)
+ 6. Update copyright. win32/win32zip.h (Ed)
+ 7. Add mesg_line_started = 0 to stats to remove blank line when clearing
+ archive bits. zipup.c (Ed)
+ 8. Add zip_fzofft() to format split size. zipsplit.c (SMS)
+ 9. Update help for splits and archive bit and add note on escaping [.
+ zip.c (Ed)
+10. Add -M option and bad_open_is_error to exit with error if any input
+ file unreadable. Also error if -M and would get "name not matched"
+ warning. zip.c (Ed)
+11. Copy Zip 2.32 csharp example, though it is designed for zip32.dll and
+ not zip32z64.dll from Zip 3.0. Updated note. windll/csharp (Ed)
+12. Change -M to -MM and define -mm to avoid accidental use of -m.
+ zip.c (Ed)
+13. Define split_method -1 to not allow splitting, mainly used when reading
+ a split archive to stop automatic splitting of output with same
+ split size. Now -s=0 or -s- disables splitting. zip.h, globals.c,
+ zip.c (Ed)
+14. Add fflush() after dots displayed. deflate.c, fileio.c, zipup.c (Ed)
+15. Instead of assuming buffer size as 32 KB for dots, use WSIZE for
+ compressing and SBSZ for storing and calculate as dots are counted.
+ Now dot_count and dot_size are bytes instead of buffers. Add dots
+ to Delete and Archive modes. zip.c, zipup.c, deflate.c, fileio.c (Ed)
+16. If reading a split archive and split size has not been given, get
+ size of first split read by zipcopy(), which should be the first
+ split, and set split size to that, making the output archive the same
+ split size as the input archive. Delay -sv split size message
+ if split size is 0 at first but then changed. zipfile.c (Ed)
+17. Add proc_archive_name() for new archive mode to process names in old
+ archive only and skip looking on the file system. Easier than modifying
+ the various port codes. fileio.c (Ed)
+18. Fix cd_start_offset bug. fileio.c (Ed)
+19. Create new action ARCHIVE that looks for matches only in old archive
+ for Copy Mode. If no input paths and there is an output archive,
+ Copy Mode is assumed even without ARCHIVE. Old default Copy Mode
+ when no input files updated to work like -U mode and allow filters.
+ New global copy_only currently only used to control global dots.
+ zip.c, fileio.c, globals.c, zip.h (Ed)
+20. Update help. Change extended help to more help. Update more help
+ to include internal modes delete and new Archive. Update help for
+ formatting options. Update help for wildcards. Remove streaming
+ examples from top basic section. Indent examples. Help for new
+ --out and Copy Mode. Add warnings that output using data descriptors
+ may not be compatible with some unzips. Update dots help and add
+ warning that dot size is approximate. Add help for new DOS archive
+ bit options. More help for -b and -MM. zip.c (Ed)
+21. Add support for Unix FIFO (named pipe). Add set_extra_field() stat
+ name ending in '/' fix found in Zip 2.32. unix/unix.c (Ed)
+22. Add check to not allow setting -U (internal copy) in similar cases to
+ -d (delete). zip.c (Ed)
+23. Add counts for internal modes Delete and Archive. Byte counts for -db
+ remain uncompressed size for external modes, but internal modes Delete
+ and Archive now use compressed sizes as these copy that many bytes.
+ zip.c (Ed)
+24. Add check for when ftell() wraps. zipup.c (Ed)
+25. Add mesg_line_started = 0 to result percentage message. zipup.c (Ed)
+26. Update contact information. unix/packaging/preinstall.in (SMS, Ed)
+27. A few Zip64 fixes to set Zip64 correctly and fix disk and offset of
+ Zip64 End Of Central Directory. zipsplit.c (Ed)
+28. Update comments for get_option(). fileio.c (Ed)
+29. Update DLL version. windll/windll.rc (SMS, Ed)
+30. New option -sf shows files that would be operated on. zip.c (Ed)
+---------------------- May 5th 2006 version 3.0f11 ----------------------
+ 1. Use C prototypes for Unicode functions. fileio.c (SMS)
+ 2. Change constant for mask in set_file_type from unsigned to signed.
+ trees.c (SMS)
+ 3. Use C prototypes for zip_fzofft() and zip_fuzofft() signed and
+ unsigned zoff_t formatting functions. util.c (SMS)
+ 4. Remove U from constants in Adler16 code. util.c, zip.h (SMS)
+ 5. Add spaces to VMS usage to avoid misinterpretation. zip.c (SMS)
+ 6. Add OF() to at_signature(). zipfile.c (SMS)
+ 7. Use zip_zofft() for entries error. zipfile.c (SMS)
+ 8. Remove U in constants in percent(). zipup.c (SMS)
+ 9. VMS command line updates. vms/cmdline.c, vms/descrip_deps.mms,
+ vms/vms_zip.rnh, zip_cli.cld, vms/zip_cli.help (SMS)
+10. Update to VMS help. vms/zip_cli.help (Ed)
+11. Check for memmove() and strerror(). Remove specific 64-bit support
+ for SunOS, as large file support now does. unix/configure (SMS)
+12. Add emergency replacements for memmove() and strerror().
+ unix/unix.c (SMS)
+13. Remove old not SPLIT_SUPPORT code. globals.c, zipnote.c, fileio.c,
+ crypt.h, crypt.c, zipcloak.c, zip.h, zip.c, zipup.c, zipsplit.c,
+ zipfile.c (Ed)
+---------------------- May 12th 2006 version 3.0f12 ----------------------
+ 1. Add UNICODE_SUPPORT ifdef around uname in zipup(). zip.c (SMS)
+ 2. Change size from uzoff_t to zoff_t in zipcopy(). zipfile.c (SMS, Ed)
+ 3. Fix a bug where filetime() returns -1 for device but not handled in
+ byte counts. zip.c (Ed)
+ 4. Add check for UnZip version and exit if not 6.00 or later if
+ a Zip64 archive. Define popen() and pclose() in Win32 to native
+ _popen() and _pclose(). ziperr.h, zip.c, win32/osdep.h (Ed)
+ 5. Add -sb option to ring bell when pause to change disk. Use new
+ global split_bell. global.c, zip.h, zip.c, fileio.c (Ed)
+ 6. Enable crc32u() and use for Unicode extra field. fileio.c (Ed)
+ 7. Add -dv to display volume being written to. zip.c, zip.h,
+ globals.c (Ed)
+ 8. Update WhatsNew. WhatsNew (Ed)
+ 9. Help updates. zip.c (Ed)
+10. Create option -X- (negated -X) to keep old extra fields and remove
+ -XX which is now -X. Make get_extra_field() global. Add
+ copy_nondup_extra_fields()to copy old extra fields not already
+ in new extra fields. zipup.c, zip.c, zipfile.c (Ed)
+11. Use output name oname for -sf option to show files that would be
+ worked on. zip.c (Ed)
+12. When updating or freshening old entries, read the old local header
+ with readlocal() to get local flags and extra fields. zip.c (Ed)
+13. Add UNICODE_SUPPORT ifdefs around uname code. zip.c (SMS, Ed)
+14. If WIN32_OEM set then on WIN32 store OEM name in archive. As read
+ DOS or WIN32 archives convert assumed OEM paths to ANSI. Remove old
+ WIN32_OEM code. Make oem_to_local_string() global for WIN32_OEM and
+ local_to_oem_string() global for WIN32_OEM and UNICODE_SUPPORT.
+ zip.h, zipfile.c, zipup.c, win32/win32.c, win32/win32zip.c (Ed)
+15. Update error 8 to include wrong unzip. ziperr.h (Ed)
+16. Change checksum for Unicode extra field to standard crc32 using
+ C version crc32u(). Add crctab.c. win32/vc6/zipnote.dsp,
+ win32/vc6/zipsplit.dsp, zipfile.c
+17. Update readlocal() to handle multi-disk archives if not UTIL.
+ zipfile.c (Ed)
+18. Convert size to signed zoff_t in zipcopy(). Update note.
+ zipfile.c (Ed)
+19. Update Readme. Readme (Ed)
+20. Add crctab.o to zipsplit and zipnote. unix/Makefile (Ed)
+21. Proposed update to license. License (Ed)
+---------------------- May 20th 2006 version 3.0f13 ----------------------
+ 1. Reformat License file. License (Cosmin)
+ 2. Change %d to %lu for disk number and add cast. zip.c (Cosmin, Ed)
+ 3. Display Scanning files message after delay at start based on
+ suggestion from Greg. Currently the time is checked every 100
+ entries processed. After 100 entries the start time is saved.
+ After 5 seconds or 100 entries after that, whichever takes
+ longer, the Scanning files message is displayed and every 2 seconds
+ or 100 entries, whichever takes longer, after that a dot is displayed.
+ fileio.c, zip.c, globals.c, zip.h (Greg, Ed)
+ 4. Add Unicode mismatch flag and option -UN. Default is now a Unicode
+ mismatch is an error. -UN=warn outputs warnings and continues,
+ -UN=ignore disables warnings, and -UN=no ignores the Unicode extra
+ fields. globals.c, zip.h, zipfile.c (Ed)
+ 5. Add options for VMS. vms/cmdline.c, vms/zip_cld.cld (SMS)
+ 6. Add casts to percent(). zipup.c (Ed)
+ 7. Minor changes to logfile formatting. zip.c (Ed)
+ 8. Update help. zip.c (Ed)
+ 9. Add -Z=compression-method option. zip.c (Ed)
+10. Add sd: to -sd status messages. zip.c (Ed)
+11. Instead of original argv[] use args[] for -sc show command line
+ to show final command line. zip.c (Ed)
+12. Change argv[] to args[] for logfile. zip.c (Ed)
+13. Put results of -sf show files in log file if open. zip.c (Ed)
+14. Add Johnny's bzip2 patch but not tested. win32/makefile, zip.c,
+ zip.h, zipup.c (Johnny)
+15. Minor tweeks to bzip2 to work with latest beta. zip.c, zipup.c (Ed)
+16. Add -sf- to list files that would be included only in log file
+ and not on stdout as list can be long. Only list totals on stdout.
+ zip.c (Ed)
+17. Create check_unzip_version(). Fix Unix check. Zip still creates
+ the temporary archive then does the check, and if it fails
+ the archive is deleted, even if the check fails because of the wrong
+ verion of UnZip. On Unix only 'unzip' the system version of UnZip
+ is checked, not './unzip' which would allow putting a local more
+ up to date version of UnZip in the current directory for the check.
+ There should be a way to override the system version of UnZip for
+ the -T test. zip.c (Ed)
+---------------------- July 12th 2006 version 3.0f14 ----------------------
+ 1. Change crypt version from 2.10 to 2.91 to match Zip 2.32 and avoid
+ confusion. crypt.h (Cosmin)
+ 2. Add abbrevmatch() to handle option values that can be abbreviated
+ like compression method. util.c, zip.h, zip.c (Ed)
+ 3. Change USE_BZIP2 to BZIP2_SUPPORT as USE_BZIP2 implies it replaces
+ deflation maybe. zip.c, zip.h, zipup.c (Ed)
+ 4. Update man page. man/zip.1, zip.txt (Ed)
+ 5. Add bzip2 to VMS. vms/build_zip.com, vms/bzlib.h, vms/cmdline.c,
+ vms/descrip.mms, vms/descrip_src.mms, vms/find_bzip2_lib.com,
+ vms/install_vms.txt, vms/zip_cli.cld (SMS)
+ 6. Remove zipfile parameter from bzfilecompress(). Add unsigned
+ cast for EOF in bzip2 code. Add bzip2 version information.
+ zipup.c, zip.c (SMS)
+ 7. Add bzip2 to Unix. unix/configure (SMS)
+ 8. Add and update bzip2 descriptions. INSTALL, README, WhatsNew,
+ bzip2/install.txt (SMS, Ed)
+ 9. Add vc6bz2 projects for compiling bzip2 code into zip (not the
+ best approach perhaps). win32/vc6/readmevc.txt,
+ win32/vc6bz2/readvcbz.txt, win32/vc6bz2/zip.dsp, win32/vc6bz2/zip.dsw,
+ win32/vc6bz2/zipcloak.dsp, win32/vc6bz2/zipnote.dsp,
+ win32/vc6bz2/zipsplit.dsp (Ed)
+10. Add support for VC++ 2005 by disabling deprecation. win32/osdep.h
+ (Cosmin)
+11. Update instructions for makefile. unix/Makefile (Ed)
+12. Update todo list. todo30.txt (Ed)
+13. Reduce #if 0 block to now allow extra data message. zipfile.c (Ed)
+14. Add note that readlocal() reads local headers. zipfile.c (Ed)
+15. Archive comment was not being read by new scanzipf_regew(). Added.
+ zipfile.c (Ed)
+16. Handle reading and writing OEM comments. zipfile.c (Ed)
+17. Update Zip64 data descriptor note. zipfile.c (Ed)
+18. Format filetypes() check. zipup.c (Ed)
+19. Update note to remember to force deflation for descriptors by
+ release. zipup.c (Ed)
+20. In compression code using libraries, enable dots for noisy also.
+ zipup.c (Ed)
+21. Update extended help to add more of the basic options and
+ compression method. zip.c (Ed)
+22. Add additional lines bz_opt_ver2 and bz_opt_ver3 to bzip2
+ version to give credit to bzip2. zip.c (Ed)
+23. Add descriptions to version information for USE_EF_UT_TIME,
+ NTSD_EAS, WILD_STOP_AT_DIR, WIN32_OEM, LARGE_FILE_SUPPORT,
+ ZIP64_SUPPORT, and UNICODE_SUPPORT similar to how UnZip does.
+ zip.c (Ed)
+24. Add note that crypt is modified in Zip 3. zip.c (Ed)
+25. Use abbrevmatch() and update warnings for compression
+ method selection. zip.c (Ed)
+26. Update config to handle either using IZ_BZIP2 to define
+ the location of the bzip2 files or the bzip2 directory.
+ unix/configure, zipup.c, zip.c (SMS, Ed)
+---------------------- July 14th 2006 version 3.0f15 ----------------------
+ 1. Change USE_BZIP2 to BZIP2_SUPPORT in VMS. vms/descrip_src.mms,
+ vms/build_zip.com (SMS)
+ 2. Add SYS$DISK:. vms/descrip.mms, vms/build_zip.com (SMS)
+ 3. Change vms/install.txt to [.vms]install.txt. bzip2/install.txt (SMS)
+ 4. Change VMS files to lower case. vms/mod_dep.com, vms/install_vms.txt,
+ vms/zip.opt, vms/hlp_lib_next.com, vms/notes.txt, vms/unixlib_gcc.h,
+ vms/unixio_gcc.h (SMS)
+ 5. Remove old VMS files. vms/descrip-old.mms (removed),
+ vms/link_zip.com (removed), vms/make_zip.com (removed),
+ vms/makefile.vms (removed) (SMS)
+---------------------- July 24th 2006 version 3.0f16 ----------------------
+ 1. Fix global dots so can set with dot size. deflate.c, fileio.c (Ed)
+ 2. Update License top line to refer only to license. License (Cosmin)
+ 3. Update License. License (Ed)
+ 4. Implement zero length UTF-8 path length as flag standard path is UTF-8
+ and should use that. This allows Zip to use the standard path as
+ UTF-8 when the local character set is UTF-8. zipfile.c (Ed)
+ 5. Update WhatsNew. WhatsNew (Ed)
+ 6. Change case of bzip2/install.txt. INSTALL (Ed)
+ 7. Change MANUAL.txt to ZIP.txt and update ftp site. README (Ed)
+ 8. Update announcement. zip30f.ann (Ed)
+ 9. Now also check if OS has bzip2 library and can use that.
+ unix/configure, zip.c (Mark Adler, Ed)
+10. Add fix from akt@m5.dion.ne.jp in Japan to recurse on doublebyte
+ characters without processing in recmatch(). This should not be needed
+ unless the rest of the code in there is broke for Japanese character
+ sets in some way. Need to test. util.c (Ed)
+11. Add note for bzip2. zip.c (Ed)
+12. Do not do seek wrap test if ftell() returns -1 as from a pipe. Add
+ output of last ftell() and current ftell() for zipfile too big seek
+ error. zipup.c (Ed)
+13. Add version to the options table. Remove the check to display version
+ before the command line is processed. Add to option -v a check to
+ display the version if that is the only argument. Can still enable
+ verbose with piping by using zip -v - - format. zip.c (Ed)
+14. Add abbrevmatch() for -UN option. zip.c (Ed)
+---------------------- August 7th 2006 version 3.0f17 ----------------------
+ 1. Change license modifications to retain intent of copyright holders, as
+ any major change in license conditions would require contacting all
+ copyright holders. LICENSE (Greg, Ed)
+ 2. Move debugging statement after zipstdout() where mesg is set to stderr.
+ Add mesg and fflush() to sd messages where needed so that messages go
+ to stderr when piping. zip.c (Ed)
+ 3. Update encryption comment. zipup.c (Ed)
+ 4. Do not use data descriptors for directories. zipup.c (Mark, Ed)
+ 5. Update Q & A to match license. README (Ed)
+ 6. Update WhatsNew. WHATSNEW (Ed)
+ 7. Add ifndef around version_info() for dll. zip.c (Ed)
+ 8. Add -TT (--unzip-path) to allow setting the unzip command to use with
+ -T to test the archive. zip.c (Ed)
+ 9. Add -DF (--difference-archive) which requires --out and turns off
+ copying unchanged entries to the new archive creating an archive with
+ just the changes and additions since the original archive was created.
+ zip.c, globals.c, zip.h (Ed)
+10. Update help. zip.c (Ed)
+---------------------- September 7th 2006 version 3.0f18 ----------------------
+ 1. Split -t and -tt options and remove limitation that only one can be
+ used to allow setting a date range. zip.c, WhatsNew (Ed)
+ 2. Minor changes in comments. zipfile.c (Ed)
+ 3. Add entries for format of Unicode Path and Unicode Comment extra fields.
+ proginfo/extrafld.txt (Ed)
+ 4. Change note at top of infozip.who, but needs to be updated with all new
+ contributors. proginfo/infozip.who (Ed)
+ 5. Note Zip 3 and UnZip 6 now support Zip64. proginfo/ziplimit.txt (Ed)
+ 6. Add note on Unicode. README (Ed)
+ 7. Update WHATSNEW. WHATSNEW (Ed)
+ 8. Update help. zip.c (Ed)
+ 9. Add {} support to -TT option, allowing insertion of temp archive path
+ into the command string to -TT similar to Unix find does. zip.c (Ed)
+10. Start changes for -F fix option. Add checks when reading input archive
+ and skip bad central directory entries and bad local entries. Currently
+ -F requires the central directory to be intact (except for bad CD entries
+ that will be skipped) and local entries and data to be where the
+ central directory say they are. This allows all recovered entries to
+ be complete with all central directory information. Calculate CRC of
+ input entry and compare to CRC from central directory. Allow skipping
+ split disks the user may not have. Store state of output archive
+ before each local entry and data are read, allowing seeking back and
+ restoring state to skip bad entries. fileio.c, global.c, zipfile.c,
+ zip.h (Ed)
+11. Started changes for fixfix. fileio.c (Ed)
+12. Update help on -t and -tt. zip.c (Ed)
+13. Add note on Unicode support, but may change if add handling of names
+ with characters not supported in current character set. README (Ed)
+14. Combined ToDo30.txt and ToDo but more to be done. TODO (Ed)
+15. Update ToDo list. ToDo30.txt (Ed)
+16. Add -F and -FF to help. zip.c (Ed)
+17. Run fix mode in copy mode, as it is copying from one archive to
+ another, and use those checks. zip.c (Ed)
+18. Add Try -F and Try -FF warnings in places. zipfile.c (Ed)
+19. Allow reading version 4.6 (bzip2) archives. zipfile.c (Ed)
+20. Add Unicode Path and Unicode Comment extra field descriptions.
+ proginfo/extrafld.txt (Ed)
+21. First attempt at updating the Who file. proginfo/infozip.who (Ed)
+22. Add note to top of ziplimit.txt. proginfo/ziplimit.txt (Ed)
+23. Add possible fix for paths returned by the Win32 directory scan with
+ '?' in the name. These are characters in the Unicode name stored on
+ disk but not represented in the multi-byte character set used by zip
+ for the scan. In this case, return the short name in 8.3 format so
+ directory scan can continue. Could put the Unicode name in the Unicode
+ extra field, but not done. Add warning when long name is replaced
+ by short name. Not fully tested. win32/win32zip.c, zip.h, zip.c,
+ fileio.c (Ed)
+24. If archive name and -sf are the only parameters, list archive contents.
+ zip.c (Ed)
+---------------------- September 8th 2006 version 3.0f19 ----------------------
+ 1. Fix error message. zipfile.c (SMS, Ed)
+ 2. Put crc32() in ifndef UTIL as only needed for fix. fileio.c (SMS, Ed)
+---------------------- November 3rd 2006 version 3.0f20 -----------------------
+ 1. Fix comment. vms/vmszip.c (SMS)
+ 2. Include oem_to_local_string() if UNICODE_SUPPORT. win32/win32.c,
+ zip.h (Ed)
+ 3. Modify procname_win32() to flag a path not supported by the local
+ character set so can get Unicode for it. Check Unicode names.
+ win32/win32zip.c (Ed)
+ 4. Add matching of escaped Unicode names to proc_archive_name() that
+ reads entries from an archive. Add sorted zlist zusort.
+ globals.c, fileio.c, zip.h, zipfile.c (Ed)
+ 5. Add support for non-local character set names and paths for WIN32,
+ getting and storing the UTF-8 path when needed. Use 8.3 name
+ when normal name has characters not supported in current local
+ character set. Note when short name used. zip.c, fileio.c (Ed)
+ 6. Add support for fix = 2 which reads local headers first to
+ bfcopy(). fileio.c, zip.h (Ed)
+ 7. Allow selection of .zip split in ask_for_split_read_path() when
+ reading a split archive that has no end records giving the total
+ split count. fileio.c (Ed)
+ 8. Add zoff_t casts to dot counts. fileio.c (Ed)
+ 9. Comment changes for Unicode. fileio.c (Ed)
+10. Call wide_to_local_string() separately in utf8_to_local_string()
+ to free up temp value. fileio.c (Ed)
+11. Support new AppNote bit 11 for forcing UTF-8, but needs finishing.
+ globals.c (Ed)
+12. Add to zlist struct zuname for the escaped version of the UTF-8
+ name in uname and add ouname for the display version of zuname.
+ zip.c, zip.h, zipfile.c (Ed)
+13. Add zipmessage_nl() that can output to the screen and to the log
+ file like zipmessage(), but can write lines without a newline.
+ zip.c, zip.h, zipcloak.c, zipnote.c, zipsplit.c (Ed)
+14. Update help for -FF and Unicode. zip.c (Ed)
+15. Change > to >= for byte message check to avoid -0 (negative zero).
+ zip.c (Ed)
+16. Add -su show unicode option which adds escaped unicode paths to
+ -sf. Also uses show_files = 3. zip.c (Ed)
+17. Update comments for -UN and -X. zip.c (Ed)
+18. Add support for new AppNote bit 11 that says standard path and
+ comment have UTF-8 when -UN=f is used. zip.c (Ed)
+19. Fix zipfile name message by replacing value with zipfile.
+ zip.c (Ed)
+20. Add new code for -FF, which processes archives by trying to read
+ the EOCDR to get split count, then starting with the local
+ entries. This option does not use the standard code but does
+ everything itself. Add scanzipf_fixnew(), which tries to read
+ the EOCDR, then the local entries, then the central directory.
+ zip.c, zipfile.c (Ed)
+21. Update note for ZIP64_CENTRAL_DIR_TAIL_SIZE. zipfile.c (Ed)
+22. Put read_Unicode_Path_entry() and read_Unicode_Path_local_entry()
+ into UNICODE_SUPPORT ifdef. zipfile.c (Ed)
+23. Add zuqcmp() and zubcmp() to support Unicode sorted list of
+ paths. zipfile.c (Ed)
+24. Update zsearch() to also search unicode paths. zipfile.c (Ed)
+25. Split out iname in read_Unicode_Path_entry() for debugging.
+ Should put it back. Update Unicode mismatch warning.
+ zipfile.c (Ed)
+26. Update Unicode in readlocal(). zipfile.c (Ed)
+27. Add more Unicode support to scanzipf_regnew(). zipfile.c (Ed)
+28. Add support for fix = 2 to zipcopy(). Add checks and warnings,
+ but allow scan to continue when can. Use local data to fill
+ in central directory fields in case no central directory entry
+ for local entry. zipfile.c (Ed)
+29. Add get_win32_utf8path() to get UTF-8 from Windows if can.
+ zipfile.c (Ed)
+---------------------- November 7th 2006 version 3.0f21 -----------------------
+ 1. Add crude data descriptor support to -FF in bfcopy() that should be
+ updated by release. fileio.c (Ed)
+ 2. Change %d to %s and use zip_fzofft() to format zoff_t byte count.
+ zipfile.c (SMS, Ed)
+ 3. Call local_to_oem_string() for only WIN32 in zipcopy(). zipfile.c
+ (SMS, Ed)
+---------------------- November 29th 2006 version 3.0f22 -----------------------
+ 1. Change ' to " in extended help. zip.c (Ed)
+ 2. Change -dv disk number display to indisk>outdisk. zip.c (Ed)
+ 3. Finish -FF fix option. Move detailed output to require -v. zip.c (Ed)
+ 4. Add note to help to use -v with -FF to see details. zip.c (Ed)
+ 5. Add -sU option to view only Unicode names when exist. zip.c (Ed)
+ 6. Change default dot size in verbose from every buffer to 10 MB. zip.c (Ed)
+ 7. Exit if --out and in path same as out path. zip.c (Ed)
+ 8. Remove verbose information when fixing archive. zip.c (Ed)
+ 9. Initialize in disk to 0, but still problem with disk number of first entry
+ for each disk lagging by 1. zip.c (Ed)
+10. Consistently use ZE error codes for exit from ask_for_split_read_path.
+ zipfile.c, zip.c (Ed)
+11. Seek back when fix finds bad entries. Also skip last entry of split
+ if next split is missing. Should check if entry completed. zip.c (Ed)
+12. Add messages to -sd for writing the central directory, replacing the old
+ zip file, and setting file type. zip.c (Ed)
+13. Don't set file type on stdout. zip.c (Ed)
+14. Increase errbuf from FNMAX + 81 to FNMAX + 4081. zip.h (Ed)
+15. Add skip_this_disk, des_good, des_crc, des_csize, and des_usize globals
+ for -FF and reading data descriptors. Change note on display_volume.
+ Add global skip_current_disk. zip.h, globals.c (Ed)
+16. BFWRITE_HEADER define now also does data descriptor. zip.h (Ed)
+17. Skip zipoddities() if fix. Maybe can later add back. zipfile.c (Ed)
+18. Update fix messages. zipfile.c (Ed)
+19. Allow user to end archive early using ZE_EOF. zipfile.c, fileio.c (Ed)
+20. Only show split numbers and offsets for -FF if verbose. zipfile.c (Ed)
+21. Handle spanning signature at top of split archive. zipfile.c (Ed)
+22. Only close in_file if open. zipfile.c (Ed)
+23. Add note if no .zip and only splits suggest use -FF. zipfile.c (Ed)
+24. In putlocal() and putcentral() only convert to OEM if z->vem == 20.
+ zipfile.c (Ed)
+25. Do not OEM convert archive comment as PKWare says this should
+ be ASCII. zipfile.c (Ed)
+26. Fix swap of siz and len and LOCSIZ and LOCLEN. zipfile.c (Ed)
+27. Call read_Unicode_Path_local_entry() before OEM conversion so Unicode
+ checksum checks iname before conversion. zipfile.c (Ed)
+28. Only check if local and central crc match if not stream entry.
+ zipfile.c (Ed)
+29. Keep data descriptors if fix == 2, but need to look at this.
+ zipfile.c (Ed)
+30. Fix bug adding up header bytes in n by adding 4 for signature.
+ zipfile.c (Ed)
+31. If fix == 2 use local crc for central, otherwise use central crc
+ for local. zipfile.c (Ed)
+32. In zipcopy(), check data descriptor and skip if not correct one.
+ zipfile.c (Ed)
+33. Add SH, LG, and LLG macros from zipfile.c to allow reading the data in
+ the data descriptor. fileio.c (Ed)
+34. In bfcopy(), read and check the data descriptor if n == -2. If
+ run out of bytes before find descriptor, return error. fileio.c (Ed)
+35. In ask_for_split_read_path(), increase buf to SPLIT_MAX_PATH + 100,
+ fix bug by adding "- 1", set split_dir = "" if current directory,
+ and update prompts to add skip and end choices. Add skip and end
+ choices. fileio.c (Ed)
+36. Increase buffer for fgets to SPLIT_MAXPATH. fileio.c (Ed)
+37. Update WhatsNew. WhatsNew (Ed)
+---------------------- December 10th 2006 version 3.0f23 -----------------------
+ 1. Handle additional ODS5 issues by upper casing many symbols and file names.
+ vms/build_zip.com, vms/collect_deps.com, vms/descrip.mms,
+ vms/descrip_mkdeps.mms, vms/descrip_src.mms, vms/find_bzip2_lib.com (SMS)
+ 2. Update VMS Find Help Library code. vms/hlp_lib_next.com (SMS)
+ 3. Instead of tempname use temp_name as parameter to avoid function
+ tempname(). zipsplit.c, zipnote.c, zipcloak.c, zip.c (Ed)
+ 4. If fixing archive with -FF and no EOCDR to get disk count, see if top of
+ archive has spanning signature or local header and guess if it is
+ single-disk archive, then ask user to confirm. zipfile.c (Ed)
+ 5. For Unix where NO_MKSTEMP is not defined, replace mktemp() with mkstemp()
+ that avoids a race condition. zip.c, zipcloak.c, zipnote.c, fileio.c (Ed)
+ 6. Eliminate mkstemp() warning by using mkstemp() instead of mktemp() for
+ Unix. Only for UNIX and if NO_MKSTEMP is not defined. Many OS do not
+ have mkstemp(). zipcloak.c, zipnote.c, zip.c, fileio.c (Ed)
+ 7. If UNICODE_SUPPORT and UNIX then try to switch to UTF-8 locale to allow
+ displaying of Unicode, otherwise just get escapes. This results in some
+ characters displaying as whitespace if needed fonts, such as East Asian,
+ are not installed. zip.c (Ed)
+ 8. If new global unicode_escape_all is set, then escape all non-ASCII
+ characters when converting Unicode file path. This allows viewing paths
+ as escapes on Unix that would otherwise be white space. If not set, any
+ characters that map to the current locale are returned as is. Can only
+ display if either supported as base by the OS or fonts installed. Set
+ using -UN=escape option. zip.c, fileio.c, zip.h, globals.c (Ed)
+ 9. Update extended help for Unicode. zip.c (Ed)
+10. All variables used by Win32 in global.c should now be initialized at
+ start so dll is initialized each call. zip.c (Ed)
+---------------------- January 1st 2007 version 3.0f24 -----------------------
+ 1. Fix a problem when building with (old, obsolete) IM attribute encoding
+ combined with bzip2 support. vms/descrip_src.mms (SMS)
+ 2. Update WHATSNEW. WhatsNew (Ed)
+ 3. Update README. ReadMe (Ed)
+ 4. Remove in_crc code. Too involved to implement but may look at later.
+ fileio.c, globals.c, zip.c (Ed)
+ 5. Use 0x50 and 0x4b for 'P' and 'K' in signatures to handle EBCDIC case.
+ zipfile.c, fileio.c (Ed)
+ 6. Implement new -FS file sync option that deletes entries missing on the
+ file system from an archive being updated. globals.c, zip.c (?, Ed)
+ 7. Update help. zip.h, zip.c (Ed)
+ 8. Include scanning files dots when update small but new file scan long.
+ zip.c (Ed)
+ 9. Ask if single-file archive when using -FF and can't tell. zipfile.c (Ed)
+10. Display message when entry would be truncated. zipfile.c (Ed)
+11. Check for VMS_IM_EXTRA. Update bzip2 support for VMS. Change
+ destination directory if large-file enabled. vms/build_zip.com,
+ vms/descrip_src.mms (SMS)
+12. Change parameters for VMS bzip2 search. vms/find_bzip2_lib.com (SMS)
+---------------------- January 12th 2007 version 3.0f25 -----------------------
+ 1. Incorporate faster crc32.c including the Rodney Brown changes (originally
+ implemented in the zlib project) from UnZip, which includes the
+ IZ_CRC_BE_OPTIMIZ and IZ_CRC_LE_OPTIMIZ optimizations when those symbols
+ are defined. These modifications include:
+ - enlarge unrolling of loops to do 16 bytes per turn
+ - use offsets to access each item
+ - add support for "unfolded tables" optimization variant
+ crc32.c (Christian)
+ 2. As the crc32.c module now includes crc table generation, remove crctab.c.
+ crctab.c (remove) (Christian)
+ 3. Update crc i386 assembler code from UnZip (details see above).
+ win32/crc_lcc.asm, win32/crc_i386.asm, win32/crc_i386.c, crc_i386.S
+ (Christian)
+ 4. Guard against redefinition of symbols @CodeSize and @DataSize in memory
+ model setup section to work around Open Watcom (version 1.6) wasm
+ assembler problem. msdos/crc_i86.asm (Christian)
+ 5. Change type of keys[] array for new crc, add IZ_CRC_BE_OPTIMIZ, and
+ use new crypt crc table. Use header buffer instead of buf for header.
+ crypt.c, crypt.h (Christian)
+ 6. Update version and remove crc table. crypt.h (Christian)
+ 7. Add crc32.h, change sprintf() format for disk number from d to lu as
+ can go over 16-bit, remove crc32u(). fileio.c (Christian)
+ 8. Update to use new crc. msdos/makefile.bor, msdos/makefile.dj1,
+ msdos/makefile.dj2, msdos/makefile.emx, msdos/makefile.msc,
+ msdos/makefile.tc, msdos/makefile.wat, unix/Makefile,
+ vms/build_zip.com, vms/descrip_deps.mms, vms/descrip_src.mms,
+ vms/osdep.h, win32/makefile.bor, win32/makefile.dj, win32/makefile.emx,
+ win32/makefile.gcc, win32/makefile.ibm, win32/makefile.lcc,
+ win32/makefile.w10, win32/makefile.w32, win32/makefile.wat,
+ win32/makenoas.w32, win32/vc6/zip.dsp,
+ win32/vc6/zipcloak.dsp, win32/vc6/zipnote.dsp, win32/vc6/zipsplit.dsp,
+ win32/vc6bz2/zip.dsp, win32/vc6bz2/zipcloak.dsp, win32/vc6bz2/zipnote.dsp,
+ win32/vc6bz2/zipsplit.dsp, windll/visualc/dll/zip32.dsp,
+ windll/visualc/dll/zip32.mak, windll/visualc/lib/zip32.dsp,
+ win32/visualc/lib/zip32.mak (Christian)
+ 9. Include crc32.h. Make variable uname local in proc_archive_name().
+ Remove unused num and new_base_path. Change %02d to %02l2 for
+ disk number in print format. Remove crc32u() as now use crc32().
+ Add parentheses around conditions in loops. Use 0 instead of NULL
+ for zwchar. fileio.c (Christian)
+10. Add z_uint4 defines from crypt.c to tailor.h. Move uch, ush, and ulg
+ typedefs before tailor.h include which needs them. tailor.h, zip.h (SMS)
+11. Include crc32.h. change add_name() to return not int but long
+ since number of command line arguments can exceed 16 bits. Cast
+ variable option to (int) for subtraction. Change 0x400 to 0x400L.
+ Add braces to show_files print block. zip.c (Christian)
+12. Add warning if use -F or -FF without --out. Change defined(NO_MKSTEMP)
+ to !defined(NO_MKSTEMP). zip.c (Ed)
+13. Define EC64LOC and EC64REC for size of Zip64 EOCD Locator and Zip64
+ EOCD Record. Add extern for crc_32_tab. Move crc32() to crc32.h.
+ zip.h (Christian)
+14. Add crc.h. zipcloak.c (Christian)
+15. Include crc32.h. Comment out scanzipf_reg() and scanzipf_fix() as
+ no longer used, which are left in for now for comparison. Cast
+ blocksize to extent for malloc(). Instead of 0x10000 malloc 0xFFFF for
+ extra field block so fits in 16 bits. Instead of crc32u() use crc32().
+ Only do lflg != flg check for fix == 2. Add comments to various #endif.
+ Indent comment. Comment out copy_sig() which is not used. Reduce size
+ of SCAN_BUFSIZE to EC64REC for MEMORY16. Use ENDHEAD for EOCDR size.
+ Change %u to %lu in print formats for disk count. Use EC64LOC for size
+ of Zip64 EOCD Locator. Use EC64REC for size of Zip64 EOCD Record.
+ Add streaming and was_zip64 to ZIP64_SUPPORT. Remove lflg != flg check
+ in zipcopy(). zipfile.c (Christian)
+16. Add note that z-flg & ~0xf check will fail if new bit 12 for UTF-8 paths
+ and comments is set. Update -FF warning. zipfile.c (Ed)
+17. Include crc32.h. Modify tempzn update. Fix comment. Set
+ z->lflg = z->flg after deflate as deflate may have set bits in z->flg
+ [Ed, Christian]. Include BZIP2_SUPPORT block in !UTIL block. zipup.c
+ (Christian)
+18. Changes to use crc32.c. acorn/gmakefile, acorn/makefile, amiga/lmkfile,
+ amiga/makefile.azt, amiga/smakefile, aosvs/make.cli, atari/makefile,
+ atheos/makefile, beos/makefile, cmsmvs/cczip.exec, cmsmvs/mvs.mki,
+ cmsmvs/zip.makefile, cmsmvs/zipmvsc.job, cmsmvs/zipvmc.exec,
+ human68k/makefile, human68k/makefile.gcc, novell/makefile, novell/zip.lnk,
+ os2/makefile.os2, qdos/makefile.qdos, qdos/makefile.qlzip, tandem/history,
+ tandem/macros, tandem/tandem.h, theos/makefile, tops20/make.mic,
+ unix/configure, unix/makefile, win32/makefile.a64 (Christian)
+19. Add note to use BZ_NO_STDIO. bzip2/install.txt (Ed)
+20. Remove crctab. cmsmvs/zipvmc.exec (Ed)
+21. Update comment. macos/source/pathname.c (Christian)
+22. Start of manual update. Zip.1 (Ed)
+23. Changes to use crc32.c. vms/descrip.mms, vms/descrip_deps.mms,
+ vms/descrip_mkdeps.mms, vms/descrip_src.mms, vms/vms.c (SMS)
+---------------------- January 17th 2007 version 3.0f26 -----------------------
+ 1. Add note for UnZip. crypt.c (Christian)
+ 2. Change current_disk and disk_number from int to ulg. Change num from int
+ to unsigned int. [Even though a 16-bit system likely won't see more than
+ 64k disks, it probably should be ulg - Ed] Remove unused mbsize. Change
+ match from long to int as the number of possible options should always fit
+ in that. fileio.c, globals.c (Christian)
+ 3. Use -Gt to force some data into separate data segments so all data fits.
+ msdos/makefile.msc (Christian)
+ 4. Move some copyright constants to far to save near space.
+ revision.h (Christian)
+ 5. Change u for character from int to unsigned int. util.c (Christian)
+ 6. Move include of crc32.h from vms/vms.c to vms/vms_pk.c. vms/vms.c,
+ vms/vms_pk.c (Christian)
+ 7. Update crci386_.o. win32/makefile.gcc (Christian)
+ 8. Use NOASM=1 to disable assembler and clear variables when do not.
+ win32/makefile.w32 (Christian)
+ 9. Remove unused totalslashes and returnslashes from get_win32_utf8path().
+ win32/win32zip.c (Christian)
+10. Remove local versions of tempzip and tempzf.
+ zip.c (Christian)
+11. Make options[] far. Change cd_start_disk from int to ulg. Cast -1 to
+ (ulg) for cd_start_disk. Put here = zftello() in DEBUG defines.
+ zip.h, zip.c (Christian)
+12. Change length of zipfile comment parameter from ush to extent. Change
+ disk numbers from int to ulg in close_split(), ask_for_split_read_path(),
+ ask_for_split_write_path(), get_in_split_path(), find_in_split_path(),
+ get_out_split_path(). Add Far to longopt and name strings in
+ option_struct. zip.h (Christian)
+13. Add far to options[]. zipcloak.c (Christian, Ed)
+14. Define write_string_to_mem() only for UNICODE_SUPPORT. Change ulg to
+ extent for append to mem memory offset and blocksize parameters. Make
+ at_signature() local. Cast usValue to char. Remove unused oname in
+ read_Unicode_Path_local_entry(). Remove local definitions of zip64_entry
+ as Zip is always processing one entry at a time and this is a global
+ flag for the current entry. Make find_next_signature() and
+ find_signature() local. Add ZCONST to signature parameter. Make
+ is_signature() and at_signature() local. Change m, result of fread(),
+ from int to extent. Reduce SCAN_BUFSIZE from 0x40000 to the size of the
+ largest header being read. As find_next_signature() is used to scan for
+ the next signature and that reads a byte at a time, the scan buf is only
+ used to read in the found headers. Since we skip the extra parts of the
+ Zip64 EOCDR, all headers are a fixed size. Remove unused variables from
+ scanzipf_fixnew(). Use ENDCOM for end comment offset. Instead of 64 KB
+ seek back 128 KB to find EOCDR. Use ENDOFF and ENDTOT for offsets in
+ EOCDR. Remove tabs. Merge versions of putend(). Update Amiga SFX.
+ Remove unused offset in zipcopy(). Make size local in zipcopy().
+ zipfile.c (Christian)
+15. Update putend() comment. zipfile.c (Ed)
+16. Add far to options[]. zipnote.c, zipsplit.c (Christian)
+17. Add NO_ASM versions of Win32 zipnote, zipsplit, and zipcloak projects.
+ Add crc32.h and crc32.c to zipsplit and zipnote projects.
+ win32/vc6/zipsplit.dsp, win32/vc6/zipnote.dsp, win32/vc6/zipcloak.dsp (Ed)
+18. Add NO_ASM versions of Win32 bzip2 zipnote, zipsplit, and Zipcloak
+ projects. Add crc32.h and crc32.c. win32/vc6bz2/zipsplit.dsp,
+ win32/vc6bz2/zipnote.dsp, win32/vc6bz2/zipcloak.dsp (Ed)
+19. Update Win32 dll and lib projects and make files.
+ windll/visualc/lib/zip32.dsp, windll/visualc/lib/zip32.mak,
+ windll/visualc/dll/zip32.dsp, windll/visualc/dll/zip32.mak (Ed)
+20. Remove space in front of #ifdef and other conditionals that slipped in.
+ zipfile.c, zipup.c (SMS)
+21. Updates for bzip2. vms/bzlib.h, vms/install_vms.txt (SMS)
+22. Updates. vms/notes.txt (SMS)
+23. Update copyrights. crc32.c, deflate.c, globals.c, revision.h, ziperr.h,
+ trees.c, win32/nt.c, win32/win32.c, win32/win32i64.c, win32/win32zip.h,
+ win32/zipup.h (Ed)
+24. Update WhatsNew. WHATSNEW (Ed)
+---------------------- February 4th 2007 version 3.0f27 -----------------------
+ 1. Fix array sizes and loop lengths in wide_to_escape_string(). fileio.c
+ (Johnny, Ed)
+ 2. Fix escape_string_to_wide() to handle hex strings, then comment out as
+ not used. zip.h, fileio.c (Ed)
+ 3. Use ZIPERRORS() macro instead of ziperrors[] array. zip.c, zipcloak.c,
+ zipnote.c, zipsplit.c (SMS)
+ 4. Add VMS-compatible "severity" values, add new ZE_SEV_PERR define to
+ set when perror() needs to be called, add ZIPERRORS() macro, change
+ PERR() to use ZE_SEV_PERR, change ziperrors[] to new structure array
+ to hold error strings, add new VMS facility names and severity codes
+ assigned by HP to ziperrors[] array, and add new official
+ VMS_MSG_IDENT. ziperr.h (SMS)
+ 5. Change ZE_SEV defines to ZE_S to save space and reformat ziperrors[].
+ ziperr.h (Ed)
+ 6. Update install.txt to include generic Unix case. bzip2/install.txt (Ed)
+ 7. Add creation of message file and add NOMSG message. vms/build_zip.com,
+ vms/descrip.mms, vms/install_vms.txt (SMS)
+ 8. Update notes.txt to add changes to program exit status values and changes
+ to messages. vms/notes.txt (SMS)
+ 9. Include crc32.h, include ssdef.h, instead of FAB_OR_NAM use FAB_OR_NAML,
+ add status code summary note detailing old versus new error codes, and if
+ CTL_FAC_IZ_ZIP is 0x7FFF and OLD_STATUS is defined use old VMS error codes.
+ vms/vms.c (SMS)
+10. Change FAB_OR_NAM to FAB_OR_NAML and remove NAME_DNA, NAME_DNS, NAME_FNA,
+ and NAME_FNS. vms/vms.h (SMS)
+11. Change FAB_OR_NAM to FAB_OR_NAML. vms/vms_im.c, vms/vms_pk.c,
+ vms/vmszip.c (SMS)
+12. Fix compile warning on VC 2005. win32/makefile.w32 (Johnny)
+13. Update readmevb.txt and readvb64.txt. windll/vb/readmevb.txt,
+ windll/vbz64/readvb64.txt (Ed)
+14. Change tch from int to ulg in utf8_from_ucs4_char(). Move comments to keep
+ line lengths to 80 characters. fileio.c (Christian)
+15. Update comment for total_cd_entries. global.c, zip.c, zip.h (Christian)
+16. Comment out unused Adler-16 code. util.c, zip.h (Christian)
+17. Add InterlockedExchangePointer() macro if not defined. Update Initialize()
+ to use macro. nt.c (Christian)
+18. Move zip64 eocd disk and offset variables next to input archive variables.
+ zip.c (Ed)
+19. Remove zipbegset from scanzipf_fixnew() as offsets are ignored when this
+ is fixing archives. Add comment to cd_total_entries. Remove local
+ cd_start_disk and cd_start_offset as these are already global. Use
+ ZIP_UWORD16_MAX when disk number exceeds this to flag use of Zip64.
+ zipfile.c (Christian)
+20. Some comment changes. zipfile.c (Ed)
+21. Fix indentation in places. zipsplit.c (Christian)
+22. Remove unused variable zfile. zipup.c (Christian)
+23. Update manual. zip.1, zip.txt, zipsplit.txt (Ed)
+---------------------- February 22nd 2007 version 3.0f28 ----------------------
+ 1. Update notes. vms/notes.txt (SMS)
+ 2. Add stream_lf.fdl to specify carriage control. vms/stream_lf.fdl (SMS)
+ 3. Update License to also refer to www.info-zip.org and to hopefully provide
+ an example of misrepresentative use. LICENSE (Ed)
+ 4. Update Readme. README (Ed)
+ 5. Update WhatsNew. WHATSNEW (Ed)
+ 6. Change output archive cd_start_disk and cd_start_offset to input archive
+ local in_cd_start_disk and in_cd_start_offset in scanzipf_fixnew() and
+ scanzipf_regnew() to avoid mixing in and out. zipfile.c (Ed)
+ 7. Update copyright. Remove crc32.h include. vms/vms.c (Christian)
+ 8. Changes for new crc32. Remove CRC32. Add CRCA_0 and CRCAUO. Add
+ compiling of crc_i386.S. win32/makefile.emx. (Christian)
+ 9. Add handlers for better RSXNT and Windows OEM conversions. Add detailed
+ comments on conversions. win32/osdef.h (Christian)
+10. Define CP_UTF8. win32/rsxntwin.h (Christian)
+11. Define WIN32_LEAN_AND_MEAN to reduce size of Windows includes.
+ win32/win32.c, win32/win32zip.c, zip.c (Christian)
+12. Use only standard FAT attributes if OEM. win32/win32zip.c (Christian)
+13. Add use of INTERN_TO_OEM() and related OEM changes. Add console comment.
+ zip.c (Christian)
+14. Change severity from char to int. Update macros. ziperror.h. (Christian)
+15. Update Visual Basic project to clarify some of the code.
+ windll/vbz64/vbzip.vbp, windll/vbz64/vbzipbas.bas,
+ windll/vbz64/vbzipfrm.frm (Ed)
+16. Update copyright. api.c (Ed)
+17. Update format for duplicate entry warning. fileio.c (Ed)
+18. Instead of ifdef __RSXNT__ use ifdef WIN32. Define WIN32_LEAN_AND_MEAN.
+ Use WIN32_CRT_OEM. Change OEM check from vem == 20 to vem & 0xff00 == 0
+ and instead of local_to_oem_string() use _INTERN_OEM(). Remove unused
+ first_CD in scanzipf_fixnew(). Instead of oem_to_local_string() use
+ Ext_ASCII_TO_Native(). Instead of local_to_oem_string() use
+ INTERN_TO_OEM(). zipfile.c (Christian)
+19. Replace escape from zipsplit man page with '. zipsplit.txt (Christian)
+20. Instead of using 20 every time, account for dosify when setting vem.
+ Update FAT comment. zipup.c (Christian)
+------------------------ March 3rd 2007 version 3.0f29 -------------------------
+ 1. Remove crctab.c. vms/build_zip.com (SMS)
+ 2. Add LFLAGS_ARCH. vms/descrip.mms (SMS)
+ 3. Remove redundant includes descrip.h, rms.h, and atrdef.h.
+ vms/vmsmunch.c (SMS)
+ 4. Remove includes descrip.h and rms.h. vms/vmszip.c (SMS)
+ 5. Only define NO_UNISTD_H if __VAX defined or __CRTL_VER is
+ less than 70301000, allowing support of the new symbolic
+ links in VMS. Also use unlink instead of delete if version
+ above 70000000. vms/osdep.h (SMS)
+ 6. Formatting changes. vms/notes.txt, vms/install_vms.txt (Christian)
+ 7. Remove spaces before tabs. win32/makefile.emx (Christian)
+ 8. Formatting change. win32/osdep.h (Christian)
+ 9. If -y on VMS open the link not the target file. vms/vms_im.c (SMS)
+10. If -y on VMS search for the link, not the target file. vms/vms_pk.c (SMS)
+11. Change default for Unicode path mismatch from error to warning, so
+ processing will continue. zip.c, globals.c (Ed)
+------------------------ March 12th 2007 version 3.0f30 ------------------------
+ 1. Add bzip2 support for the reduced no stdio bzip2 library for VMS and Unix.
+ Use libbz2_ns_.olb for VMS bzip2 library which is compiled from the VMS
+ version of bzip2 with the BZ_NO_STDIO flag set. This flag removes most
+ standard bzip2 stdio support and enables using a callback routine for
+ errors. zbz2err.c, unix/Makefile, vms/build_zip.com, vms/descrip.mms,
+ vms/descrip_deps.mms, vms/descrip_src.mms (SMS)
+ 2. Add zbz2err.c to Win32 vc6bz2 project for support of BZ_NO_STDIO for bzip2.
+ Modify zbz2err.c to handle different ports. zbz2err.c (Ed)
+ 3. Update license. zip.h (Ed)
+ 4. Update copyright. zip.c, zipfile.c, zipup.c, zbz2err.c, revision.h (Ed)
+ 5. Fix bug where directories got set to ver 4.6 in local headers instead of
+ ver 1.0 when using bzip2. zipfile.c, zipup.c (Ed)
+ 6. Minor updates to INSTALL. INSTALL (Ed)
+ 7. Minor updates to README. README (Ed)
+ 8. Add BZ_NO_STDIO to vc6bz2 projects. Error routine seems to work.
+ win32/vc6bz2 (Ed)
+ 9. Set bit FAB$M_BIO (.fab$v_bio) in the FAB when using sys$open() on a
+ symlink. vms/vms_im.c (SMS)
+10. Change sys$disk to SYS$DISK. vms/build_zip.com (SMS)
+11. Update extended help. zip.c (Ed)
+12. Update bzip2 install. bzip2/install.txt (Ed)
+------------------------ March 19th 2007 version 3.0f31 ------------------------
+ 1. Define bz2_olb as LIBBZ2_NS.OLB. Change LIBBZ2.OLB to bz2_olb. Use
+ ZZBZ2ERR.C error callback for bzip2. vms/build_zip.com (SMS)
+ 2. Change NO_SYMLINK to NO_SYMLINKS to be consistent with UnZip. tailor.h,
+ acorn/osdep.h, macos/osdep.h, tops20/osdep.h, vms/osdep.h (SMS)
+ 3. Minor note changes. Add section on Symbolic Links. vms/notes.txt (SMS)
+ 4. Update copyright. globals.c (Ed)
+ 5. Update License with official copy. LICENSE (Greg, Ed)
+ 6. Update Readme. README (Ed)
+ 7. Add support for NO_BZIP2_SUPPORT. tailor.h (Ed)
+ 8. Add common compiler flags to Install. INSTALL (Ed)
+ 9. Remove SPLIT_FILE define. zip.c (Ed)
+10. Minor updates to extended help. zip.c (Ed)
+11. Modify Makefile to also build bzip2 library if found. Split $MAKE
+ ("make -f unix/Makefile") into $MAKE and $MAKEF, leaving $MAKE as defined by
+ Make and defining $MAKEF to "-f unix/Makefile". Add clean_bzip2 target.
+ unix/Makefile (SMS)
+12. Modify configure to handle compiling bzip2. unix/configure (SMS)
+13. Remove linking bzip2 with utilities. Other changes. unix/Makefile (Ed)
+14. Change bzip2 wrong library errors to warnings. Put back OS bzip2 library
+ check. Only compile bzip2 if in bzip2 directory. unix/configure (Ed)
+15. More modifications to Makefile and configure to only allow compiling in
+ the bzip2 directory. unix/Makefile, unix/configure (Ed)
+------------------------ March 27th 2007 version 3.0f32 ------------------------
+ 1. Modify configure and Makefile to only allow compiling bzip2 in the Zip bzip2
+ source directory. unix/Makefile, unix/configure (SMS, Ed)
+ 2. Update bzip2 installation instructions. bzip2/install.txt (SMS, Ed)
+ 3. Remove need for BZIP2_USEBZIP2DIR define by using an appropiate include dir
+ specification (-I ../../bzip2) when needed. zip.c, win32/vc6bz2/zip.dsp,
+ unix/configure (SMS, Ed, Christian)
+ 4. Update VC6 readme. win32/readmeVC.txt (Christian, Ed)
+ 5. Add crc32.h to VC projects. Add assembler group to zipcloak, zipnote, and
+ zipsplit projects. Add BZ_NO_STDIO to all configurations with bzip2 so
+ reduced bzip2 code is used. win32/vc6/zip.dsp, win32/vc6/zipcloak.dsp,
+ win32/vc6/zipnote.dsp, win32/vc6/zipsplit.dsp (Christian)
+ 6. Update VC6bz2 readme. win32/readVCBZ.txt (Christian, Ed)
+ 7. Modify bzip2 VC6 workspace to use standard zipcloak, zipnote, and zipsplit
+ projects as they don't need bzip2. win32/vc6bz2/zip.dsw (Christian)
+ 8. Fix zlib flag problem by properly setting and clearing deflInit flag to
+ initialize and release resources. zipup.c (Bill Brinzer, Christian)
+ 9. Update copyright. crypt.h, api.c, tailor.h, fileio.c, ziperr.h,
+ zipsplit.c, zipnote.c, zipcloak.c, util.c (Ed)
+------------------------ April 25th 2007 version 3.0f33 ------------------------
+ 1. Fix -dd display_dots option for VMS. Fix adding value for -ds to command
+ line. Fix /NAMES = AS_IS for older header files. cmdline.c (SMS)
+ 2. Add Win32 wide scan support. In fileio.c add Win32 wide functions lastw(),
+ msnamew(), newnamew(), wchar_to_wide_string(), is_ascii_stringw(),
+ wchar_to_local_string(), and wchar_to_utf8_string(). In globals.c
+ add no_win32_wide that is true if the wide versions of calls like
+ GetFileAttributesW() do not work as on Win9x without the Unicode kit.
+ In tailor.h define zwstat for stats that use wchar_t strings and
+ defines SSTATW and LSSTATW. In util.c add isshexpw() and recmatchw()
+ and dosmatchw() for matching using wchar_t strings. In win32.c add
+ FSusesLocalTimeW(), IsFileSystemOldFATW(), GetFileModeW(), GetLongPathEAW(),
+ and zstat_zipwin32w(). In win32zip.c add zdirscanw structure,
+ GetDirAttribsW(), zDIRSCANW, readdw(), wild_recursew(), procname_win32w(),
+ OpenDirScanW(), GetNextDirEntryW(), CloseDirScanW(), procnamew(),
+ local_to_wchar_string(), wchar_to_utf8_string(), in wild() code to
+ check if W versions are supported and send zip down byte or wide path,
+ ex2inw(), in2exw(), and filetimew(). In zipup.h define zwopen to use
+ wide paths. In zipup.c if supported use filetimew() and zwopen().
+ In zip.h add namew, inamew, and znamew to zlist and flist. In zip.c
+ remove duplicate initialization of use_wide_to_mb_default, force_zip64,
+ zip64_entry, and zip64_archive. Use filetimew() if UNICODE_SUPPORT and
+ using wide paths for directory scan. Remove old 8.3 path Unicode fix as
+ now use wide paths and get all where the 8.3 kluge missed paths where
+ characters in path needed multiple code pages. Changes to bit 11 Unicode
+ but still not ready. fileio.c, globals.c, tailor.h, util.c, zipup.h,
+ win32/win32.c, win32/win32zip.c, win32/win32.h, zipup.c, zip.c (Ed)
+ 3. Update copyright. Don't define UNICODE_SUPPORT if already defined.
+ Define MATCHW and zstat_zipwin32w(). win32/osdep.h (Ed)
+------------------------ April 29th 2007 version 3.0f34 ------------------------
+ 1. Add temporary option -sC to test Unicode file creation enabled with
+ UNICODE_TEST define. zip.c, fileio.c (Ed)
+ 2. On Unix display control characters as ^X as UnZip. (SMS) fileio.c
+ 3. Update extended help. zip.c (Ed)
+ 4. Fix bugs in Unicode changes. zip.c, fileio.c (SMS, Ed)
+ 5. Add NAMES AS_IS support. Handle root dir [000000]. zip.h,
+ vms/install_vms.txt, vms/vmszip.c, vms/vmsmunch.c (SMS)
+ 6. Add global zipfile_exists to handle missing zipfile errors better. zip.h,
+ globals.c, zip.c (Ed)
+ 7. Add functions utf8_to_escape_string(), wide_to_escape_string(),
+ local_to_escape_string(), utf8_to_wchar_string(), and
+ rename wide_to_escape_string() to wide_char_to_escape_string(). fileio.c,
+ win32/win32zip.c, zip.h (Ed)
+ 9. Free f->inamew in fexpel(). Use zuname for matching. fileio.c (Ed)
+10. Fix memory bug by setting z->namew, z->inamew, and z->znamew to NULL.
+ Set f->namew, f->inamew, and f->znamew to NULL for new file in newname().
+ Free wide_string in local_to_utf8(). Other Unicode fixes. Add namew,
+ inamew, and znamew to freeup(). fileio.c, win32/win32zip.c, zip.h (Ed)
+11. Move wchar functions only used by Windows to win32zip.c. fileio.c,
+ zip.h (Ed)
+12. Fix spelling in manual. zip.1 (SMS, Ed)
+13. Add zuebcmp() for Unicode. zipfile.c
+14. Open files to read using wide name as input path. zipup.c (Ed)
+15. Update help. zip.c (Ed)
+16. Change -TT long option from --unzip-path to --unzip-command. zip.c (Ed)
+17. Update Manual to include section on Unicode, add -TT option, make some
+ changes to Unicode in other sections, update copyright at bottom, and
+ some small changes to wording and examples. man/zip.1, zip.txt (Ed)
+18. Put #ifdef WIN32 around WIN32 blocks. zipfile.c (Ed)
+------------------------- May 14th 2007 version 3.0f35 -------------------------
+ 1. Update VMS to include new options. vms/cmdline.c, vms/zip_cli.cld (SMS)
+ 2. Update VMS help. vms/vms_zip.rnh (SMS)
+ 3. Minor updates to VMS help. vms/vms_zip.rnh (Ed)
+ 4. Create global filter_match_case that defaults to 1 (case-sensitive). zip.c
+ zip.h, globals.c (Ed)
+ 5. Add option -fc to fold case for case-insensitive matching in filter().
+ Currently enabled only for WIN32. zip.c, win32/osdep.h (Ed)
+ 6. Change (action == DELETE || action == FRESHEN) to filter_match_case in
+ PROCNAME() define. I just couldn't figure out what was going on here and
+ why the case flag was controlled by this. zip.c (Ed)
+ 7. Update WhatsNew. WHATSNEW (Ed)
+------------------------- May 17th 2007 version 3.0f36 -------------------------
+ 1. Touch date on generated file. vms/ZIP_MSG.MSG (SMS, Ed)
+ 2. Update Betas readme to include Release Candidates. Betas_Readme.txt (Ed)
+ 3. Update Zip 3.0f announcement. zip30f.ann (Ed)
+ 4. Minor updates to VMS help. vms/cvthelp.tpu, vms/vms_zip.rnh (SMS)
+ 5. Major changes to VMS CLI help. vms/zip_cli.help (SMS, Ed)
+ 6. Update license. revision.h (Ed)
+------------------------- May 21st 2007 version 3.0f37 -------------------------
+ 1. Rename -fc (fold case) to -ic (ignore case) which may be more intuitive.
+ zip.c (Ed)
+ 2. VMS CLI updates for new options. vms/cmdline.c, vms/vms_zip.rnh,
+ vms/zip_cli.cld, vms/zip_cli.help (SMS)
+ 3. Updates to support Watcom C, mingw, djgppv2 and msc-16-bit, including
+ supporting wide stat and compare calls and work-around for problem with
+ "no symlink support" detection. tailor.h, util.c, zip.c, win32/osdep.h,
+ win32/win32.c, win32/win32/zipup.h (Christian)
+------------------------- May 29th 2007 version 3.0f38 -------------------------
+ 1. Update description. file_id.diz (Ed)
+ 2. Handle better when not splitting and run out of disk space. Also, for split
+ method 1 (automatically write all splits to same place) exit if run out of
+ space instead of filling available space with near empty splits. For split
+ method 2 require splits to be at least 64K bytes (the minimum split size).
+ fileio.c (Ed)
+ 3. Add line break in ziperr() if message line has been started. zip.c (Ed)
+ 4. In ziperr() don't close output handle y if same as current_local_file handle
+ and just closed that. zip.c (Ed)
+ 5. Change default definition of PROCNAME() to handle new filter_match_case flag
+ and restore backward compatibility. zip.c (Christian, Ed)
+ 6. Add note detailing definition of PROCNAME(). zip.c (Ed)
+ 7. Remove nonlocalpath parameter from procname_win32() and procname_win32w()
+ and variables nonlocal_path and nonlocal_name as this is not used now that
+ unicode is implemented in WIN32 using the wide calls.
+ 8. Enable ignore case option for VMS. zip.c (SMS)
+ 9. Update -v and other updates in manual. man/zip.1 (Christian, Ed)
+10. Updates for Watcom C and Win32 symlinks. win32/osdep.h (Christian)
+11. Fix historic problem with VAX seeking. zipfile.c (SMS)
+12. Add NAM_M_EXP_DEV. Add determination if device is in file specification.
+ If device name in file specification do ODS2 and ODS5 down-casing.
+ Define explicite_dev(). vms/vms.h, vms/vmszip.c (SMS)
+------------------------- June 4th 2007 version 3.0f39 -------------------------
+ 1. Update osdep.h to use new filter_match_case flag. vms/osdep.h (SMS)
+ 2. Fix unterminated string bug and trim extra allocated space in
+ local_to_display_string(). fileio.c (Ed)
+ 3. Updated extended help for -u and -ic options. zip.c (Ed)
+ 4. Update Manual. man/zip.1, zip.txt (Ed)
+------------------------- June 15th 2007 version 3.0f40 -------------------------
+ 1. Update Unicode Path and Unicode Comment descriptions based on suggestions
+ from WinZip. proginfo/extrafld.txt (Steve Gross, Ed)
+ 2. Update descriptions for Add, Update, and Freshen in the manual. man/zip.1
+ (Christian)
+ 3. Update default definition of PROCNAME() to use filter_case_match flag to
+ turn off case matching in filter(). zip.c (Christian)
+ 4. Update WhatsNew. WHATSNEW (Ed)
+ 5. Update announcement. zip30f.ann (Ed)
+ 6. Update manual. man/zip.1, zip.txt (Ed)
+------------------------- July 7th 2007 version 3.0f41 -------------------------
+ 1. Use File Name as Unicode path if UTF-8 flag is set in header. zip.c,
+ globals.c, zipfile.c, zip.h (Ed)
+ 2. Update ToDo. TODO (Ed)
+ 3. Update WhatsNew. WHATSNEW (Ed)
+ 4. Update ReadMe. README (Ed)
+ 5. Fix problems with incompatible stat types on Win32. fileio.c, tailor.h,
+ zip.h, win32/win32.c, win32/win32zip.c, win32/osdep.h (Ed)
+ 6. Define NO_STREAMING_STORE to turn off storing while streaming.
+ INSTALL, zipup.c (Ed)
+ 7. Define UNICODE_ALLOW_FORCE to enable -UN=force option which is now
+ disabled and would need work. globals.c, zip.h (Ed)
+ 8. Add global using_utf8 to flag when OS current character set is UTF-8.
+ If an existing entry has the UTF-8 flag set the flag is kept. If a new
+ entry needs Unicode and on a UTF-8 system assume the strings are UTF-8
+ and set the UTF-8 flag. globals.c, zip.h (Ed)
+ 9. Update Unicode extra field descriptions. proginfo/extrafld.txt (Ed)
+10. Add include directory so can find bzip2 header file when using bzip2
+ directory. unix/configure (Ed)
+11. Fix wide character wild(), wild_recursew() and OpenDirScanW() for Win32 so
+ work like the regular versions. win32/win32zip.c (Ed)
+12. Update Unicode in manual. Update -W description in manual zip.1
+13. Flush logfile writing. zip.c (Ed)
+14. Update extended help for -UN option. Update help for Update to note it
+ updates files where the OS has a later date. Chance -UN=Exit to -UN=Quit
+ so can abbreviate to first letter. zip.c (Ed)
+15. Fix a bug in readzipfile() when zip used in pipe. Other pipe fixes. zip.c,
+ zipfile.c (Ed)
+------------------------ August 10th 2007 version 3.0f42 -----------------------
+ 1. Update error message for -DF. zip.c (Ed)
+ 2. Add bzipped message to write to log file. zipup.c (Ed)
+ 3. Update bzip2 install instructions. bzip2/install.txt (Ed)
+ 4. Move local.h include to tailor.h to fix compiler multiple define. tailor.h,
+ zip.c (SMS)
+ 5. Add additional C compiler checks for GNU and HP. unix/configure (SMS)
+ 6. Fix to build libbz2.a. unix/Makefile (SMS)
+ 7. Update copyright. acorn/osdep.h, macos/osdep.h, tops20/osdep.h,
+ vms/vmszip.c, vms/vmsmunch.c, vms/vms_pk.c, vms/vms_im.c, vms/vms.h,
+ vms/vms.c, vms/osdep.h, win32/rsxntwin.h, win32/osdep.h, win32/nt.c (Ed)
+ 8. Change zfeeko(file, 0, SEEK_SET) to rewind(file) in ffile_size() so
+ EOF is always reset. This was creating problems in WIN32 when
+ NO_ZIP64_SUPPORT was set but LARGE_FILE_SUPPORT was set. zipfile.c (Ed)
+ 9. Update compile -v descriptions for LARGE_FILE_SUPPORT and ZIP64_SUPPORT to
+ be more specific as to what each does. zip.c (Ed)
+10. Fix bug that added the local header size to the next entry compressed size
+ giving a wrong compressed size error if splitting and the split occurs when
+ writing a local header. fileio.c (Ed)
+11. Remove UNICODE_TEST define from VC 6 projects. win32/vc6/zip.dsp,
+ win32/vc6/zipcloak.dsp, win32/vc6/zipnote.dsp, win32/vc6/zipsplit.dsp (Ed)
+12. Update extended help. zip.c (Ed)
+13. Only output -FF central directory messages in verbose mode. zipfile.c (Ed)
+14. Add note about possible bug when copying entries from a split archive.
+ WHATSNEW (Ed)
+------------------------ August 11th 2007 version 3.0f43 -----------------------
+ 1. Display locale inside check to avoid NULL locale. zip.c (SMS, Ed)
+ 2. Add include wchar.h to tailor.h. tailor.h (SMS)
+------------------------ August 21st 2007 version 3.0f44 -----------------------
+ 1. Remove verbose messages when setting locale as verbose flag is not set yet.
+ zip.c (SMS, Ed)
+ 2. Change reading splits message "abort archive" to "abort archive - quit" and
+ change selection letter from a to q so q quits consistently. For quit,
+ don't confirm as more annoying than helpful. fileio.c (Ed)
+ 3. In bfwrite() handle case where a split ends at the end of one entry and
+ trying to write the next local header forces opening next split. This
+ caused copying entries from one archive to another to fail if this came up.
+ Also handle case where a new split is needed while writing central directory
+ entries. Now close last split and update pointers to point to the new
+ split. fileio.c (Ed)
+ 4. Update use of mesg_line_started and add new logfile_line_started to account
+ for line ends in logfile. fflush() output. zip.c, zip.h, globals.c (Ed)
+ 5. Move setting split size if input archive is split and split_size not set
+ to after archive is read. zipfile.c, zip.c (Ed)
+ 6. Update Manual to describe Unicode as implemented and note that old splits
+ are not automatically excluded. man/zip.1, zip.txt (Ed)
+ 7. Update WhatsNew to remove note that creating and copying split archives
+ is broke as it seems fully working now. WHATSNEW (Ed)
+ 8. Update announcement. zip30f.ann (Ed)
+------------------------ August 31st 2007 version 3.0f45 -----------------------
+ 1. Unicode fix for VMS. tailor.h (SMS)
+ 2. Add member current to zlist structure to flag when an archive entry is
+ current with the matching OS file using file time and size. This is used by
+ File Sync to copy current entries from archive. zip.h, zip.c (Ed)
+ 3. Comment out zip info verbose extra data message as this message does not
+ seem to add much. zipfile.c (Ed)
+ 4. Add local and central directory Version Needed To Extract to mismatch
+ warning. Update warning text. zipfile.c (Ed)
+ 5. Add function BlankRunningStats() to output blanks for the running stats
+ part of the line to use when displaying stats for entries not on the mark
+ list so all output lines up. zip.c
+ 6. Add -FS to extended help as new mode. zip.c (Ed)
+ 7. Update description of -FF to remove Assume Worst. zip.c (Ed)
+ 8. Add all_current flag that is set if all entries in archive are current and
+ skip updating archive if -FS and all entries are current. zip.c (Ed)
+ 9. Change argv[] to args[] for "try: zip" error message as message depends on
+ new argument order in args where options are now at beginning. zip.c (Ed)
+10. For File Sync, copy entries to new archive if file time and size are the
+ same. If verbose, output ok when copying current entries, otherwise no
+ message when current_entry. Set all_current to 0 if an entry not marked or
+ a file not on OS as need to avoid the All Current message in these cases to
+ catch only deletions. zip.c (Ed)
+11. Initialize variables excluding zipstate and setjmp() if USE_ZIPMAIN defined
+ to fix bug when recall zipmain(). zip.c (Ed)
+12. Update Manual. zip.1, zip.txt (Ed)
+13. Update WhatsNew. WHATSNEW (Ed)
+14. Update announcement. zip30f.ann (Ed)
+----------------------- September 5th 2007 version 3.0f46 ----------------------
+ 1. Move write of local header after when GPB11 UTF-8 bit set in putlocal().
+ zipfile.c (Ed)
+ 2. Change to uppercase for compatibility. vms/install_vms.txt (SMS)
+ 3. Set cenbeg and bytes_this_split to fix grow. Check if grow split archive.
+ zipfile.c, zip.c (Ed)
+----------------------- September 14th 2007 version 3.0f47 --------------------
+ 1. Include address for new Info-ZIP forum. Add note on 16-bit OS support.
+ Add note about text file line ends. README (Ed)
+ 2. Update WhatsNew to include latest on Unicode. Add section on plans for
+ Zip 3.1. WHATSNEW (Ed)
+ 3. Minor change in note for Unicode in extended help. zip.c (Ed)
+ 4. Modify definitions of Unicode extra fields based on discussions with PKWare
+ and WinZip. proginfo/extrafld.txt (Ed)
+ 5. Add note on UTF-8 flag. INSTALL (Ed)
+ 6. Minor updates to ToDo list. Needs more work. TODO (Ed)
+ 7. Update announcement. zip30f.ann (Ed)
+ 8. Change definition of IZ_OUR_BZIP2_DIR to be compatible with Configure and
+ to work with HP-UX. unix/Makefile (SMS)
+------------------------ September 24th 2007 version 3.0f ---------------------
+ 1. Update extended help Unicode description. zip.c (Ed)
+ 2. Update Readme. README (Ed)
+ 3. Fix case of define identifying IA64. vms/vms.c (SMS)
+ 4. Update announcement date. zip30f.ann (Ed)
+ 5. Update Unicode extra field definitions based on changes proposed for
+ AppNote. extrafld.txt (Ed)
+------------------------ October 17th 2007 version 3.0g01 ---------------------
+ 1. Can get stuck on open Unix FIFO so default to skip and add option -FI to
+ enable reading FIFO. Add global allow_fifo. zip.c, zip.h, globals.c
+ (Willus 0, Ed)
+ 2. As problems with MinGW with wide-character paths, disable wide-character
+ Unicode support. zip.c, unix/unix.c (Willus 0, Ed)
+ 3. Update manual installs to include zipcloak.1, zipnote.1, and zipsplit.1
+ pages. unix/Makefile (Ed)
+ 4. Update Solaris packages. unix/Packaging/pkginfo.in,
+ unix/Packaging/postinstall, unix/Packaging/preinstall.in,
+ unix/Packaging/prototype (SMS)
+------------------------ October 30th 2007 version 3.0g02 ---------------------
+ 1. Fix bug in get_in_split_path() where look for .zip split when attempting
+ to open archives without a .zip extension, even when a single file archive
+ like jar file. fileio.c (Gabriele (balducci@units.it), Ed)
+ 2. Fix bug where temp file got created in current working directory on Unix
+ by giving entire archive path to mkstemp() as template. fileio.c, zip.c
+ (Willus, Ed)
+ 3. Use 64-bit output functions for bits_sent. trees.c (SMS)
+ 4. Add -FF to fixfix -sd messages to make different from identical main
+ messages. zip.c (SMS, Ed)
+ 5. If quiet do not ask for splits and all splits must be in same location.
+ zipfile.c (Ed)
+ 6. Clean up making zip manuals. unix/Makefile (Ed, SMS)
+ 7. Add clean_exe to make. unix/Makefile (SMS)
+ 8. Update to VMS Notes, including adding details on symlinks, -V, and UTC
+ dates times. vms/notes.txt (SMS)
+ 9. Fix bug in wild() when calling wile_recursew() where qw should be
+ pointing inside pw. win32/win32zip.c (Willus, Ed)
+10. Fix bug where is_ascii_string() fails when passed a NULL string. This
+ may fix problem where the CentOS mbstowcs() function is returning -1 when
+ trying to convert a file name with a bad character (0xe6), causing
+ local_to_wide_string() and then local_to_utf8_string() to return NULL, so
+ f->uname gets NULL and so is_ascii_string() fails with SIGSEGV. fileio.c
+ (Willus, Ed)
+------------------------ October 31st 2007 version 3.0g03 ---------------------
+ 1. Add handling of -b temp directory when opening splits in bfwrite() using
+ mkstemp(). fileio.c (SMS, Ed)
+------------------------ November 3rd 2007 version 3.0g04 ---------------------
+ 1. Move show_files to global so can avoid split warning for -sf. zip.c,
+ globals.c, zip.h, zipfile.c (Ed)
+ 2. Account for -b tempath when opening temp file. zip.c, zipnote.c,
+ zipcloak.c (SMS, Ed)
+------------------------ November 4th 2007 version 3.0g05 ---------------------
+ 1. Minor fixes to fdopen calls. zipcloak.c, zipnote.c (SMS, Ed)
+------------------------ November 4th 2007 version 3.0g06 ---------------------
+ 1. Add negation to -db, -dc, -dd, -dg, -du, -dv display options. zip.c (Ed)
+ 2. Put back UNICODE_SUPPORT no_win32_wide code left out in previous fix.
+ win32/win32zip.c (Willus, Ed)
+------------------------ November 21st 2007 version 3.0g07 ---------------------
+ 1. Fix bug preventing newline in some cases in zipmessage(). zip.c (Ed)
+ 2. Update Unicode help. zip.c (Ed)
+ 3. Update -sd messages. zip.c (Ed)
+ 4. Add filetimew() for Unicode case. zip.c (Ed)
+ 5. Add ClearArchiveBitW() for Win32 wide. zip.c, zip.h, win32/win32.c (Ed)
+ 6. Only ask for .zip split if path ends in .znn or .znnn where n 0 to 9. This
+ allows -FF to work on .exe sfx files without adding .zip. zipfile.c (Ed)
+ 7. Fix bug where only backed up 20 bytes to find Z64 EOCD Locator. Now back
+ up 24 bytes to include size of Z64 EOCD Locator signature. This prevented
+ reading and updating archives greater than 4 GB. zipfile.c (Ed)
+ 8. If -FF on Win32 initialize wide strings namew, inamew, and znamew to NULL.
+ zipfile.c (Ed)
+ 9. Add #include <wctype.h> to support towupper(). tailor.h (SMS)
+------------------------ December 4th 2007 version 3.0g08 ---------------------
+ 1. Update dot_size comment. globals.c (Ed)
+ 2. Update Compression in extended help. zip.c (Ed)
+ 3. Add extended help on self extractor -A and -J. zip.c (Ed)
+ 4. Update VMS SYMLINK version information. zip.c (SMS)
+ 5. Remove not final from Unicode version information as final now. zip.c (Ed)
+ 6. Remove apparently not needed WINDLL variable retcode. zip.c (Ed)
+ 7. Fix -A to calculate sfx offset and adjust offsets as it should. zip.c (Ed)
+ 8. Split -F and -FF used with -A warning to separate warnings. zip.c (Ed)
+ 9. Add adjusting to can't to that to split archive error. zip.c (Ed)
+10. Fix bug for -A that tries to open split by asking for disk 0 instead of
+ disk 1. Add adjust_offset and cd_total_size variables. Calculate
+ sfx offset by determining offset of start of central directory. Archives
+ larger than 4 GB are not supported as sfx archives but these don't seem
+ to work anyway. Add adjust_offset to Zip64 EOCDR offset and central
+ directory offsets. zip.c, zipfile.c (Ed)
+11. Comment out here debug variable in find_next_signature(). zipfile.c (Ed)
+12. Change %2x to %02x as format for parts of a signature in error messages.
+ zipfile.c (SMS)
+13. Add warning adjusting split archives not yet supported. zipfile.c (Ed)
+14. Add period to central directory comment. zipfile.c (Ed)
+15. Update readme for vb Zip64 project. windll/vbz64/readvb64.txt (Ed)
+16. Update comments of VB for Zip64 example. Add SplitSize to VB Zip64
+ example. windll/vbz64/vbzipbas.bas, windll/vbz64/vbzipfrm.frm (Ed)
+17. Add SourceForge to comment noting where can get the source code.
+ windll/vbz64/vbzipfrm.frm (Ed)
+18. Update WhatsNew. WHATSNEW (Ed)
+------------------------ December 12th 2007 version 3.0g09 --------------------
+ 1. A few minor changes to extended help. zip.c (Ed)
+ 2. Uppercase beginning of most -sd messages. zip.c (Ed)
+ 3. Add spaces between options in some error messages. zip.c (Ed)
+ 4. Update comments in scanzipf_regnew(). zipfile.c (Ed)
+ 5. Update scanzipf_regnew() to figure out sfx offset. (Ed)
+ 6. Uppercase VMS RUNOFF file as apparently needed. VMS_ZIP.RNH (SMS)
+ 7. Add comments to zipmessage(). zip.c (Ed)
+ 8. Update extended help and option descriptions. zip.c (Ed)
+------------------------ December 20th 2007 version 3.0g10 --------------------
+ 1. Fix -F to include -A adjustment check. zipfile.c (Ed)
+ 2. Change -FF message when find EOCDR. zipfile.c (Ed)
+ 3. For -FF, reset first CD entry flag in_central_directory when a local entry
+ is found after CD entries so that another CD entry forces sorting of all
+ local entries to that point. This allows files with multiple archives in
+ them to be processed. zipfile.c (Ed)
+ 4. Add message when a local entry is found after a central directory.
+ zipfile.c (Ed)
+ 5. Remove word offset from disk offset location messages. zipfile.c (Ed)
+ 6. Make Adjust offset message more descriptive. zipfile.c (SMS, Ed)
+ 7. In scanzipf_regnew(), if adjustment to offsets, add it to
+ in_cd_start_offset. zipfile.c (Ed)
+ 8. Allocate cextra only if localz->ext not 0 in zipcopy(). zipfile.c (Ed)
+------------------------ December 28th 2007 version 3.0g11 --------------------
+ 1. Include definitions of zip64_eocdr_start and z64eocdl_offset in
+ ZIP64_SUPPORT ifdef block. Add comments for End Of CD Record (EOCDR).
+ Update comments for adjust offset detection. zipfile.c (Ed)
+ 2. Change ((uzoff_t)1 << 32) to 0xFFFFFFFF. zipfile.c (SMS, Ed)
+ 3. Leave off local header detection as not useful when searching for start
+ of central directory to get adjust offset. Looks like all expected cases
+ are now covered as long as archive is intact. zipfile.c (Ed)
+ 4. Update some warning messages. Simplify adjust offset information message.
+ zipfile.c (Ed)
+ 5. Add braces to unicode_mismatch if block. zipfile.c (Christian)
+ 6. Add (void *) cast in InterlockedExchangePointer() mutex calls to fix
+ compile warnings in MinGW (GCC 3.4.4). win32/nt.c (Christian)
+ 7. Remove unused nonlocalpath variable. win32/win32zip.c (Christian)
+ 8. Update betas readme file. betas_readme.txt (Ed)
+ 9. Partial update to Who list of contributors. proginfo/infozip.who (Ed)
+10. Update ReadMe. Create Announcement. README, zip30g.ann (Ed)
+11. Update WhatsNew. WHATSNEW (Ed)
+------------------------ January 7th 2008 version 3.0g12 --------------------
+ 1. Convert Scanning files message to use standard zipmessage_nl() so line
+ ends are generated when needed. fileio.c (Ed)
+ 2. Add line ends in DisplayRunningStats() if a display line has been
+ started. zip.c (Ed)
+ 3. For the command line listed at the top of the log file, add double
+ quotes around any arguments that have spaces in them.
+ zip.c (Ed)
+ 4. Instead of stdout use standard mesg output stream for show files.
+ Output new line for show files for display and log file if there was
+ output on the current line. zip.c (Ed)
+ 5. Comment out new line output code after zipup() and replace with
+ call to zipmessage_nl("", 1) to output new line if needed.
+ zip.c (Ed)
+ 6. In GetFileMode() and GetFileModeW() when get attributes fails
+ instead of fprintf(mesg, ...) use zipwarn() so error goes in
+ log file and new lines are displayed when needed. win32/win32.c (Ed)
+ 7. In GetSD(), change cbytes from long to ulg. Check cbytes (the
+ compressed size of the security descriptor) and issue warning if
+ the compressed security descriptor is greater than 0x7FFF (32k)
+ as the entire header this extra field is in needs to fit in the
+ 64k header. Should be a check on the running size of the header
+ so the actual space remaining is tracked. Maybe in Zip 3.1. If
+ cbytes OK cast to ush and store. win32/win32zip.c (Ed)
+ 8. Use zipmessage_nl() for bytes security message so new lines are
+ handled and message goes in log file. win32/win32zip.c (Ed)
+ 9. Add new option -RE to enable [list] (regex) matching in DOS and
+ WIN32 but disable [list] matching otherwise. Default behavior
+ is restored if ALLOW_REGEX is defined. globals.c, util.c,
+ zip.h, zip.c (Ed)
+------------------------ January 20th 2008 version 3.0g13 --------------------
+ 1. Update copyrights to 2008. zip.c, zipcloak.c, zipfile.c, zipnote.c,
+ zipsplit.c, zipup.c, README (Ed)
+ 2. Update Who. proginfo/infozip.who (Ed)
+------------------------ January 30th 2008 version 3.0g14 --------------------
+ 1. Update copyrights. fileio.c, globals.c, revision.h, util.c, zip.h,
+ win32/win32.c, win32/win32zip.c (Ed)
+ 2. Updates. README, proginfo/infozip.who (Ed)
+ 3. Update announcement and WhatsNew. zip30g.ann, WHATSNEW (Ed)
+ 4. Add ALLOW_REGEX to INSTALL define list. INSTALL (Ed)
+ 5. Change -sd message. zip.c (Ed)
+ 6. For bzip2 check for binary and set binary/text flag. Handle -l and -ll
+ line end conversions for bzip2. zipup.c (Ed)
+------------------------ February 3rd 2008 version 3.0g --------------------
+ 1. Change && to || to fix logic bug in show files. zip.c (Johnny)
+ 2. Add CLEAN and CLEAN_ALL VMS targets. vms/descrip_mkdeps.mms (SMS)
+----------------------- February 22nd 2008 version 3.0h01 --------------------
+ 1. Update some echo statements to use CFLAGS_OPT. Add GNUC check.
+ unix/configure (SMS)
+ 2. Only store UID and GID if 16 bit. unix/unix.c (Ed)
+----------------------- March 21st 2008 version 3.0h02 --------------------
+ 1. Change long Unicode escapes from 8 characters to 6 characters based on
+ change in UnZip 6.0. fileio.c (Ed)
+ 2. Put zuebcmp() declaration in #if 0 block as definition already is. This
+ function would be used to allow Unicode escapes on the command line
+ without using the -UN=escape option, but the utility of this is still
+ being determined. zipfile.c (SMS, Ed)
+ 3. Remove declaration for unused bz_deflate_init(). zipup.c (SMS, Ed)
+ 4. Add release announcement file, anticipating the long-awaited release.
+ zip30.ann (Ed)
+ 5. Update WhatsNew. WHATSNEW (Ed)
+----------------------- March 24th 2008 version 3.0h03 --------------------
+ 1. Update Unix configure script to better test for modern HP-UX compiler.
+ unix/configure (SMS)
+ 2. Updated Beta Readme. betas_readme.txt (Ed)
+ 3. Update Install. INSTALL (Ed)
+ 4. Update ReadMe. README (Ed)
+ 5. Small change to main help screen. zip.c (Ed)
+ 6. Small update to top of ToDo list. Actual updating of items still
+ needs to be done. TODO (Ed)
+----------------------- April 2nd 2008 version 3.0h04 --------------------
+ 1. Update copyright. crc32.h (Christian)
+ 2. Remove zip.h include. crc32.h (Christian)
+ 3. Add local prototypes for Unicode functions. Add cast for split size
+ check. Make many Unicode functions local. #if 0 out currently unused
+ utf8_chars(). Fix memory leak in wide_to_local_string() by adding
+ free() for buffer on error return. Fix memory leak in copy_args() on
+ error return by adding free-args(). Add ZCONST to arg in
+ insert_arg(). Shorten some lines to less than 80 characters. Add
+ free() to get_longopt() to fix memory leak. fileio.c (Christian)
+ 4. Create Win32 versions of wide_to_local_string() and
+ local_to_wide_string() so can use Win32 conversion functions.
+ fileio.c, win32/win32.c (Christian)
+ 5. Update comments for get_option(). fileio.c (Ed)
+ 6. Update encryption code readme. README.cr (Ed)
+ 7. Add prototype for recmatchw(). util.c (Christian)
+ 8. Change count_args() from static to local. util.c (Christian)
+ 9. Change ifdefs for includes for prototypes for version_info(),
+ zipstdout(), and check_zipfile() for WINDLL and MACOS and add
+ check_unzip_version(). zip.c (Christian)
+10. Change ifndef NO_SYMLINKS to ifdef S_IFLNK for determining compiler
+ information. zip.c (Christian)
+11. Change UTF-8 locale from en_GB.UTF-8 to .UTF-8. zip.c (Christian)
+12. Change cast of -1 for dot_size from uzoff_t to zoff_t.
+ zip.c (Christian)
+13. Change prototype for set_filetype to include parameter char *.
+ Change prototype of has_win32_wide to include parameter void.
+ zip.h (Christian)
+14. Add prototypes for find_next_signature(), find_signature(),
+ and is_signature(). Change duplicate prototype scanzipf_regnew()
+ to missing prototype scanzipf_fixnew(). Change comment for Adler-16
+ checksum to CRC-32 checksum as that is being used at that point in
+ the code. Move multiple uname assignments to common assignment.
+ Add inameLocal for WIN32_OEM and use define for inameLocal if not
+ to save memory allocation when not not using WIN32_OEM. Also
+ change _INTERN_OEM(str1) to INTERN_TO_OEM(src, dst) for OEM
+ conversion. Format comment for vem to fit in 80 character lines.
+ zipfile.c (Christian)
+15. Change variable a from buffer to a pointer and add abf as the
+ buffer for zgetline() to handle NULL case. zipnote.c (Christian)
+16. Change comments to zipentry comments and zipfile comment in
+ messages. zipnote.c (Ed)
+17. Use uidgid_16bit as flag variable instead of uid_size. Modify
+ size check that prevents saving Unix UIDs and GIDs in the old
+ Unix extra field if they are not 16 bits. Change memory
+ allocation based on uidgid_16bit. Delete unused code for memory
+ copy for extra field. unix/unix.c (Christian, Ed)
+18. Change compiler flag from -zp8 to -Zp8 for LCC Win32.
+ win32/makefile.lcc (Christian)
+19. Add ifndef debug. Add bzip2 support. Add additional compiler
+ flags. win32/makenoas.w32 (Christian)
+----------------------- April 10th 2008 version 3.0h05 --------------------
+ 1. Fix bug found by forum poster where Zip stops recursing down a tree
+ when option -AS is set and a directory without the Windows archive
+ bit is reached. Now Zip continues down the tree to include files with
+ the bit set. win32/win32zip.c (forum poster, Ed)
+ 2. Update comments. win32/osdep.h (Ed)
+ 3. Update VMS notes to better organize and add information about file
+ name case. Additional small updates. vms/notes.txt (SMS)
+ 4. Fix bugs from previous changes to unix. unix/unix.c (SMS, Christian,
+ Ed)
+ 5. Add unix IBM support. unix/unix.c (SMS)
+ 6. Update INSTALL to account for new distribution structure and other
+ changes. INSTALL (SMS, Ed)
+ 7. Update bzip2 install readme. bzip2/install.txt (SMS, Ed)
+ 8. Fix bug noted in forum where -@ and -x generated a "nothing to
+ select from error" by also checking filelist variable populated by
+ -@ for entries. zip.c (forum poster, Ed)
+----------------------- April 20th 2008 version 3.0h06 --------------------
+ 1. Start announcement for Zip 3.0h public beta. zip30h.ann (Ed)
+ 2. Update beta readme. betas_readme.txt (Ed)
+ 3. Update case of README.CR. INSTALL (Ed)
+ 4. Change -W to -ws for option to stop wildcards from scanning directory
+ boundaries in path. This frees up -W for later use, maybe as extendted
+ option introducer. zip.c, man/zip.1 (Ed)
+ 5. Updated date in announcement to May 4th. zip30.ann (Ed)
+ 6. Added announcement for public beta Zip 3.0h. zip30h.ann (Ed)
+ 7. Fix large file support for MinGW by checking for compiler environments
+ before the check for (generic) gcc. zipup.c, win32/osdep.h
+ (Will, Christian)
+ 8. Fix large file support for bzip2. Additionally, the "dot printout"
+ code has also been adapted for LARGE_FILE support. zipup.c
+ (Will, Christian)
+ 9. Add comments to top of configure. unix/configure (Ed)
+10. Move comment and comment out value size check for UID/GID extra field.
+ unix/unix.c (Ed)
+11. Change case of file ToDo to TODO for consistency and to work with Unix
+ package. TODO (SMS, Ed)
+----------------------- April 26th 2008 version 3.0h07 --------------------
+ 1. For -AS, which for Windows only includes files with the archive bit
+ set, exclude directory entries (by setting -D) as some directories may
+ not have any files with the archive bit set and so the directory would
+ be empty. zip.c (Ed)
+ 2. Fix UID/GID size detection to use byte sizes and remove data fit test.
+ unix/unix.c (Ed)
+ 3. Update announcement. zip30h.ann (Ed)
+ 4. Add new unix extra field with tag 'ux' that stores UIDs/GIDs of 1 to 4
+ bytes (8 to 32 bits). unix/unix.c (Ed)
+ 5. Update VB readme. windll/vbz64/readVB64.txt (Ed)
+ 6. For Unicode escaped output also show escape for ASCII 7-bit if
+ isprintable() is false. fileio.c (Ed)
+ 7. Use locale "en_US.UTF-8" for Unix. zip.c (Ed)
+ 8. Also show escaped Unicode for new files in found list. zip.c (Ed)
+ 9. Update manual. man/zip.1, zip.txt (Ed)
+------------------------ May 4th 2008 version 3.0h08 -----------------------
+ 1. Handle when a bad Unicode string in archive forces
+ utf8_to_wide_string() to return a NULL string. Give warning if UTF-8
+ in existing archive is bad. Put WIN32 wide local header initializations
+ in UNICODE_SUPPORT block. fileio.c, zipfile.c (Ed)
+ 2. Leave out Unicode escape code if not Unicode enabled. zip.c (Ed)
+ 3. Enable oem_to_local_string() and local_to_oem_string() for WIN32
+ even if no Unicode. zip.h, win32/win32.c (Christian, Ed)
+ 4. Update comment about encryption code. zipcloak.c (Ed)
+ 4. Update zipmessage_nl() and zipmessage() from zip.c. zipcloak.c,
+ zipnote.c, zipsplit.c (Ed)
+ 5. Add Mac OS X library check. unix/configure (SMS)
+ 6. Add 16-bit UID/GID check. unix/configure (Christian, Ed)
+ 7. Format echo and comment statements a bit. unix/configure (Ed)
+ 8. Only compile in old 16-bit UID/GID code if new define UIDGID_NOT_16BIT
+ from unix configure script is not defined. unix/unix.c (Christian)
+ 9. A couple changes to updated 16-bit UID/GID code. Add 64-bit
+ UID/GID support to new Unix extra field. unix/unix.c (Ed)
+10. Remove redundant "license" from options table. zipcloak.c (Ed)
+11. Remove old unix build files. unix/configure-orig, unix/Makefile-orig
+ (Christian)
+12. Add -O (--output-file) option to ZipCloak. Fix bug by setting
+ out_path. zipcloak.c (Ed)
+------------------------ May 8th 2008 version 3.0h09 -----------------------
+ 1. Update copyright. Add check for NO_UNICODE_SUPPORT. tailor.h (Ed)
+ 2. Fix bug where Unicode General Purpose Bit Flag 11 should force keeping
+ the old name field but it was being overwritten by the escaped name
+ in the central directory header. Fixed some ZIPERR() calls in
+ putcentral() that referred to putlocal(). zipfile.c (Ed)
+ 3. Add comment about OCRCU8 and OCRCTB. unix/configure (Ed)
+ 4. Change line in instructions to note that manuals should be made after
+ Zip is made. Change OCRTB to OCRCTB. Add $(OCRCTB) to rule for
+ zipcloak$E so crc32_.o is linked in. Add comment for NO_UNICODE_SUPPORT
+ flag. unix/makefile (Ed)
+ 5. Update WhatsNew. Add additional items to the Zip 3.1 list. Add note
+ about Zip 2.4. WHATSNEW (Ed)
+ 6. Update Zip 3.0h announcement. zip30h.ann (Ed)
+ 7. Update manual pages. man/zip.1, man/zipsplit.1, man/zipnote.1,
+ man/zipcloak.1 (Ed)
+ 8. Add noted for UTF-8 locale. zip.c (Ed)
+ 9. Set UTF-8 locale for Unix in utilities if UNICODE_SUPPORT enabled
+ so can display and process paths in archives correctly. zipsplit.c,
+ zipcloak.c, zipnote.c (Ed)
+------------------------ May 12th 2008 version 3.0h10 ----------------------
+ 1. Add use of new Unix UID/GID extra field and of old Unix 16-bit UID/GID
+ extra field when system uses 16-bit UIDs/GIDs to version information.
+ zip.c (SMS, Ed)
+ 2. Add Unicode Path and Unicode Comment extra fields to extra fields list.
+ Update new Unix extra field revision date. proginfo/extrafld.txt (Ed)
+ 3. Add Mac hardware platform to version information. unix/unix.c (SMS)
+------------------------ May 19th 2008 version 3.0h11 ----------------------
+ 1. Initialize f->namew when streaming stdin to fix bug. fileio.c (Ed)
+ 2. Change force_zip64 to start as -1 as unset, then use 1 for forcing use
+ of Zip64 and 0 for disabling use of Zip64. Add negation of -fz to
+ prevent use of Zip64 during streaming from stdin to a non-seekable
+ output where data descriptors will be used, which allows creating
+ archives with the old stream format but will fail if a large file is
+ streamed. Default is still to force Zip64 data descriptors when
+ streaming, which covers all cases but requires a Zip64 compatible
+ unzip. zip.c, globals.c, zipfile.c (Ed)
+ 3. Handle case of bad Unicode in archive. zipfile.c (Ed)
+------------------------ May 22nd 2008 version 3.0h12 ----------------------
+ 1. Fix bug introduced last beta that prevented streaming large files. Use
+ separate error message depending on if -fz- was used. zipfile.c (Ed)
+ 2. Change non existent to nonexistent. unix/configure (SMS)
+ 3. Don't output blank line when zipmessage_nl() gets passed an empty
+ string. This removes blank lines for skipped entries when -FS used.
+ zip.c (Ed)
+------------------------ May 27th 2008 version 3.0h13 ----------------------
+ 1. Change UNICODE_ALLOW_FORCE to UNICODE_SUPPORT, -UN=force to -UN=UTF8,
+ and unicode_force to utf8_force. This option now standard with Unicode
+ support and forces Zip to save UTF-8 paths and comments, when not ASCII,
+ as if UTF-8 were the native character set. globals.c, zip.c, zip.h (Ed)
+ 2. Add note to Todo that it's out of date. TODO (Ed)
+ 3. Update WhatsNew. WHATSNEW (Ed)
+ 4. Update Unicode help in extended help. zip.c (Ed)
+ 5. Update announcements. zip30h.ann, zip30.ann (Ed)
+ 6. Fix bug with -UN=UTF8. zip.c, zipfile.c (Ed)
+ 7. Update Zip manual. man/zip.1, zip.txt (Ed)
+ 8. Attempt an update to zip limits document. proginfo/ziplimit.txt (Ed)
+ 9. Update README regarding forum postings. README (Ed)
+10. Remove duplicate initialization lines for found and fnxt. zip.c (SMS)
+------------------------ May 28th 2008 version 3.0h14 ----------------------
+ 1. Remove >= 0 check from wide character check as value is unsigned.
+ fileio.c (SMS)
+ 2. In putlocal(), move nam and use_uname to UNICODE_SUPPORT block. If
+ no UNICODE_SUPPORT use z->nam instead of nam. zipfile.c (SMS, Ed)
+ 3. Update announcement date for beta. zip30h.ann (Ed)
+------------------------ May 31st 2008 version 3.0h ------------------------
+ 1. In putlocal() if using UTF-8 bit then also set UTF-8 bit in z->lflg so
+ is set in local header for streaming. zipfile.c (Ed)
+ 2. Update announcement date for beta. zip30h.ann (Ed)
+ 3. Rename lib and dll projects to zip32z64 and update project files so
+ project name is same as lib and dll libraries. Export make files.
+ windll/visualc/dll/zip32z64.dsp, windll/visualc/dll/zip32z64.dsw,
+ windll/visualc/dll/zip32z64.mak, windll/visualc/libzip32z64.dsp,
+ windll/visualc/libzip32z64.dsw, windll/visualc/libzip32z64.mak (Ed)
+------------------------ June 7th 2008 version 3.0i01 ----------------------
+ 1. Update Mac ReadMe to note Mac OS X uses Unix port. macos/readme.1st (Ed)
+ 2. Change UNIX to Unix in manual. Update dates in manual and add note
+ about Mac OS X. Change switch to switches. zip.1 (SMS, Ed)
+ 3. Add version information under Windows by adding a version resource.
+ win32/vc6/zip.dsp, win32/vc6bz2/zip.dsp, win32/zip.rc (Ed)
+------------------------ June 15th 2008 version 3.0i02 ----------------------
+ 1. Update Install instructions. INSTALL (Ed)
+ 2. Update ReadMe. README (Ed)
+ 3. Update ToDo list. TODO (Ed)
+ 4. Update WhatsNew. WHATSNEW (Ed)
+ 5. Add note to WHERE. WHERE (Ed)
+ 6. Update announcement. zip30.ann (Ed)
+ 7. Review man pages and update Zip man page. Compile text files from man
+ pages. man/zip.1, zip.txt, zipnote.txt, zipsplit.txt, zipcloak.txt (Ed)
+ 8. Update extended help. zip.c (Ed)
+------------------------ June 17th 2008 version 3.0i03 ----------------------
+ 1. Fix bug where UTF-8 flag was not being set when using_utf8 was set as
+ result of UTF-8 being current character set. zipfile.c (Ed)
+ 2. Update man page globbing description. man/zip.1, zip.txt (SMS, Ed)
+ 3. Update web address to bzip2 package for VMS. vms/install_vms.txt (SMS)
+------------------------ June 21st 2008 version 3.0i04 ----------------------
+ 1. Update comments. zbz2err.c (Christian)
+ 2. Put use_uname in UNICODE_SUPPORT block. zipfile.c (Christian)
+ 3. Increase st to 0x1400. msdos/makefile.msc (Christian)
+ 4. Update copyright and put @CodeSize and @DataSize into ifndef blocks for
+ Huge, Large, Compact, Medium, and Small. msdos/match.asm (Christian)
+ 5. Add check to disable symbolic links. msdos/osdep.h (Christian)
+ 6. Put Mac OS X compiler check into if Mac OS X block to avoid problems on
+ some other Unix ports with the check. unix/configure (SMS)
+ 7. Move set_extra_field() to fix compile problem. unix/unix.c (SMS)
+ 8. Update USEBZIP2 to USEBZ2 and -DUSE_BZIP2 to -DBZIP2_SUPPORT. Drop
+ -DMSDOS compile flag. win32/makefile.w32 (Christian)
+ 9. Change BZIP2_SUPPORT to USEBZ2. win32/makenoas.w32 (Christian)
+------------------------ June 23rd 2008 version 3.0i05 ----------------------
+ 1. Update and unify resources. Remove any MFC dependencies from the resource
+ files zip.rc and windll.rc. win32/zip.rc and windll/windll.rc now read
+ the version info from revision.h. windll.rc internal flags modified to
+ "32-bit dll". zip.rc internal flags liberated from "winnt 32-bit"
+ to "generic 32-bit windows". Win32 zip.exe also supported on Win9x
+ (32-bit). Update makefiles for Borland, MSC, GCC(mingw32), Watcom
+ to support inclusion of zip.rc version resources into zip.exe binary.
+ revision.h, msdos/osdep.h, win32/makefile.bor, win32/makefile.gcc,
+ win32/makefile.w10, win32/makefile.w32, win32/makefile.wat,
+ win32/makenoas.w32, win32/zip.rc, windll/windll.rc (Christian)
+ 2. Remove unused files. win32/resource.h, windll/resource.h,
+ windll/windll.aps, windll/zipver.h, windll/visualc/dll/zip32z64.mak,
+ windll/visualc/lib/zip32z64.mak (Christian)
+ 3. Update VMS. vms/descrip_deps.mms (SMS)
+------------------------ June 26th 2008 version 3.0i06 ----------------------
+ 1. Update Install and Readme in preparation for release. Update WhatsNew.
+ INSTALL, README, WHATSNEW (Ed)
+ 2. Update announcement. zip30.ann (Ed)
+ 3. Update original Visual Basic project comments and documentation.
+ windll/vb/readmevb.txt, windll/vb/vbzip.vbp, windll/vb/vbzip.vbw,
+ windll/vb/vbzipbas.bas, windll/vb/vbzipfrm.frm (Ed)
+ 4. Add bzip2 version of djgpp 2.x makefile thanks to Robert. Assumes a
+ standard djgpp installation. msdos/makebz2.dj2 (Robert Riebisch, Ed)
+------------------------ June 27th 2008 version 3.0i07 ----------------------
+ 1. Add DJGPP to bzip2 install instructions. bzip2/install.txt,
+ msdos/makebz2.dj2 (Robert, Ed)
+------------------------- July 5th 2008 version 3.0 -------------------------
+ 1. Add -sd to extended help. zip.c (Will, Ed)
+ 2. Fix memory bug when rebuilding Zip64 central directory extra field which
+ can crash MinGW and other ports when processing large files. zipfile.c
+ (Will)
+ 3. Fix -v bug preventing display of version information when options in
+ environment variables. zip.c (Ed)
+ 4. Update WhatsNew. WHATSNEW (Ed)
+ 5. Update announcement. zip30.ann (Ed)
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..be3e0c5
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,368 @@
+HOW TO INSTALL ZIP
+
+ Zip is distributed as C source code that can be compiled on a
+ wide range of systems: Unix, VMS, MSDOS, OS/2, NT, Amiga, Atari,
+ BeOS, VM/CMS, ... You will need Unzip 5.0p1 or later (under any
+ system) or PKUNZIP 2.04g or later (under MSDOS) to unpack the
+ distribution file, in this case zip30.zip. But since you read this,
+ you have unpacked it already, or you cheated and got a tar.Z file...
+
+ Note: Zip 3.0 distribution kits (unlike previously distributed
+ Zip 2.x kits) are created with a top-level directory ("zip30") in
+ the archive, making the creating of the zipsrc directory optional.
+
+Installation on Unix (see below for installation on other systems)
+
+ Let's assume that you start from scratch and have not yet unpacked
+ the sources. First step, then, is to unpack Zip. The following
+ assumes that you have zip30.zip in the current directory.
+
+ For example, to extract to a new zipsrc directory (assuming
+ zip30.zip is in the current directory):
+
+ mkdir zipsrc
+ cd zipsrc
+ cp ../zip30.zip .
+ unzip zip30.zip
+ cd zip30
+
+ To extract in an existing directory, such as /usr/local/src/zip:
+
+ cd /usr/local/src/zip
+ (copy zip30.zip here)
+ unzip zip30.zip
+ cd zip30
+
+ The first extracts all source files and documentation to the
+ directory "zipsrc/zip30". The second places the zip30 directory
+ in the "/usr/local/src/zip" directory. Both then cd in to the
+ zip30 directory where Zip will be built.
+
+ Note: This release now includes the standard encryption code
+ previously in the separate package zcrypt29.zip, but you still
+ can decide whether to activate the crypt code or not. Crypt is
+ enabled by default, but you may disable it by specifying the
+ option -DNO_CRYPT in the LOCAL_ZIP environment variable (or by
+ adding this option to the compilation options in the appropiate
+ makefile). See README.CR for more on crypt.
+
+ You then do:
+
+ make -f unix/Makefile system
+
+ where "system" is one of: generic, generic_gcc,
+ att6300, coherent, cray_v3, minix, sco_x286, xenix, zilog.
+
+ For Unix systems where "cc" is the preferred C compiler command,
+ try
+
+ make -f unix/Makefile generic
+
+ first. If "gcc" is preferred, specify "generic_gcc" instead of
+ "generic". This should work on most systems and automatically
+ selects compilation options based on a set of tests (in
+ unix/configure), including detection of large file support
+ sufficient to enable Zip64 large archive features. If "generic"
+ (or "generic_gcc" if that is used) fail, then one of the special
+ targets given above may work.
+
+ Among other special systems are Cray Unicos, Zilog Zeus and MINIX.
+
+ The optimization settings for many systems should be close, but
+ if you see optimization for your system is not ideal, send in
+ the changes so we can improve it.
+
+ By default, Zip uses the "deflate" compression method. To add
+ the additional optional "bzip2" compression method, see the file
+ bzip2/install.txt. Note that bzip2 support is provided by
+ compiling or linking in the bzip2 library. See the bzip2 site
+ (http://www.bzip.org/) for more on bzip2.
+
+ If you get error messages such as "constant expected" in
+ deflate.c, add -DDYN_ALLOC to CFLAGS in your makefile entry.
+
+ If you have lots of memory, try compiling with -DBIG_MEM. If your
+ system supports mmap(), try compiling with -DMMAP. This generally
+ gives faster compression but uses more memory. See the unix/Makefile
+ entry mmap_gcc for an example.
+
+ If none of these compiles, links, and functions properly on
+ your Unix system, then your system apparently has specific
+ requirements we did not account for. See the file README for how
+ to get help.
+
+ If the appropriate system was selected, then the executables zip,
+ zipnote, zipcloak, and zipsplit will be created. You can copy
+ them to an appropriate directory in the search path using:
+
+ make -f unix/Makefile install
+
+ The defaults are /usr/local/bin for the executables and
+ /usr/local/man/man1 for the manual pages. Change the macros
+ BINDIR and MANDIR in makefile to change these if needed.
+
+ If necessary, add the directory with the Zip executables to your
+ shell's PATH (or "path") variable. (C-shell users may need to
+ use the "rehash" command so csh can find the new command in the
+ path.) You should now be ready to use Zip.
+
+ You can get rid of the now unnecessary source and object files
+ with:
+
+ cd ..
+ rm -r zip30
+
+ This will remove the directory zip30 and its contents created
+ by unzip. You should keep the zip30.zip file around though,
+ in case you need to build it again or want to give it to a
+ colleague.
+
+ You can add the following lines to the file /etc/magic for
+ usage by the 'file' command:
+
+0 string PK Zip archive
+>4 byte 011 (at least v0.9 to extract)
+>4 byte 012 (at least v1.0 to extract)
+>4 byte 013 (at least v1.1 to extract)
+>4 byte 024 (at least v2.0 to extract)
+>4 byte 025 (at least v2.1 to extract)
+
+
+Installation on other systems
+
+ The steps for installation under VMS, MSDOS, OS/2, NT, Amiga and
+ Atari are similar to the above: first unzip the distribution
+ files into their own directory. The system-dependent files are
+ stored in special subdirectories.
+
+ For all the non-Unix ports which support the creation of "UT" extra
+ fields (these ports contain USE_EF_UT_TIME in the list of optional
+ features displayed with "zip -v"), the timezone environment variable TZ
+ should be set according to the local timezone in order for the -f, -u,
+ -o, and similar options to work correctly. This is not needed for the
+ WIN32 and WinDLL ports, since they get the timezone information from
+ the OS by other means.
+
+
+ MSDOS:
+
+ Do one of:
+
+ make msdos\makefile.msc (Microsoft C 5.1)
+ nmake -f msdos\makefile.msc (Microsoft C 6.0 and newer)
+ make -fmsdos\makefile.bor -DCC_REV=1 (Borland Turbo C++ 1.0)
+ make -fmsdos\makefile.bor (Borland C++ 2.0 and newer)
+ make -fmsdos\makefile.tc (Borland Turbo C 2.0x)
+ make -f msdos/makefile.dj1 (DJGPP v1.12m4)
+ make -f msdos/makefile.dj2 (DJGPP v2.01 and newer)
+ make -f msdos/makefile.emx (gcc/emx 0.9b and newer)
+ make -f os2/makefile.os2 gccdos (gcc/emx 0.9b and newer)
+ wmake -f msdos\makefile.wat (Watcom C 11.x 16-bit)
+ wmake -f msdos\makefile.wat PM=1 (Watcom C 11.x 32-bit, PMODE/W)
+
+ for Microsoft, Borland C++ and Turbo C, Watcom C/C++ and the various
+ free GNU C implementations, respectively. More detailed instructions
+ can be found in the respective makefiles.
+
+
+ WIN32 (Windows NT/2K/XP/2K3 and Windows 95/98/ME):
+
+ Supported compilers are Microsoft Visual C++, Borland C++, Watcom C/C++,
+ and miscellaneous free GNU C implementations (gcc/mingw, CygWin, ...).
+ The makefiles supplied in the win32/ subdirectory contain further
+ information.
+
+
+ Windows DLL (WIN32):
+
+ Supported environments are Visual C++ (32-bit only, 5.x and newer).
+ For instructions how to build the DLLs and where find the makefiles,
+ look into windll/contents.
+
+
+ OS/2:
+
+ Type
+
+ {make} -f os2/makefile.os2
+
+ to get a list of supported targets/compiling environments.
+ (replace "{make}" with the name of your OS/2 make utility.)
+
+ To initiate the actual compiling process, you have to specify
+ a system target:
+
+ {make} -f os2/makefile.os2 {system}
+
+ An example: type
+
+ nmake -f os2/makefile.os2 msc
+
+ for Microsoft C 6.00.
+
+
+ VMS (OpenVMS):
+
+ The most complete information on building and installing Zip on VMS
+ is in [.vms]install_vms.txt. Optimists in a hurry may wish to try
+ commands like these:
+
+ @ [.VMS]BUILD_ZIP.COM
+ or:
+ MMS /DESCRIP = [.VMS]DESCRIP.MMS CLEAN ! Or MMK ...
+ MMS /DESCRIP = [.VMS]DESCRIP.MMS ! Or MMK ...
+
+ When the executables have been created (or located if already installed),
+ most users define foreign command symbols for the Zip executables, like
+ this:
+
+ ZIP :== $ dev:[dir]ZIP.EXE ! UNIX-like command line.
+ or:
+ ZIP :== $ dev:[dir]ZIP_CLI.EXE ! VMS-like command line.
+
+ Such symbol definitions are often added to a user's
+ SYS$LOGIN:LOGIN.COM procedure, or to a common, site-specific
+ procedure, like SYS$MANAGER:SYLOGIN.COM.
+
+ Additional installation options are described in install_vms.txt.
+
+ The builders create help text files, ZIP.HLP and ZIP_CLI.HLP. Also
+ see install_vms.txt for how to create the help libraries.
+
+
+Mac OS:
+
+ Mac OS X is part of the Unix port, so use the Unix installation above.
+
+ Mac OS before Mac OS X use the Mac OS port, though little testing has
+ been done for that port recently. See macos/README.TXT for more on
+ this port.
+
+
+Compiler Flags
+
+ Zip should compile fine out of the box for your port. In particular,
+ for Unix the command
+ make -f unix/Makefile generic
+ should automatically detect the features available on your system and
+ set the flags appropriately. In some cases, however, you may need to
+ set one or more compiler flags yourself to get Zip to compile or to
+ add features you want or remove features that cause trouble for your
+ port. Below are the more common compiler macros you can set.
+
+ LARGE_FILE_SUPPORT
+ Tell Zip that the OS supports large files (generally files larger
+ than 4 GB). Zip will try to compile in the large file calls
+ (typically 64-bit) for the OS instead of using the standard
+ (typically 32-bit) file calls. On Unix Zip tries to switch over to
+ the 64-bit file environment. If setting this flag causes errors
+ or Zip still can't handle large files on that port, then probably
+ either Zip doesn't have the code to support large files on your OS
+ (write a patch and send it in to us) or your OS doesn't support large
+ files.
+
+ Note that the flag ZIP64_SUPPORT must also be set to create archives
+ with large files.
+
+ This flag should be set automatically on Unix, Win32, and some
+ other ports. Setting NO_LARGE_FILE_SUPPORT turns this flag off.
+
+ ZIP64_SUPPORT
+ Enable the Zip64 code in Zip that supports the Zip64 extensions noted
+ in the PKWare AppNote. These extensions allow storing files larger
+ than 4 GB in archives and the creating of archives larger than 4 GB.
+ They also allow storing more than 64K files in an archive. Currently
+ Zip does not handle archives of PKZip version 4.5 or later unless
+ this flag is set.
+
+ To enable large file support in Zip, you generally need to set both
+ LARGE_FILE_SUPPORT (to read and write large files) and ZIP64_SUPPORT
+ (to store them in and read them from archives). Files larger than
+ 4 GB may be invisible to Zip (directory scans don't see them) if
+ LARGE_FILE_SUPPORT is not enabled.
+
+ Keeping LARGE_FILE_SUPPORT and ZIP64_SUPPORT separate allows easier
+ debugging of these features. When testing large file support on an
+ OS, first set just LARGE_FILE_SUPPORT to test the file calls (all
+ should compile and work as before with small files), then turn on
+ ZIP64_SUPPORT to let Zip recognize and handle large files.
+
+ This flag should be set automatically on most ports if
+ LARGE_FILE_SUPPORT is set. Setting NO_ZIP64_SUPPORT turns this flag
+ off.
+
+ UNICODE_SUPPORT
+ Enable storing and using UTF-8 paths. These paths are stored in
+ a backward-compatible way so that archives with UTF-8 paths still
+ work on zips and unzips that don't support Unicode. This support
+ follows the recent additions to the PKWare AppNote for Unicode
+ support, except that Unicode comments on systems where UTF-8 is
+ not the current character set is not implemented in this release.
+
+ On some ports UNICODE_SUPPORT is set automatically if wide characters
+ are supported. Setting NO_UNICODE_SUPPORT turns off this flag.
+
+ USE_EF_UT_TIME
+ Enables storing UT time in an extra field. This becomes useful
+ for ports that normally store file times as local time, resulting
+ in problems when files are moved across time zones and when
+ there are daylight savings time changes. Zip and UnZip will
+ automatically correct for time zone changes when UT time is stored.
+
+ This is usually set by default. Use NO_EF_UT_TIME to turn this off.
+
+ NTSD_EAS (Win32 only)
+ Enable storing Windows NT file security descriptors. This allows
+ restoring the descriptors (file ACL's, etc.).
+
+ This is on by default for Win32. Use NO_NTSD_EAS to turn this off.
+
+ BZIP2_SUPPORT
+ Enable compressing zip entries using the bzip2 library. You must get
+ the bzip2 library from somewhere else as we only provide a way to
+ compile or link the library in and compress files using bzip2. Enables
+ a new compression method, bzip2, that can be used instead of the default
+ Zip compression method deflate.
+
+ This flag is set on Unix, including Mac OS X, when compiling using
+ generic if the bzip2 library is found. Set on Win32 if the bzip2
+ projects are used. See the VMS documentation for when VMS sets this
+ flag. Setting NO_BZIP2_SUPPORT turns this off.
+
+ See bzip2/install.txt for more on installing bzip2 support.
+
+ WIN32_OEM (Win32 only)
+ Enable saving paths on Win32 in the OEM character set. Zip has stored
+ paths using the standard ANSI local character set, but other zips have
+ used the OEM character set on MSDOS and Win32. This flag should make
+ Zip more compatible with other DOS and Win32 zips and unzips. It also
+ enables the translation of OEM paths in DOS archives to ANSI and should
+ eliminate some problems with funny characters showing up in path names.
+
+ If Unicode is enabled and used, Unicode paths generally override
+ local paths using OEM character sets.
+
+ This flag is on by default on most Win32 ports. Some ports apparently
+ have problems with OEM conversions. If your port or compiler does
+ funny things with file names, you may want to turn this off. Defining
+ NO_WIN32_OEM turns this flag off.
+
+ NO_STREAMING_STORE
+ Because storing zip archives inside a zip entry adds "false" signatures
+ and this causes problems when using data descriptors if the archive
+ needs fixing, this option is provided to force deflating when streaming.
+ This version of Zip includes an advanced algorithm for correctly finding
+ these signatures, but if an archive is "broke", there is no telling
+ what's where. This is only a problem if an archive becomes broke for
+ some reason, but to be safe define this.
+
+ ALLOW_REGEX
+ For MSDOS and Windows, now "[list]" wildcard matching (where any
+ character between [ and ] can be used to match the character at that
+ position) is turned off unless the new -RE option is used. Defining
+ this flag forces "[list]" matching to be always on as in previous
+ releases.
+
+
+For command help on any of the zip* utilities, simply enter
+the name with no arguments.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bcfe47e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,60 @@
+This is version 2007-Mar-4 of the Info-ZIP license.
+The definitive version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and
+a copy at http://www.info-zip.org/pub/infozip/license.html.
+
+
+Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+For the purposes of this copyright and license, "Info-ZIP" is defined as
+the following set of individuals:
+
+ Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+ Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+ Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+ David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+ Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+ Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+ Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+ Rich Wales, Mike White.
+
+This software is provided "as is," without warranty of any kind, express
+or implied. In no event shall Info-ZIP or its contributors be held liable
+for any direct, indirect, incidental, special or consequential damages
+arising out of the use of or inability to use this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the above disclaimer and the following restrictions:
+
+ 1. Redistributions of source code (in whole or in part) must retain
+ the above copyright notice, definition, disclaimer, and this list
+ of conditions.
+
+ 2. Redistributions in binary form (compiled executables and libraries)
+ must reproduce the above copyright notice, definition, disclaimer,
+ and this list of conditions in documentation and/or other materials
+ provided with the distribution. The sole exception to this condition
+ is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+ part of a self-extracting archive; that is permitted without inclusion
+ of this license, as long as the normal SFX banner has not been removed
+ from the binary or disabled.
+
+ 3. Altered versions--including, but not limited to, ports to new operating
+ systems, existing ports with new graphical interfaces, versions with
+ modified or added functionality, and dynamic, shared, or static library
+ versions not from Info-ZIP--must be plainly marked as such and must not
+ be misrepresented as being the original source or, if binaries,
+ compiled from the original source. Such altered versions also must not
+ be misrepresented as being Info-ZIP releases--including, but not
+ limited to, labeling of the altered versions with the names "Info-ZIP"
+ (or any variation thereof, including, but not limited to, different
+ capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the
+ explicit permission of Info-ZIP. Such altered versions are further
+ prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
+ e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
+ will provide support for the altered versions.
+
+ 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
+ "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its
+ own source and binary releases.
diff --git a/README b/README
new file mode 100644
index 0000000..a559425
--- /dev/null
+++ b/README
@@ -0,0 +1,234 @@
+Zip 3.0 is the first Zip update adding large file support. For now Zip 2.3x
+remains available and supported, but users should switch to this new release.
+
+Testing for Zip 3.0 has focused mainly on Unix, VMS, Max OS X, and Win32,
+and some other ports may not be fully supported yet. If you find your
+favorite port is broke, send us the details or, better, send bug fixes. It's
+possible that support for some older ports may be dropped in the future.
+
+
+
+Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+See the accompanying file LICENSE (the contents of which are also included
+in unzip.h, zip.h and wiz.h) for terms of use. If, for some reason, all
+of these files are missing, the Info-ZIP license also may be found at:
+ftp://ftp.info-zip.org/pub/infozip/license.html and
+http://www.info-zip.org/pub/infozip/license.html.
+
+
+Zip 3.0 is a compression and file packaging utility. It is compatible with
+PKZIP 2.04g (Phil Katz ZIP) for MSDOS systems. There is a companion to zip
+called unzip (of course) which you should be able to find in the same place
+you got zip. See the file 'WHERE' for details on ftp sites and mail
+servers.
+
+So far zip has been ported to a wide array of Unix and other mainframes,
+minis, and micros including VMS, OS/2, Minix, MSDOS, Windows, Atari, Amiga,
+BeOS and VM/CMS. Although highly compatible with PKware's PKZIP and PKUNZIP
+utilities of MSDOS fame, our primary objective has been one of portability
+and other-than-MSDOS functionality. Features not found in the PKWare version
+include creation of zip files in a pipe or on a device; VMS, BeOS and OS/2
+extended file attributes; conversion from Unix to MSDOS text file format; and,
+of course, the ability to run on most of your favorite operating systems. And
+it's free.
+
+See the file zip30.ann for a summary of new features in Zip 3.0 and WhatsNew
+for the detailed list of new features and changes since Zip 2.32. The file
+CHANGES details all day-to-day changes during development.
+
+Notes:
+
+Multi-volume support. This version does not support multi-volume spanned
+archives as in pkzip 2.04g, and there is no intention at this point to support
+spanned archives, but Zip 3.0 supports split archives. A split archive is an
+archive split into a set of files, each file a piece of the archive and each
+file using an extension, such as .z02 as in the file name archive.z02, that
+provides the order of the splits. In contrast, a spanned archive is the
+original multi-floppy archive supported by pkzip 2.0g where the split order
+is contained in the volume labels. The contents of split and spanned archives
+are mostly identical and there is a simple procedure to convert between the
+formats. Many current unzips now support split archives.
+
+Zip64 support. This version supports Zip64 archives as described in the
+PKWare AppNote. These archives use additional fields to support archives
+greater than 2 GB and files in archives over the 2 GB previous limit (4 GB
+on some ports). The Zip64 format also allows more than 64k entries in an
+archive. Support by the OS for files larger than 4 GB is needed for Zip to
+create and read large files and archives. On Unix, Win32, and some other
+ports, large file and Zip64 support is automatically checked for and
+compiled in if available. Use of Zip64 by Zip is automatic and to maximize
+backward compatibility the Zip64 fields will only be used if needed. A
+Zip64 archive requires a pkzip 4.5 compatible unzip, such as UnZip 6.0.
+
+Unicode support. This version has initial Unicode support. This allows
+paths and names of files in other character sets to be accurately recreated
+on OS that have sufficient character set support. On Win32, if wide
+character calls are supported (not Win 9x unless Unicode support has been
+added) all files (including paths with illegal characters in the current
+character set) should now be readable by zip. Unicode support is provided
+using a new set of UTF-8 path and comment extra fields and a new UTF-8 bit
+for flagging when the current character set is already UTF-8. Zip 3.0
+maintains backward compatibility with older archives and is mostly compliant
+with the new Unicode additions in the latest PKWare AppNote. The exception
+is UTF-8 comments, which are not supported if UTF-8 is not the native
+character set, but should be fully implemented in Zip 3.1.
+
+16-bit OS support. Though Zip 3.0 is designed to support the latest zip
+standards and modern OS, some effort has been made to maintain support
+for older and smaller systems. If you find Zip 3.0 does not fit on or
+otherwise does not work well on a particular OS, send in the details and
+we might be able to help.
+
+Compression methods. In addition to the standard store and deflate methods,
+Zip now can use the bzip2 compression format using the bzip2 library. Though
+bzip2 compression generally takes longer, in many cases using bzip2 results
+in much better compression. However, many unzips may not yet support
+bzip2 compressed entries in archives, so test your unzip first before using
+bzip2 compression.
+
+Installation. Please read the file INSTALL for information on how to compile
+and install zip, zipsplit, zipcloak, and zipnote and please read the manual
+pages ZIP.txt, ZIPSPLIT.txt, ZIPCLOAK.txt, and ZIPNOTE.txt for information on
+how to use them. Also, if you are using MSDOS or Windows, note that text
+files in the distribution are generally in Unix line end format (LF only)
+and Windows and DOS users will need to either convert the files as needed to
+DOS line ends (CR LF) or extract the distribution contents using unzip -a.
+
+Utilities. At this point zipsplit, zipcloak, and zipnote should work with
+large files, but they currently do not handle split archives. A work around
+is to use zip to convert a split archive to a single file archive and then use
+the utilities on that archive.
+
+Encryption. This version supports standard zip encryption. Until recently
+the encryption code was distributed separately because of the US export
+regulations but now is part of the main distribution. See crypt.c for
+details. Decryption can be made with unzip 5.0p1 or later, or with zipcloak.
+
+Bug reports. All bug reports or patches should go to zip-bugs via the web
+site contact form at http://www.info-zip.org/zip-bug.html (we have discontinued
+the old email address zip-bugs@lists.wku.edu because of too much spam lately)
+and suggestions for new features can be submitted there also (although we don't
+promise to use all of them). We also are on SourceForge at
+http://sourceforge.net/projects/infozip/ and now automatically get Bug Reports
+and Feature Requests submitted there. In addition, a new Info-ZIP discussion
+forum is available as well. See below. Though bug reports can be posted there,
+we don't have automatic monitoring of all postings set up yet so you may want
+to use the web form or SoureForge for a quicker response. A good approach may
+be to post the details on the forum so others can benefit from the posting,
+then use the web reply form to let us know you did that if you don't get a
+reply in a reasonable time.
+
+Ports. If you're considering a port, please check in with zip-bugs FIRST,
+since the code is constantly being updated behind the scenes. We'll
+arrange to give you access to the latest source.
+
+Discussion group. If you'd like to keep up to date with our Zip (and companion
+UnZip utility) development, join the ranks of BETA testers, add your own
+thoughts and contributions, etc., check out the new discussion forum. This is
+the latest offering, after the various Info-ZIP mailing-lists on
+mxserver@lists.wku.edu (courtesy of Hunter Goatley) were no longer available
+and the temporary QuickTopic discussion group for Info-ZIP issues at
+http://www.quicktopic.com/27/H/V6ZQZ54uKNL died a horrible death due to large
+amounts of spam. The new discussion forum is now available at
+http://www.info-zip.org/board/board.pl (thanks again to Hunter Goatley) and
+can be used to discuss issues, request features, and is one place new betas
+and releases are announced. It also is a place to post bug reports, and
+patches can be submitted as attachments. However, we don't yet get
+automatic notification of all postings there so try one of the other methods
+if you don't get a response. You can also post Bug Reports and Feature
+Requests at Source Forge. However, the web site contact form remains
+available if you would rather not post on the public forums.
+
+Frequently asked questions on zip and unzip:
+
+Q. When unzipping I get an error message about "compression method 8".
+
+A. This is standard deflate, which has been around for awhile. Please
+ get a current version of unzip. See the file 'WHERE' for details.
+
+
+Q. How about "compression method 12"?
+
+A. Compression method 12 is bzip2 and requires a relatively modern unzip.
+ Please get the latest version of unzip.
+
+
+Q. I can't extract this zip file that I just downloaded. I get
+ "zipfile is part of multi-disk archive" or some other message.
+
+A. Please make sure that you made the transfer in binary mode. Check
+ in particular that your copy has exactly the same size as the original.
+ Note that the above message also may actually mean you have only part
+ of a multi-part archive. Also note that UnZip 5.x does not and UnZip 6.0
+ probably won't have multi-disk (split) archive support. A work around
+ is to use Zip 3.0 to convert the split archive to a single-file archive
+ then use UnZip on that archive. As a last result, if there's something
+ readable in what you have, zip -FF should be able to recover it.
+
+
+Q. When running unzip, I get a message about "End-of-central-directory
+ signature not found".
+
+A. This usually means that your zip archive is damaged, or that you
+ have an uncompressed file with the same name in the same directory.
+ In the first case, it makes more sense to contact the person you
+ obtained the zip file from rather than the Info-ZIP software
+ developers, and to make sure that your copy is strictly identical to
+ the original. In the second case, use "unzip zipfile.zip" instead
+ of "unzip zipfile", to let unzip know which file is the zip archive
+ you want to extract.
+
+
+Q. Why doesn't zip do <something> just like PKZIP does?
+
+A. Zip is not a PKZIP clone and is not intended to be one. In some
+ cases we feel PKZIP does not do the right thing (e.g., not
+ including pathnames by default); in some cases the operating system
+ itself is responsible (e.g., under Unix it is the shell which
+ expands wildcards, not zip). Info-ZIP's and PKWARE's zipfiles
+ are interchangeable, not the programs.
+
+ For example, if you are used to the following PKZIP command:
+ pkzip -rP foo *.c
+ you must use instead on Unix:
+ zip -R foo "*.c"
+ (the quotes are needed to let the shell know that it should
+ not expand the *.c argument but instead pass it on to the program,
+ but are not needed on ports that do not expand file paths like
+ MSDOS)
+
+
+Q. Can I distribute zip and unzip sources and/or executables?
+
+A. You may redistribute the latest official distributions without any
+ modification, without even asking us for permission. You can charge
+ for the cost of the media (CDROM, diskettes, etc...) and a small copying
+ fee. If you want to distribute modified versions please contact us at
+ www.Info-ZIP.org first. You must not distribute beta versions.
+ The latest official distributions are always on ftp.Info-ZIP.org in
+ directory /pub/infozip and subdirectories and at SourceForge.
+
+
+Q. Can I use the executables of zip and unzip to distribute my software?
+
+A. Yes, so long as it is made clear in the product documentation that
+ zip or unzip are not being sold, that the source code is freely
+ available, and that there are no extra or hidden charges resulting
+ from its use by or inclusion with the commercial product. See the
+ Info-ZIP license for more. Here is an example of a suitable notice:
+
+ NOTE: <Product> is packaged on this CD using Info-ZIP's compression
+ utility. The installation program uses UnZip to read zip files from
+ the CD. Info-ZIP's software (Zip, UnZip and related utilities) is
+ freely distributed under the Info-ZIP license and can be obtained as
+ source code or executables from various anonymous-ftp sites,
+ including ftp://ftp.info-zip.org/pub/infozip.
+
+
+Q. Can I use the source code of zip and unzip in my commercial application?
+
+A. Yes, as long as the conditions in the Info-ZIP license are met. We
+ recommend you include in your product documentation an acknowledgment
+ and note that the original compression sources are available at
+ www.Info-ZIP.org. If you have special requirements contact us.
diff --git a/README.CR b/README.CR
new file mode 100644
index 0000000..c777d19
--- /dev/null
+++ b/README.CR
@@ -0,0 +1,119 @@
+_____________________________________________________________________________
+
+ This is Info-ZIP's README.CR for zcrypt29.zip, last updated 27 March 2008.
+_____________________________________________________________________________
+
+
+The files described below contain the encryption/decryption code for Zip 2.31,
+UnZip 5.52, and WiZ 5.02 (and later). These files are included in the main
+source distributions for all of these now, but the encryption patch is still
+available for earlier versions of these. This file both describes the history
+of the encryption package and notes the current conditions for use. Check
+the comments at the top of crypt.c and crypt.h for additional information.
+
+As of version 2.9, this encryption source code is copyrighted by Info-ZIP;
+see the enclosed LICENSE file for details. Older versions remain in the pub-
+lic domain. Zcrypt was originally written in Europe and, as of April 2000,
+can be freely distributed from the US as well as other countries.
+
+(The ability to export from the US is new and is due to a change in the Bureau
+of Export Administration's regulations, as published in Volume 65, Number
+10, of the Federal Register [14 January 2000]. Info-ZIP filed the required
+notification via e-mail on 9 April 2000; see the USexport.msg file in this
+archive. However, as of June 2002, it can now be freely distributed in both
+source and object forms from any country, including the USA under License
+Exception TSU of the U.S. Export Administration Regulations (section 740.13(e))
+of 6 June 2002.)
+
+ LIKE ANYTHING ELSE THAT IS FREE, ZIP, UNZIP AND THEIR ASSOCIATED
+ UTILITIES ARE PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND,
+ EITHER EXPRESSED OR IMPLIED. IN NO EVENT WILL THE AUTHORS BE LIABLE
+ FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE.
+
+The encryption code is a direct transcription of the algorithm from
+Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+file is distributed with the PKZIP program (even in the version without
+encryption capabilities). Note that the encryption will probably resist
+attacks by amateurs if the password is well chosen and long enough (at
+least 8 characters) but it will probably not resist attacks by experts.
+Paul Kocher has made available information concerning a known-plaintext
+attack for the PKWARE encryption scheme; see http://www.cryptography.com/
+for details.) Short passwords consisting of lowercase letters only can be
+recovered in a few hours on any workstation. But for casual cryptography
+designed to keep your mother from reading your mail, it's OK.
+
+For more serious encryption, check into PGP (Pretty Good Privacy), a
+public-key-based encryption system available from various Internet sites.
+PGP has Zip and UnZip built into it. The most recent version at the time
+this was originally written was 6.5, although older versions were still
+widespread. At the time of this writing there are now GPG, PGP Universal
+2.0, and various others based on OpenPGP.
+
+We are looking at adding AES strong encryption to future versions of Zip and
+UnZip.
+
+Zip 2.3x and UnZip 5.5x and later are compatible with PKZIP 2.04g. (Thanks
+to Phil Katz for accepting our suggested minor changes to the zipfile format.)
+
+IMPORTANT NOTE:
+
+ Zip archives produced by Zip 2.0 or later must not be *updated* by
+ Zip 1.1 or PKZIP 1.10 or PKZIP 1.93a, if they contain encrypted members
+ or if they have been produced in a pipe or on a non-seekable device.
+ The old versions of Zip or PKZIP would destroy the zip structure. The
+ old versions can list the contents of the zipfile but cannot extract
+ it anyway (because of the new compression algorithm). If you do not
+ use encryption and compress regular disk files, you need not worry about
+ this problem.
+
+
+Contents that were distributed and now are part of the main source files:
+
+ file what it is
+ ---- ----------
+ README.CR this file
+ LICENSE Info-ZIP license (terms of reuse and redistribution)
+ USexport.msg export notice sent to US Bureau of Export Administration
+ WHERE where Zip/UnZip/WiZ and related utilities can be found
+ crypt.c code for encryption and decryption
+ crypt.h code for encryption and decryption
+ file_id.diz description file for some BBSes
+
+Most all of the files are in Unix (LF only) format. On MSDOS systems, you
+can use the -a option of UnZip to convert the source files to CRLF
+format. This is only necessary if you wish to edit the files -- they
+will compile as is with Microsoft C and Turbo/Borland C++ 1.0 or
+later. However, you will have to convert the files (using "unzip -a")
+to the CRLF format to compile with the older Turbo C 1.0 or 2.0. You
+should be able to find Zip and UnZip in the same place you found this
+(see ftp://ftp.info-zip.org/pub/infozip/Info-ZIP.html or the file
+"WHERE" for details).
+
+Current releases all have encryption built in. To update previous versions
+using the zcrypt sources:
+
+ (1) Get the main sources (e.g., Zip 2.3) and unpack into a working
+ directory, as usual.
+
+ (2) Overwrite the dummy crypt.c and crypt.h from the main sources with
+ the versions from this package. If you want to overwrite directly
+ out of the zcrypt29 archive, do not use UnZip's freshen/updating
+ option; the dummy files may be newer than the real sources in
+ zcrypt29. ("unzip -o zcrypt29 -d /your/working/dir" will do the
+ Right Thing in most cases, although it may overwrite a newer WHERE
+ file under some circumstances.)
+
+ (3) Read the main INSTALL document and compile normally! No makefile
+ changes are necessary on account of the zcrypt sources. You can
+ check that the version you just compiled has encryption or decryption
+ support enabled by typing "zip -v" or "unzip -v" and verifying that
+ the last "special compilation option" says encryption or decryption
+ is included.
+
+Encryption enables new "-e" and "-P password" options in Zip, and a new
+"-P password" option in UnZip--see the normal Zip and UnZip documentation
+for details. (Note that passing a plaintext password on the command line
+is potentially much more insecure than being prompted for it interactively,
+which is the default for UnZip and for Zip with "-e". Also note that the
+interactive method allows UnZip to deal with archives that use different
+passwords for different files.)
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..8d51732
--- /dev/null
+++ b/TODO
@@ -0,0 +1,142 @@
+Todo list (last updated 12 June 2008).
+
+Features for next official version:
+
+- Extended attributes for Windows, Linux, and Mac OS X.
+- Win32 ACL rewrite to use backup api to create new and more useful extra
+ field (need unzip support) (Kai).
+- Allow -d@ to read in a list of names to delete (11/17/2005).
+- AES encryption (3/19/05).
+
+Features that may make the next release:
+
+- Allow reading in list of files using @filename.
+- When -R, -x, or -i pattern ends in a directory add / to the end
+ (11/5/2004 Nehal).
+- Decide if -R, -i and -x should use external rather than internal patterns.
+ Also, change pattern matching to not do ex2in() and then in2ex() if
+ appropriate. (12/26/2005 SMS)
+- Though Unicode paths have been implemented and tested, Unicode comments
+ are not yet supported (except for comments on UTF-8 native systems which
+ are supported).
+- Verbose mode -v may still need work.
+
+- Add C# example for Zip 3.0 (need to be converted to new DLLs) - original
+ C# example added with note.
+- Path Prefix maybe, so entries added to an archive can have a directory
+ path string prepended to each path so can zip multiple drives and avoid
+ name conflicts (4/17/2006).
+- UNC paths like \\server\path (4/26/2005).
+- Support for other languages maybe.
+
+- Add About page option similar to -h2 and -v but lists Info-ZIP
+ information (could be -sa) (4/29/2006).
+- Update utilities ZipSplit, ZipNote, and ZipCloak to handle split archives.
+- Update ziperr and finish if needed.
+- Review memory allocation and fill in memory leaks if any.
+- Enhance -FF to fix common problems such as archives ftp in text mode
+ and fixing checksums so entries can be extracted if that makes
+ sense (6/17/2007).
+- Add \ to / conversion in zipsplit to fix problem in
+ 1/29/2004 email.
+- Encryption bug with small stored file (12/27/2005) (fixed?).
+
+- When updating large archives with few entries being
+ updated maybe display something in large periods of
+ quiet (1/23/2006).
+- Windows OEM comments (5/17/2006).
+- Example of using MVS zip and unzip (3/30/2004) (Need one).
+- UTF-8 comments need to be implemented (6/17/2007)
+- Maybe convert ../ in archive (5/20/2006).
+- Per so many buffers dll callback (12/23/2005 Ale).
+- Allow rename stdin "-" to something else (12/27/2005 gregor).
+- Check for possible buffer overrun weaknesses while reading zip files.
+- Do Active Template Library (ATL) (4/27/2005).
+- Flush Win16 support - to be determined (Mike).
+- Way to convert file names on input, converting foo.c to dir/foo_bar.c
+ for instance (4/8/2004, 3/12/2004).
+- French WiZ (not a Zip thing actually but dependent on zip and unzip).
+- Then there is that wierd ^D being converted to \000 error reported
+ in 6/21/2003 email when Zip is outputted into a pipe on Windows ports.
+
+Old list:
+
+Main features still missing for next official version (last updated 2/11/2001):
+
+- what about the binary/text detection ? (seems done)
+- -b and -t options in help screen (covered in -h2)
+- findfirst/findnext and after that LSSTAT (performance!!)
+- use IS_EXEC from djgpp stat.h
+- use install in unix/Makefile instead of mkdir -p, look at install sh script.
+- #elif for those ports that can handle it.
+- what about zopen vs. fopen ?
+- Add zcreate or zfcreate for win32.
+- Assembler stuff in match.S (subexpressions)
+- zipping huge files (> 2G, unsigned 32bit) (done)
+- Testsuite for zip and unzip (John D. Mitchell)
+- make a version.c or version.h that includes all the compiler names
+- run utils with dmalloc().
+- what to do with zip -F and zip -FF (readzipfile2()) ? (done?)
+- profiling of the code
+- multi disk zip files (could be done)
+- zipfile modification tool (Greg)
+- Implement -- option (Thomas Klauser, wiz@danbala.tuwien.ac.at) (could be done)
+- don't add files with "Archive bit" or add files with "Archive bit"
+ (uwe.becher@metronet.de) (could be done with -AS and -AC)
+- 32 bit file attributes
+- generate output without having to seek at all (this seems to be stream output)
+- remove contractions from zip error messages, make them clearer (Steve)
+- display "[text]" for ascii files when not quiet (no -q) (Timo Salmi)
+- does zipnote accept names with version number?
+- for a WORM, zip should create temp file only when updating; new archives
+ should be created directly.
+- APPNOTE.TXT specifies "4) The entries in the central directory may
+ not necessarily be in the same order that files appear in the zipfile"
+ but readzipfile() relies on same order. (new read does not, and now
+ the read for -FF searches for central directory matches rather than
+ rely on the order)
+- on Mac, MPW C 3.3.1 requires #if (a || b) ["#if a || b" taken as "#if a"]
+- on Unix, let -S be "include non-regular files without reading from them"
+ (as pkzip on Unix). This requires unzip support.
+- zip -l should do ebcdic->ascii translation on CMS and MVS
+- zip as subroutine (zdig/241) (some work done on this)
+- accept k and M in zipsplit
+- store / (part of file name) as ! in OS/2 (problem only with -E ?)
+- in addition to -l (LF to CR LF) and -ll (CR LF to LF) add -lc
+ (LF to CR LF but CR LF remains unchanged)
+
+Known bugs:
+
+- On VMS, zip fails reading some files with "byte record too large for
+ user's buffer". You must use the "-V" option for such files.
+ (many changes to VMS so may be fixed)
+
+- on MSDOS, zip386.exe does not like "zip -bc: foo ..."
+
+- on MSDOS, zip386.exe is sometimes much slower than zip.exe. This is
+ probably a problem with DJGPP (to be investigated).
+
+- on NT with C shell, zip should not do file name expansion again.
+
+- zip zipfile ... ignores existing zipfile if name does not have an extension
+ (except for the -A option, generally used on self-extracting files).
+ (archives should probably have extensions. Things like archive.jar work)
+
+- For an sfx file without extension, "zip -A sfx" works but "zip sfx -A"
+ doesn't. (because options were required first, but now both OK)
+
+- When storing files in a zipfile (-0), zip marks all of them as binary.
+
+- On VMS, some indexed files are not restored correctly after zip -V and unzip.
+ (This is now known to be a problem of UnZip. The workaround for Zip 2.2
+ and newer is to use PK-style VMS extra fields; this is now the default.
+ NOTE that UnZip 5.32 has been fixed [971019]!) (many VMS changes so
+ this may be fixed)
+
+- zip and unzip should use the same pattern matching rules, particularly
+ on MSDOS and OS/2. On OS/2, "zip foo *.*" should also match files
+ without extension.
+ Partially DONE (OS/2 "*.*" matches "*".)
+
+- there should be a way to avoid updating archive members (only addition
+ of new files allowed)
diff --git a/USexport.msg b/USexport.msg
new file mode 100644
index 0000000..068aa9f
--- /dev/null
+++ b/USexport.msg
@@ -0,0 +1,75 @@
+From roelofs (at) sonic.net Tue Jun 17 08:26:55 2003
+Date: Tue, 17 Jun 2003 08:26:50 -0700
+Message-Id: <200306171526.h5HFQoaw014091 (at) bolt.sonic.net>
+From: Greg Roelofs <newt (at) pobox.com>
+Reply-To: Greg Roelofs <newt (at) pobox.com>
+To: crypt (at) bis.doc.gov, enc (at) ncsc.mil, web_site (at) bis.doc.gov
+Subject: TSU NOTIFICATION - Encryption (Info-ZIP zcrypt.zip)
+Cc: newt (at) pobox.com, zip-bugs (at) lists.wku.edu
+
+
+ SUBMISSION TYPE: TSU
+ SUBMITTED BY: Greg Roelofs
+ SUBMITTED FOR: the Info-ZIP group (an informal, Internet-based
+ collection of software developers with the contact
+ address given in next item)
+ POINT OF CONTACT: Zip-Bugs (at) lists.wku.edu
+ PHONE and/or FAX: n/a
+ MANUFACTURER: n/a
+ PRODUCT NAME/MODEL #: zcrypt
+ ECCN: 5D002
+
+ NOTIFICATION:
+
+ ftp://ftp.info-zip.org/pub/infozip/src/zcrypt.zip
+
+
+FURTHER COMMENTS:
+
+(1) This notice is being sent in order to ensure that we may legally
+ take advantage of the 6 June 2002 amendment to 740.13 regarding
+ "corresponding object code." The encryption code in question is
+ unchanged since our original notification of 9 April 2000, appended
+ below and also reproduced within the above zcrypt.zip archive.
+ (Indeed, there has been no change to the core encryption/decryption
+ code in well over five years.)
+
+(2) The (larger) source archives for Zip, UnZip, MacZip, WiZ, and
+ potentially other packages, currently available in the same ftp
+ directory given above, also contain (or may contain) copies of
+ the same zcrypt source code.
+
+(3) ftp.info-zip.org currently points to a site in Germany, so techni-
+ cally it is not involved in "US export" in any direct way. However,
+ we encourage other sites to "mirror" our software, and some of these
+ mirror sites may be US-based (and therefore involved in reexport of
+ the code in question). In addition, some Info-ZIP members reside in
+ the US, and www.info-zip.org currently points to a site in Kentucky.
+
+
+ORIGINAL NOTIFICATION:
+
+From roelofs (at) sonic.net Sun Apr 9 15:11:45 2000
+Date: Sun, 9 Apr 2000 15:11:27 -0700
+Message-Id: <200004092211.PAA20023 (at) sonic.net>
+From: Greg Roelofs <newt (at) pobox.com>
+To: crypt (at) bxa.doc.gov
+Subject: notice of export of unrestricted encryption source code
+Cc: newt (at) pobox.com, zip-bugs (at) lists.wku.edu
+
+The Info-ZIP group, an informal, Internet-based collection of software
+developers with contact address Zip-Bugs (at) lists.wku.edu, hereby notifies
+the US Bureau of Export Administration (BXA) of the posting of freely
+available encryption source code on the Internet under License Exception
+TSU, to commence later today at this location:
+
+ ftp://ftp.info-zip.org/pub/infozip/src/zcrypt.zip
+
+This notification is in accordance with section 740.13(e) of the amended
+Export Administration Regulations, as published in the 14 January 2000
+issue of the Federal Register.
+
+--
+Greg Roelofs newt (at) pobox.com http://pobox.com/~newt/
+Newtware, PNG Group, Info-ZIP, Philips Research, ...
+
diff --git a/WHATSNEW b/WHATSNEW
new file mode 100644
index 0000000..9e8d52b
--- /dev/null
+++ b/WHATSNEW
@@ -0,0 +1,333 @@
+What's New
+
+Last updated 1 July 2008
+
+This file is the full list of new features and major changes for Zip 3.0
+by beta release. See the announcement file zip30.ann for a quick summary
+of all features and changes in Zip 3.0. Also see the file README for
+release information, INSTALL for installation procedures, and the manual
+pages zip.txt, zipsplit.txt, zipcloak.txt, and zipnote.txt for how to use
+the new features. The file CHANGES has all the day-to-day changes made
+during development.
+
+
+Below are some of the more significant items on the list for Zip 3.1
+(see ToDo for a more complete list):
+
+- AES encryption.
+- Extended attributes for Windows, Linux, and Mac OS X.
+- Support -d@ for deleting list of files.
+- Decide if -R, -i and -x should use external rather than internal patterns.
+- Though Unicode paths have been implemented and tested, Unicode comments
+ are not yet supported (except for comments on UTF-8 native systems which
+ are supported).
+- Verbose mode -v may still need work.
+- When pattern is directory add end / automatically.
+- Add C# example for Zip 3.0 (need to be converted to new DLLs) - original
+ C# example added with note.
+- Path Prefix maybe, so entries added to an archive can have a directory
+ path string prepended to each path.
+- UNC path support maybe.
+- Support for other languages maybe.
+- Send in your suggestions.
+- ...
+
+
+MAJOR CHANGES BY BETA VERSION
+-----------------------------
+
+New things in Zip 3.0 since Zip 3.0h:
+
+- Unicode fixes.
+- Test and fix various ports as needed.
+- Update Win32 resource to support more Windows ports.
+- Add djgpp 2.x makefile that includes bzip2.
+- Add Win32 version resource to Win32 executable.
+- Bug fixes.
+- Documentation updates.
+- Package for release.
+
+
+New things in Zip 3.0h
+
+- Allow -@ and -x to work together.
+- Unicode code cleanup.
+- Allow forcing use of UTF-8 storage in standard path and comment.
+- Update symbolic link checks.
+- Add support for storing 32-bit UIDs/GIDs using new extra field.
+ Backward compatible support for the old 16-bit UID/GID extra field
+ remains if Zip is compiled on an OS that has 16-bit UID/GID
+ storage.
+- Update VMS notes.
+- Directory scan using -AS (include only files with Windows archive
+ bit set) now ignores archive bit on directories to include all files
+ with archive bit set in all directories. Also, to avoid empty
+ directories being created, -AS now does not store directory
+ entries.
+- Add Unix IBM support.
+- Change -W to -ws to free -W for later use.
+- Fix large file support for MinGW.
+- Fix large file support for bzip2.
+- Fix compile error in ZipCloak when UNICODE_SUPPORT is not enabled.
+- Fix Unicode bug in ZipCloak involving Unicode paths.
+- Long Unicode escapes changed from #Lxxxxxxxx to #Lxxxxxx to shorten
+ paths with escaped Unicode.
+- Bug fixes.
+
+
+New things in Zip 3.0g
+
+- Add split support to VB project for Zip64.
+- Disable reading of Unix FIFOs unless new -FI option used to avoid an
+ archiving operation stopping when it hits an active unfed FIFO.
+- The "[list]" wildcard expression (regular expression matching of any
+ character or range of characters in list) is now disabled on DOS and
+ Windows as it has caused confusion when filenames have [ and ] in
+ them. The new -RE option reenables it.
+- Add negation to many display options such as -dc and -db.
+- Allow -FF to read and fix archives having local entries that appear
+ after central directory entries.
+- Bug fixes.
+
+
+New things in Zip 3.0f
+
+- bzip2 - The bzip2 compression method looks supported for at least
+ Windows, Unix, and VMS using the bzip2 library. A new option, -Z cm,
+ selects the compression method.
+
+- Split archives - Can now use -s to create a split archive. The
+ default is to update split files as the archive is being written,
+ which requires all splits to remain open until the archive is done.
+ This should be no problem when writing the archive to a hard drive,
+ for example, and this approach creates archives that should be
+ supported by all unzips that support splits. Adding the -sp option
+ enables split pause mode that instead writes splits that do not
+ need updating and pauses Zip after each split. This allows splits
+ to be written directly to removable media, however -sp archives
+ may not be as universally compatible.
+
+- Unicode support - Zip now stores Unicode paths that should be more
+ portable across character sets and languages. The unzip must have
+ Unicode support enabled or the Unicode paths are ignored. If
+ reading an archive with Unicode paths, unsupported characters are
+ replaced by #Uxxxx and #Lxxxxxxxx escapes in the file name. Option
+ -UN controls how Unicode is handled. Also, on systems where the
+ current character set is UTF-8, preliminary support for the new
+ General Purpose Bit Flag, bit 11, UTF-8 flag, that indicates UTF-8
+ is stored in the path and comment fields is implemented for paths.
+- Unicode on Win32 - On WIN32 systems that support the wide character
+ calls (mainly NT and later systems using NTFS), when UNICODE SUPPORT
+ is enabled Zip will now do directory scans using Unicode and convert
+ the Unicode paths to the local character set for storage in the standard
+ path field and store UTF-8 in the Unicode extra field. This allows
+ directory scans to complete successfully regardless of the character
+ set the path is in. On Win9x systems wide character scans are not
+ generally supported and Zip automatically uses a local character scan
+ instead.
+
+- Keep extra fields option - The default operation has been, and continues
+ to be, to read then strip old extra fields when reading entries from an
+ existing archive and then recreate the extra fields that Zip knows about.
+ Extra fields specific to each operating system get added by default also.
+ The new option -X- (negated -X) keeps any old extra fields, copying
+ them to the updated archive unchanged (unless Zip has updated them).
+ The unnegated -X still strips most all extra fields except Zip64,
+ Unicode, and UT time.
+
+- License - minor updates to the license.
+
+- Windows OEM - When compiled with WIN32_OEM (the default for WIN32),
+ Zip on WIN32 now stores OEM paths, which should be more compatible
+ with other zips and should fix some character set problems.
+- Windows Archive Bit support - On Windows can now use new -AS
+ (include if archive bit set) option to select files with the DOS
+ archive bit set and use new -AC (clear archive bits) option to clear
+ the archive bits on files after the archive has been created.
+ But -DF is probably better.
+
+- Difference mode - A new option -DF (--dif) creates an output archive
+ that includes only files changed or new since the input archive was
+ created. Can use to create incremental backups.
+- File Sync - The new option -FS enables File Sync, a new mode that
+ synchronizes the entries in an archive with the files on the file
+ system, adding updating, and deleting entries as needed. This
+ should create the same results as creating a new archive, but
+ since existing entries are copied, may be much faster.
+
+- Copy Mode - A new --out option allows creating a new archive with a
+ different name than the input archive, leaving the input archive
+ unchanged. This allows updating split archives. It also allows
+ for a new copy mode to select entries in one archive and copy them
+ directly to a new archive.
+- Empty archives - Now an empty archive is created when -i or -i@ is used
+ and the file patterns given do not match anything. This has been
+ requested to support scripts.
+
+- Global dots - A new -dg option now displays progress dots as -dd does,
+ but instead of displaying them for each file, the dots track the total
+ bytes read for the archive. The -dg option also works when -q is used
+ to disable most output, which allows for something like zip -qdgds 100m
+ to be used to not display specific files but display a dot every 100 MB
+ as a global status.
+- Date range - Can now use -t and -tt to set a date range
+- Fix options - Option -F redone and can recover files from an archive
+ with a mostly complete central directory more reliably, but no longer
+ can handle truncated archives. Option -FF redone and now can salvage
+ files from slightly more damaged archives, including truncated archives.
+ In some ways -F is less powerful but more stable than it was and -FF will
+ be needed where -F in Zip 2.32 was enough. One big change is -F and -FF
+ both now support split archives.
+- Console writing - Updates to how messages are written to the console have
+ been made including more consistent handling of line breaks.
+- Show Files options - Option -sf lists the files that would be operated
+ on. This option can be used alone to list the files in an archive.
+ Also see options -su and -sU for showing Unicode paths.
+- UnZip Check - Now check that UnZip 6.00 or later is being used for
+ unzip if testing a Zip64 archive. A new option -TT can be used to set
+ the unzip to use with the -T check. Currently UnZip does not support
+ split archives so split archives can't be tested by UnZip.
+- Streaming - Directories are now handled better when streaming.
+- Case matching - Normally all matching against archive entries is case
+ sensitive, so *.BAR will not match or find foo.bar in an archive
+ when deleting, copying, or freshening entries (deleting and copying
+ only on VMS). New option -ic (--ignore-case) enables case insensitive
+ matching. Currently -ic is only implemented on WIN32 and VMS.
+
+- Delete date bug fixed - Bug when using -d to delete files while
+ using -t or -tt to select the files based on date is fixed
+- Large file encryption bug fixed - Fix for bug that very rarely
+ results in bad data being stored when deflating and encrypting
+ uncompressable data and resulting in CRC errors when extracting,
+ but the chance of error increases with file size (thanks to
+ WinZip for finding this bug). See CHANGES for details.
+
+
+New things in Zip 3.0e
+
+- Bugs described in Debian patches 004 (unix configure script update) and
+ 005 (large path bug) fixed
+- Various fixes
+- Add optional running stats and also end stats if not all files could
+ be read
+- Options -l and -ll now do quick binary check on first buffer and skip
+ formatting if first buffer has binary - still check at end to note
+ if formatting was done on file that was later determined to be binary,
+ but now potential file corruption is generally avoided
+- Main binary check now uses new algorithm that should also treat UTF-8 and
+ other similar encodings as text, allowing proper line end translation
+ for UTF-8 files
+- When output is not updatable by seeking back and Zip64 is enabled, output
+ is forced to Zip64 to avoid possible later need for Zip64 when not enabled
+- More work on splits, but still not usable
+- Fixes for djgpp
+- Add log file capability to save all errors and optionally messages
+- Add code to test for a Zip64 archive when compiled without Zip64 support
+- New VC6 projects for Win32 and WinDLL
+- Updates to extended help
+- Changes to force-zip64 option
+- ZE_BIG error now given also for files too big to read or write
+- Fix file delete bug
+- Update license
+- Update export documentation
+- Add VMS extended filename support
+- Add directory traversal improvements, some for Win32 ports and some for
+ all ports, that can result in a 10 times increase in speed in some cases
+
+
+New things in Zip 3.0d
+
+- Some large file crypt fixes
+- Some updates to support WiZ
+- On VMS, changed -V (/VMS) processing to truncate file at EOF, allowing
+ greater compatability with non-VMS systems. New -VV (/VMS=ALL) option
+ saves all allocated blocks in a file. (Previously, -V did neither.)
+- On VMS, pushed 2GB file size limit with -V out to 4GB
+- On VMS (recent, non-VAX), with SET PROCESS /PARSE = EXTEND,
+ command-line case is preserved. This obviates quoting upper-case
+ options, like -V, when enabled
+- On VMS, fixed problems with mixed-case directory names. Also changed
+ to keep ODS5 extended file name escape characters ("^") out of the
+ archived names in simple cases
+- Changes to the display dots
+- Option -W should now force wildcard matching to not cross directory
+ separators. For example, a/b*r/d will match a/bar/d but not a/ba/r/d
+- Option -nw should turn off all wildcard matching so foo[bar] is matched
+ literally and [bar] is not considered a regular expression
+- Atheos port
+- Debugging of Unix and VMS large file ports. Most features may work now
+ on these ports for large files. Still need to fix 2 GB to 4 GB when not
+ compiled with large file support
+- On VMS, added an open callback function which (where supported) senses
+ the process RMS_DEFAULT values for file extend quantity (deq)
+ multi-block count (mbc), and multi-buffer count (mbf), and sets the
+ FAB/RAB parameters accordingly. The default deq is now much larger
+ than before (16384 blocks, was none), and the default mbc is now 127
+ (up from 64), speeding creation of a large archive file. The "-v"
+ option shows some of the activity. On old VMS versions, RMS_DEFAULT
+ sensing (GETJPI) fails (silently, without "-v"), and no changes will
+ be made. Even there, (DCL) SET RMS /EXTEND = <big> can help
+ performance. RMS_DEFAULT values override built-in default values.
+
+
+New things in Zip 3.0c
+
+- Converted to using 64-bit file environment instead of transitional functions
+ like fseeko64 for ports that support it
+- Added "--" argument to read all following arguments as paths
+- Second help page added
+- Binary detection adjusted from 20% binary is binary to 2%
+- When -R and -i used together now -i has precedence over -R
+- Archive names with spaces can now be tested on MSDOS and Win32
+
+
+New things in Zip 3.0b
+
+- Fixed ifdefs so can test base code by compiling with NO_LARGE_FILE_SUPPORT, then
+ compiling with NO_ZIP64_SUPPORT to test 64-bit file calls (if port enables) but
+ otherwise use base code, and compiling normally to enable Zip64 code
+- Unix Zip64 fixes - should now be able to create and read large files
+- WinDLL changes to support Zip64. Zip 3.0 dll named Zip32z64.dll
+- New VB example to show use of Zip32z64.dll
+- New options -sc (show final command line and exit) and -sd (show each
+ step zip is doing, a little different than verbose which is still there) added
+ to help debug but both or at least -sd might go away in the release
+- Some minor posted bugs fixed (see Changes)
+
+
+New things in Zip 3.0a
+
+- Initial Zip64 support allowing large files and large numbers of files
+- New command line processor
+- Other changes, see file Changes
+
+
+Note: Zip 2.4 was never released. That code was the start of the Zip 3.0
+effort above.
+
+
+New things in Zip 2.3
+
+- IBM OS/390 port (Unix like, but EBCDIC) by Paul von Behren
+- Apple Macintosh (MACOS) port by Dirk Haase
+- Theos port by Jean-Michel Dubois
+- Multibyte characterset support by Yoshioka Tsuneo
+- Support for ISO 8601 date format with -t and -tt options
+- Info-ZIP license
+
+
+New things in Zip 2.2
+
+- BEOS port by Chris Herborth
+- QDOS port by Jonathan Hudson
+- TANDEM port by Dave Smith
+- WINDLL port (16-bit Win 3.x and 32-bit WinNT/Win95) by Mike White
+- SYSV packages support by John Bush
+- zip -P SeCrEt encrypts entries in the zip file with password SeCrEt
+ (WARNING: THIS IS INSECURE, use at your own risk)
+- zip -R recurses into subdirectories of current dir like "PKZIP -rP"
+- zip -x@exclude.lst excludes files specified in the file exclude.lst
+- zip -i@include.lst includes files specified in the file include.lst
+- zip -@ only handles one filename per line, but supports whitespace in names
+- zip -t mmddyyyy, 4 digit year number for uniqueness of years beyond 2000
+- zip -tt mmddyyyy only includes files before a specified date
diff --git a/WHERE b/WHERE
new file mode 100644
index 0000000..94a0d55
--- /dev/null
+++ b/WHERE
@@ -0,0 +1,261 @@
+__________________________________________________________________________
+
+ This is the Info-ZIP file ``WHERE,'' last updated on 1 March 2005.
+__________________________________________________________________________
+
+ This file is out of date. We plan to update the structure of the ftp
+ site shortly and should be updating this file as soon as that's done.
+
+ The latest version of this file can be found online at:
+
+ ftp://ftp.info-zip.org/pub/infozip/doc/WHERE
+
+ Note that some ftp sites may not yet have the latest versions of Zip
+ and UnZip when you read this. The latest versions always appear in
+ ftp://ftp.info-zip.org/pub/infozip/ (and subdirectories thereof) first,
+ except for encryption binaries, which always appear in
+ ftp://ftp.icce.rug.nl/infozip/ (and subdirectories) first.
+
+ IF YOU FIND AN ERROR: please let us know! We don't have time to
+ check each and every site personally (or even collectively), so any
+ number of the sites listed below may have moved or disappeared en-
+ tirely. E-mail to Zip-Bugs@lists.wku.edu and we'll update this file.
+__________________________________________________________________________
+
+
+Info-ZIP's home WWW site is listed on Yahoo and is at:
+
+ ftp://ftp.info-zip.org/pub/infozip/Info-ZIP.html (master version)
+ http://ftp.info-zip.org/pub/infozip/ (master version)
+ http://www.info-zip.org/
+
+Note that the old sites at http://www.cdrom.com/pub/infozip/ and
+http://www.freesoftware.com/pub/infozip are PERMANENTLY BROKEN. They
+cannot be updated or removed, apparently.
+
+The Zip and UnZip pages have links to most known mirror sites carrying our
+source and/or binary distributions, and they generally are more up-to-date
+and have better information than what you are reading:
+
+ ftp://ftp.info-zip.org/pub/infozip/Zip.html
+ ftp://ftp.info-zip.org/pub/infozip/UnZip.html
+
+The related zlib package by Info-ZIP's Jean-loup Gailly and Mark Adler is at:
+
+ http://www.zlib.net/
+
+Source-code archives for Info-ZIP's portable Zip, UnZip, and related
+utilities:
+
+ zip231.zip Zip 2.31 (deflation; includes zipnote/zipsplit/zipcloak)
+ zip231.tar.Z ditto, compress'd tar format
+
+ zip11.zip Zip 1.1 (shrinking, implosion; compatible w. PKUNZIP 1.1)
+ zip11.tar.Z ditto, compress'd tar format
+
+ unzip552.zip UnZip 5.52 (all methods[*]; unzip/funzip/unzipsfx/zipgrep)
+ unzip552.tar.gz ditto, gzip'd tar format
+ unzip552.tar.Z ditto, compress'd tar format
+
+ unred552.zip UnZip 5.52 add-on, contains copyrighted unreduce support
+
+ zcrypt29.zip encryption support for Zip 2.3[**]
+ zcrypt10.zip encryption support for Zip 1.1
+
+ MacZip106src.zip contains all the GUI stuff and the project files to build
+ the MacZip main-app. To build MacZip successfully, both
+ the Zip 2.31 and UnZip 5.52 sources are required, too.
+
+ wiz502.zip WiZ 5.02, Windows 9x/NT GUI front-end for Info-ZIP DLLs
+ wiz502+dlls.zip WiZ 5.02, Windows 9x/NT GUI front-end plus DLL sources
+
+[*] Unreducing is disabled by default, but is available as add-on.
+ As of July 2004, Unisys's LZW patent was expired worldwide, and
+ unshrinking is turned on by default since the release of UnZip 5.52.
+ See UnZip's INSTALL file for details.
+
+[**] As of January 2000, US export regulations were amended to allow export
+ of free encryption source code from the US. As of June 2002, these
+ regulations were further relaxed to allow export of encryption binaries
+ associated with free encryption source code. The Zip 2.31, UnZip 5.52
+ and Wiz 5.02 archives now include full crypto source code. As of the
+ Zip 2.31 release, all official binaries include encryption support; the
+ former "zcr" archives ceased to exist.
+ (Note that restrictions may still exist in other countries, of course.)
+
+Executables archives (and related files) for Info-ZIP's software; not all
+of these will be immediately available due to lack of access to appropriate
+systems on the part of Info-ZIP members.
+
+ zip231x.zip MSDOS executables and docs
+ zip231x1.zip OS/2 1.x (16-bit) executables and docs
+ zip231x2.zip OS/2 2/3/4.x (32-bit) executables and docs
+ zip231xA.zip Amiga executables and docs
+ zip231xB.zip BeOS executables and docs
+ zip231xC.zip VM/CMS executable and docs
+ zip231xK.zip Tandem NSK executables and docs
+ zip231xM.xmit MVS classic executable
+ zip231xM-docs.zip MVS classic port, docs only
+ zip231dN.zip WinNT/Win9x (Intel) DLL, header files, docs
+ zip231xN.zip WinNT/Win9x (Intel) executables and docs
+ zip231xN-axp.zip WinNT (Alpha AXP) executables and docs
+ zip231xN-mip.zip WinNT (MIPS R4000) executables and docs
+ zip231xN-ppc.zip WinNT (PowerPC) executables and docs
+ zip231xO.zip IBM OS/390 Open Edition binaries and docs
+ zip231xQ.zip SMS/QDOS executables and docs
+ zip231xR.zip Acorn RISC OS executables and docs
+ zip231xT.zip Atari TOS executables and docs
+ zip231-vms-axp-obj.zip
+ VMS (Alpha AXP) object libs, link procedure and docs
+ zip231-vms-axp-exe.zip
+ VMS (Alpha AXP) executables for VMS 6.1 or later and docs
+ zip231-vms-vax-decc-obj.zip
+ VMS (VAX) object libs (new DEC C), link procedure and docs
+ zip231-vms-vax-decc-exe.zip
+ VMS (VAX) executables (DEC C) for VMS 6.1 or later; docs
+ zip231-vms-vax-vaxc-obj.zip
+ VMS (VAX) object libs (old VAX C), link procedure and docs
+ zip231x.hqx Macintosh BinHex'd executables and docs
+
+ unz552x.exe MSDOS self-extracting executable (16-bit unzip, ..., docs)
+ unz552x3.exe MSDOS self-extracting executable (16-, 32-bit unzip, docs)
+ unz552x1.exe OS/2 1.x (16-bit) self-extracting executables and docs
+ unz552x2.exe OS/2 2/3/4.x (32-bit) self-extracting executables and docs
+ unz552d2.zip OS/2 2/3/4.x (32-bit) DLL, header file, demo exe and docs
+ unz552xA.ami Amiga self-extracting executables and docs
+ unz552xA.lha Amiga executables and docs, LHa archive
+ unz552xB.sfx BeOS self-extracting executables and docs
+ unz552xB.tar.gz BeOS executables and docs, gzip'd tar archive
+ unz552xC.mod VM/CMS executable module in "packed" format
+ unz552xC-docs.zip VM/CMS docs, only
+ unz552xF.zip FlexOS executable and docs
+ unz552xK.zip Tandem NSK executable and docs
+ unz552xM.xmit MVS classic executable
+ unz552xM-docs.zip MVS classic port, docs only
+ unz552dN.zip NT4/W2K/XP/2K3/W9x (32-bit Intel) DLL, header files, docs
+ unz552xN.exe NT/2K/XP/2K3/W9x self-extracting i386 executables and docs
+ unz552xN-axp.exe WinNT (Alpha AXP) self-extracting executables and docs
+ unz552xN-mip.exe WinNT (MIPS R4000) self-extracting executables and docs
+ unz552xN-ppc.exe WinNT (PowerPC) self-extracting executables and docs
+ unz552xQ.sfx SMS/QDOS self-extracting executables and docs
+ unz552xO.tar.Z IBM OS/390 Open edition (Unix-like), exes and docs
+ unz552xR.exe Acorn RISC OS self-extracting executables and docs
+ unz552xR.spk Acorn RISC OS Spark'd executables and docs
+ unz552xT.tos Atari TOS self-extracting executables and docs
+ unz552x-vms-axp-obj.bck VMS backup saveset,
+ contains UnZip (Alpha) obj libs, link procedure, docs
+ unz552x-vms-axp-obj.exe VMS (Alpha AXP) SFX archive (statically linked),
+ contains UnZip (Alpha) obj libs, link procedure, docs
+ unz552x-vms-axp-exe.exe VMS (Alpha AXP) SFX archive (dynamically linked),
+ contains UnZip (Alpha AXP, DEC C) executables and docs,
+ smaller than object archive, but requires VMS 6.1
+ unz552x-vms-vax-decc-obj.bck VMS backup saveset,
+ contains UnZip (new DEC C) obj libs, link procedure, docs
+ unz552x-vms-vax-decc-obj.exe VMS (VAX) SFX archive (statically linked),
+ contains UnZip (new DEC C) obj libs, link procedure, docs
+ unz552x-vms-vax-decc-exe.exe VMS (VAX) SFX archive (dynamically linked),
+ contains UnZip (new DEC C) executables and docs,
+ smaller than object archive, but requires VMS 6.1
+ unz552x-vms-vax-vaxc-obj.bck VMS backup saveset,
+ contains UnZip (old VAX C) obj libs, link procedure, docs
+ unz552x-vms-vax-vaxc-obj.exe VMS (VAX) SFX archive (statically linked),
+ contains UnZip (old VAX C) obj libs, link procedure, docs
+ unz552x.hqx Macintosh BinHex'd executables and docs for unzip
+ (unz552x.tar.{Z,gz} Unix exes/docs for Solaris 2.x, SCO Unix, Linux, etc.,
+ depending on directory/location; generally only provided
+ in cases where the OS does *not* ship with a bundled C
+ compiler)
+
+ MacZip106nc.hqx Macintosh combined Zip&UnZip application with GUI,
+ executables and docs (no encryption)
+ MacZip106c.hqx Macintosh combined Zip&UnZip application with GUI,
+ executables and docs (with encryption)
+
+ wiz502xN.exe WiZ 5.02 32-bit (Win9x/NT/2K/XP/2K3) app+docs (self-extr.)
+
+ UnzpHist.zip complete changes-history of UnZip and its precursors
+ ZipHist.zip complete changes-history of Zip
+
+ftp/web sites for the US-exportable sources and executables:
+
+ NOTE: Look for the Info-ZIP file names given above (not PKWARE or third-
+ party stuff) in the following locations. Some sites like to use slightly
+ different names, such as zip-2.31.tar.gz instead of zip231.tar.Z.
+
+ ftp://ftp.info-zip.org/pub/infozip/ [THE INFO-ZIP HOME SITE]
+ ftp://sunsite.doc.ic.ac.uk/packages/zip/ [MIRRORS THE INFO-ZIP HOME SITE]
+ ftp://unix.hensa.ac.uk/mirrors/uunet/pub/archiving/zip/
+
+ ftp://ftp.cmdl.noaa.gov/aerosol/doc/archiver/{all,dos,os2,mac,vax_alpha}/
+ ftp://garbo.uwasa.fi/pc/arcers/ [AND OTHER GARBO MIRRORS]
+ ftp://garbo.uwasa.fi/unix/arcers/ [AND OTHER GARBO MIRRORS]
+ ftp://ftp.elf.stuba.sk/pub/pc/pack/ [AND OTHER STUBA MIRRORS]
+ ftp://ftp-os2.cdrom.com/pub/os2/archiver/
+ ftp://ftp-os2.nmsu.edu/os2/archiver/
+ ftp://ftp.informatik.tu-muenchen.de/pub/comp/os/os2/archiver/
+ ftp://sumex-aim.stanford.edu/info-mac/cmp/
+ ftp://ftp.wustl.edu/pub/aminet/util/arc/ [AND OTHER AMINET MIRRORS]
+ ftp://atari.archive.umich.edu/pub/Archivers/ [AND OTHER UMICH MIRRORS]
+ http://www.umich.edu/~archive/atari/Archivers/
+ ftp://jake.educom.com.au/pub/infozip/acorn/ [Acorn RISC OS]
+ http://www.sitec.net/maczip/ [MacZip port]
+
+ftp/web sites for the encryption and decryption sources and/or executables:
+
+ Outside the US:
+ ftp://ftp.info-zip.org/pub/infozip/ [THE INFO-ZIP HOME SITE]
+ ftp://ftp.icce.rug.nl/infozip/ [THE INFO-ZIP ENCRYPTION HOME SITE]
+ ftp://ftp.elf.stuba.sk/pub/pc/pack/
+ ftp://garbo.uwasa.fi/pc/arcers/
+ ftp://ftp.inria.fr/system/arch-compr/
+ ftp://ftp.leo.org/pub/comp/os/os2/leo/archiver/
+ (mail server at ftp-mailer@ftp.leo.org)
+
+ ftp://ftp.win.tue.nl/pub/compression/zip/
+ ftp://ftp.uni-erlangen.de/pub/pc/msdos/arc-utils/zip/
+
+
+The primary distribution site for the MacZip port can be found at:
+
+ http://www.sitec.net/maczip/
+
+ftp sites for VMS-format Zip and UnZip packages (sources, object files and
+executables, no encryption/decryption--see also "Mail servers" section below):
+
+ ftp.spc.edu [192.107.46.27] and ftp.wku.edu:
+
+ [.MACRO32]AAAREADME.TXT
+ [.MACRO32.SAVESETS]UNZIP.BCK or UNZIP.ZIP (if already have older version)
+ [.MACRO32.SAVESETS]ZIP.ZIP
+
+To find other ftp/web sites:
+
+ The "archie" ftp database utility can be used to find an ftp site near
+ you (although the command-line versions always seem to find old ver-
+ sions...the `FTPsearch' server at http://ftpsearch.ntnu.no/ftpsearch
+ --formerly `Archie 95'--is quite up-to-date, however). Or check a stan-
+ dard WWW search engine like AltaVista (http://www.altavista.digital.com/)
+ or Yahoo (http://www.yahoo.com/). If you don't know how to use these,
+ DON'T ASK US--read the web sites' help pages or check the Usenet groups
+ news.announce.newusers or news.answers or some such, or ask your system
+ administrator.
+
+Mail servers:
+
+ To get the encryption sources by e-mail, send the following commands
+ to ftp-mailer@informatik.tu-muenchen.de:
+
+ get /pub/comp/os/os2/archiver/zcrypt29.zip
+ quit
+
+ To get the VMS Zip/UnZip package by e-mail, send the following
+ commands in the body of a mail message to fileserv@wku.edu (the
+ "HELP" command is also accepted):
+
+ SEND FILESERV_TOOLS
+ SEND UNZIP
+ SEND ZIP
+
+ To get Atari executables by e-mail, send a message to
+ atari@atari.archive.umich.edu for information about the mail server.
+__________________________________________________________________________
diff --git a/acorn/GMakefile b/acorn/GMakefile
new file mode 100644
index 0000000..01842c4
--- /dev/null
+++ b/acorn/GMakefile
@@ -0,0 +1,130 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# add -g to CC to debug
+# add -d to BIND to debug
+CC = gcc -mlibscl
+BIND = $(CC)
+AS = $(CC) -c
+ASM = AS
+SQUEEZE = squeeze -v
+E =
+
+# flags
+# CFLAGS flags for C compile
+# LFLAGS1 flags after output file spec, before obj file list
+# LFLAGS2 flags after obj file list (libraries, etc)
+#
+LIB =
+CFLAGS = -O2 -mthrowback -DASMV
+ASMFLAGS = -throwback -objasm -upper
+LFLAGS1 =
+LFLAGS2 = $(LIB)
+
+# Uncomment the following line to enable support for Unix
+# Extra Field (Timezone)
+#CFLAGS = $(CFLAGS) -DUSE_EF_UT_TIME
+
+# object file lists
+OBJZ = o.zip o.zipfile o.zipup o.fileio o.util o.globals o.crc32 \
+ o.crypt o.ttyio o.riscos o.acornzip o.swiven
+
+OBJI = o.deflate o.trees
+OBJA = o.match o.sendbits
+OBJU = o.zipfile_ o.fileio_ o.util_ o.globals o.riscos o.acornzip_ o.swiven
+OBJN = o.zipnote $(OBJU)
+OBJC = o.zipcloak $(OBJU) o.crc32_ o.crypt_ o.ttyio
+OBJS = o.zipsplit $(OBJU)
+
+ZIP_H = h.zip h.ziperr h.tailor acorn.h.osdep acorn.h.riscos acorn.h.swiven
+
+all: zip zipnote zipsplit zipcloak
+
+install: %.zip %.zipnote %.zipsplit %.zipcloak %.acorn.zipsfx \
+ zip zipnote zipsplit zipcloak acorn.zipsfx
+ $(SQUEEZE) zip %.zip
+ $(SQUEEZE) zipnote %.zipnote
+ $(SQUEEZE) zipsplit %.zipsplit
+ $(SQUEEZE) zipcloak %.zipcloak
+ copy acorn.zipsfx %.zipsfx ~CVF
+
+# rules for zip, zipnote, zipcloak and zipsplit
+
+o.api: c.api
+ $(CC) $(CFLAGS) -c c.api -o o.api
+o.crc32: c.crc32 $(ZIP_H) h.crc32
+ $(CC) $(CFLAGS) -c c.crc32 -o o.crc32
+o.crypt: c.crypt $(ZIP_H) h.crypt h.crc32 h.ttyio
+ $(CC) $(CFLAGS) -c c.crypt -o o.crypt
+o.deflate: c.deflate $(ZIP_H)
+ $(CC) $(CFLAGS) -c c.deflate -o o.deflate
+o.fileio: c.fileio $(ZIP_H) h.crc32
+ $(CC) $(CFLAGS) -c c.fileio -o o.fileio
+o.globals: c.globals $(ZIP_H)
+ $(CC) $(CFLAGS) -c c.globals -o o.globals
+o.mktime: c.mktime
+ $(CC) $(CFLAGS) -c c.mktime -o o.mktime
+o.trees: c.trees $(ZIP_H)
+ $(CC) $(CFLAGS) -c c.trees -o o.trees
+o.ttyio: c.ttyio $(ZIP_H) h.crypt
+ $(CC) $(CFLAGS) -c c.ttyio -o o.ttyio
+o.util: c.util $(ZIP_H)
+ $(CC) $(CFLAGS) -c c.util -o o.util
+o.zip: c.zip $(ZIP_H) h.crc32 h.crypt h.revision h.ttyio
+ $(CC) $(CFLAGS) -c c.zip -o o.zip
+o.zipcloak: c.zipcloak $(ZIP_H) h.crc32 h.crypt h.revision h.ttyio
+ $(CC) $(CFLAGS) -c c.zipcloak -o o.zipcloak
+o.zipfile: c.zipfile $(ZIP_H) h.crc32
+ $(CC) $(CFLAGS) -c c.zipfile -o o.zipfile
+o.zipnote: c.zipnote $(ZIP_H) h.revision
+ $(CC) $(CFLAGS) -c c.zipnote -o o.zipnote
+o.zipsplit: c.zipsplit $(ZIP_H) h.revision
+ $(CC) $(CFLAGS) -c c.zipsplit -o o.zipsplit
+o.zipup: c.zipup $(ZIP_H) h.crc32 h.crypt h.revision
+ $(CC) $(CFLAGS) -c c.zipup -o o.zipup
+
+o.crc32_: c.crc32 $(ZIP_H) h.crc32
+ $(CC) $(CFLAGS) -DUTIL -c c.crc32 -o o.crc32_
+o.crypt_: c.crypt $(ZIP_H) h.crypt h.crc32 h.ttyio
+ $(CC) $(CFLAGS) -DUTIL -c c.crypt -o o.crypt_
+o.util_: c.util $(ZIP_H)
+ $(CC) $(CFLAGS) -DUTIL -c c.util -o o.util_
+o.fileio_: c.fileio $(ZIP_H) h.crc32
+ $(CC) $(CFLAGS) -DUTIL -c c.fileio -o o.fileio_
+o.zipfile_: c.zipfile $(ZIP_H) h.crc32
+ $(CC) $(CFLAGS) -DUTIL -c c.zipfile -o o.zipfile_
+o.acornzip_: acorn.c.acornzip $(ZIP_H)
+ $(CC) $(CFLAGS) -I@ -DUTIL -c acorn.c.acornzip -o o.acornzip_
+
+o.riscos: acorn.c.riscos acorn.h.riscos $(ZIP_H)
+ $(CC) $(CFLAGS) -I@ -c acorn.c.riscos -o o.riscos
+
+o.acornzip: acorn.c.acornzip $(ZIP_H)
+ $(CC) $(CFLAGS) -I@ -c acorn.c.acornzip -o o.acornzip
+
+o.match: acorn.s.match
+ $(ASM) $(ASMFLAGS) -I@ acorn.s.match -o o.match
+
+o.sendbits: acorn.s.sendbits
+ $(ASM) $(ASMFLAGS) -I@ acorn.s.sendbits -o o.sendbits
+
+o.swiven: acorn.s.swiven
+ $(ASM) $(ASMFLAGS) -I@ acorn.s.swiven -o o.swiven
+
+zip: $(OBJZ) $(OBJI) $(OBJA)
+ $(BIND) -o zip$(E) $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote: $(OBJN)
+ $(BIND) -o zipnote$(E) $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+ $(BIND) -o zipcloak$(E) $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+ $(BIND) -o zipsplit$(E) $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+clean:
+ remove zip
+ remove zipcloak
+ remove zipsplit
+ remove zipnote
+ create o.!fake! 0
+ wipe o.* ~cf
+
+# end of Makefile
diff --git a/acorn/ReadMe b/acorn/ReadMe
new file mode 100644
index 0000000..41c37a5
--- /dev/null
+++ b/acorn/ReadMe
@@ -0,0 +1,85 @@
+Acorn-specific compile instructions
+-----------------------------------
+
+Use the "RunMe1st" file (it is an Obey file) to convert all the files from
+"filename/[chs]" to "[chs].filename" (so that zip could be easily compiled
+under RISC OS). It will also set the correct makefile.
+
+To compile just set the CSD to the main zip directory and run 'amu'.
+
+Currently only the Acorn C V5 compiler has been tested but probably also
+Acorn C V4 and the Acorn Assembler V2 will be able to compile zip.
+
+The default makefile is configured without the support for the
+Extended Timestamp Extra Field. If you wan to enable it you have to
+add "-DUSE_EF_UT_TIME" to CFLAGS (see makefile). Without the Extended
+Timestamp Field support, zipfiles created by zip are identical to the
+zipfiles created by SparkFS. However, the Extended Timestamp Field can
+be useful if you are going to unzip your zipfiles on a non-RISC OS machine
+since the correct time stamp will be preserved across different timezones.
+Note that in this case, both the SparkFS Extra Field and the Extended
+Timestamp Extra Field will be used, so the zipfiles will still be fully
+compatible with SparkFS and with the RISC OS version of unzip.
+
+The executables-only distributions will be compiled without the support for
+the Extended Timestamp Extra Field. If you need it but you can't compile zip
+yourself, you can contact the authors at the Info-ZIP address who will do it
+for you.
+
+
+Acorn-specific usage instructions
+---------------------------------
+
+An extra option ('I') has been added to the Acorn port: if it is specified
+zip will not consider Image files (eg. DOS partitions or Spark archives when
+SparkFS is loaded) as directories but will store them as single files. This
+means that if you have, say, SparkFS loaded, zipping a Spark archive will
+result in a zipfile containing a directory (and its content) while using the
+'I' option will result in a zipfile containing a Spark archive. Obviously
+this second case will also be obtained (without the 'I' option) if SparkFS
+isn't loaded.
+
+When adding files to a zipfile; to maintain FileCore compliance, all
+files named "file/ext" will be added to the archive as "file.ext".
+This presents no problem if you wish to use unzip to extract them on any
+other machine, as the files are correctly named. This also presents no
+problem if you use unzip for RISC OS, as the files are converted back to
+"file/ext" format. The only problem appears when you use SparkFS to
+decompress the files, as a file called "file.ext" will be extracted as
+"file_ext", not what it was added as. You must be careful about this.
+
+Case Specific. Depending on how you type the command, files will be added
+exactly as named; in this example:
+*zip new/zip newfile
+*zip new/zip NewFile
+*zip new/zip NEWFILE
+will create an archive containing 3 copies of the same Risc OS file 'newfile'
+called 'newfile', 'NewFile' and 'NEWFILE'. Please be careful.
+
+The Acorn port conserves file attributes, including filetype, so if you
+zip on an Acorn, and unzip on another Acorn, filetypes will be maintained
+precisely as if you used uncompressed files. If you de-archive on another
+machine (PC, Mac, Unix etc..), filetypes will be ignored, but the files
+will be identical despite this. This feature is fully compatible with
+SparkFS, so zipfiles created by zip will be correctly uncompressed (including
+filetype, etc.) by SparkFS.
+
+An additional feature went into this port to cope better with C-code
+and extensions. This allows the acorn files "c.foo" to be added to the
+archive as "foo/c", eventually appearing in the archive as "foo.c", allowing
+for better handling of C or C++ code. Example:
+*Set Zip$Exts "dir1:dir2:dir3"
+*zip new/zip dir1.file
+*zip new/zip dir2.help
+*zip new/zip dir3.textfile
+Creates a zipfile new/zip, with entries file.dir1, help.dir2, textfile.dir3.
+The usual settings for Zip$Exts are "h:o:s:c", allowing C code to be added
+to the archive in standard form.
+
+A final note about the Acorn port regards the use of the 'n' option: this is
+used to specify a list of suffixes that will not be compressed (eg. .ZIP,
+since it is already a compressed file). Since RISC OS uses filetypes instead
+of suffixes, this list of suffixes is actually considered as a list of
+filetypes (3 hex digit format). By default, zip doesn't compress filetypes
+DDC (Archive, Spark or Zip), D96 (CFS files) and 68E (PackDir).
+
diff --git a/acorn/ReadMe.GMakefile b/acorn/ReadMe.GMakefile
new file mode 100644
index 0000000..8762cdb
--- /dev/null
+++ b/acorn/ReadMe.GMakefile
@@ -0,0 +1,16 @@
+GMakefile is for use with Acorn RISC OS and the forthcoming
+post-Acorn RISC OS for the compilation of both the current release and
+development versions of zip.
+
+It is recommended that you use gcc 2.95.4 or higher and you will need a
+suitable 'make' utility. Both are available from
+<URL:http://hard-mofo.dsvr.net/gcc/>.
+
+You will need the files gcc.zip and cc1.zip for the C compiler with the
+documentation available in the gccdoc.zip archive. GNU make can be
+found in the utils.zip archive, although most versions of 'make' should be
+fine.
+
+When using gcc, check RunMe1st for two lines which need uncommenting.
+
+
diff --git a/acorn/RunMe1st b/acorn/RunMe1st
new file mode 100644
index 0000000..a330adb
--- /dev/null
+++ b/acorn/RunMe1st
@@ -0,0 +1,23 @@
+| This Obey file prepares the zip port for a Desktop C re-compile.
+| Run it and it will copy all the needed files into the correct
+| place.
+
+| Set the correct type of 'srcrename' so that the only requirement
+| for the user is to set 'RunMe1st' to Obey
+SetType <Obey$Dir>.srcrename FF8
+
+| Run 'srcrename' on the main zip directory with recursion enabled
+/<Obey$Dir>.srcrename -r -e c:h:s:o <Obey$Dir>.^
+
+| Create the 'o' directory
+CDir <Obey$Dir>.^.o
+
+| Put the Makefile in its correct place and set the correct filetype
+Copy <Obey$Dir>.makefile <Obey$Dir>.^.makefile ~C ~V F
+
+| Uncomment the following lines if you're using gcc
+|| Put the Makefile in its correct place and set the correct filetype
+|Copy <Obey$Dir>.GMakefile <Obey$Dir>.^.makefile ~C~VF
+
+SetType <Obey$Dir>.^.makefile FE1
+SetType <Obey$Dir>.zipsfx Obey
diff --git a/acorn/acornzip.c b/acorn/acornzip.c
new file mode 100644
index 0000000..40debc0
--- /dev/null
+++ b/acorn/acornzip.c
@@ -0,0 +1,592 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include <stdlib.h>
+#include <string.h>
+#include "zip.h"
+
+#ifndef UTIL
+
+#define PAD 0
+#define PATH_END '/'
+
+
+local int wild_recurse(char *whole, char *wildtail);
+local int uxtime2acornftime(unsigned *pexadr, unsigned *pldadr, time_t ut);
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+char *readd(DIR *d)
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return (e == NULL ? (char *) NULL : e->d_name);
+}
+
+/* What we have here is a mostly-generic routine using opend()/readd() and */
+/* isshexp()/MATCH() to find all the files matching a multi-part filespec */
+/* using the portable pattern syntax. It shouldn't take too much fiddling */
+/* to make it usable for any other platform that has directory hierarchies */
+/* but no shell-level pattern matching. It works for patterns throughout */
+/* the pathname, such as "foo:*.?/source/x*.[ch]". */
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the */
+/* middle of it. All wildcards to be expanded must come AFTER wildtail. */
+
+local int wild_recurse(whole, wildtail) char *whole; char *wildtail;
+{
+ DIR *dir;
+ char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+ ush newlen, amatch = 0;
+ struct stat statb;
+ int disk_not_mounted=0;
+ int e = ZE_MISS;
+
+ if (!isshexp(wildtail)) {
+ if (stat(whole,&statb)==0 && (statb.st_mode & S_IREAD)!=0) {
+ return procname(whole, 0);
+ } else
+ return ZE_MISS; /* woops, no wildcards! */
+ }
+
+ /* back up thru path components till existing dir found */
+ do {
+ name = wildtail + strlen(wildtail) - 1;
+ for (;;)
+ if (name-- <= wildtail || *name == '.') {
+ subwild = name + 1;
+ plug2 = *subwild;
+ *subwild = 0;
+ break;
+ }
+ if (glue)
+ *glue = plug;
+ glue = subwild;
+ plug = plug2;
+ dir = opendir(whole);
+ } while (!dir && !disk_not_mounted && subwild > wildtail);
+ wildtail = subwild; /* skip past non-wild components */
+
+ if ((subwild = strchr(wildtail + 1, '.')) != NULL) {
+ /* this "+ 1" dodges the ^^^ hole left by *glue == 0 */
+ *(subwild++) = 0; /* wildtail = one component pattern */
+ newlen = strlen(whole) + strlen(subwild) + 32;
+ } else
+ newlen = strlen(whole) + 31;
+ if (!dir || !(newwhole = malloc(newlen))) {
+ if (glue)
+ *glue = plug;
+ e = dir ? ZE_MEM : ZE_MISS;
+ goto ohforgetit;
+ }
+ strcpy(newwhole, whole);
+ newlen = strlen(newwhole);
+ if (glue)
+ *glue = plug; /* repair damage to whole */
+ if (!isshexp(wildtail)) {
+ e = ZE_MISS; /* non-wild name not found */
+ goto ohforgetit;
+ }
+
+ while (name = readd(dir)) {
+ if (MATCH(wildtail, name, 0)) {
+ strcpy(newwhole + newlen, name);
+ if (subwild) {
+ name = newwhole + strlen(newwhole);
+ *(name++) = '.';
+ strcpy(name, subwild);
+ e = wild_recurse(newwhole, name);
+ } else
+ e = procname(newwhole, 0);
+ newwhole[newlen] = 0;
+ if (e == ZE_OK)
+ amatch = 1;
+ else if (e != ZE_MISS)
+ break;
+ }
+ }
+
+ ohforgetit:
+ if (dir) closedir(dir);
+ if (subwild) *--subwild = '.';
+ if (newwhole) free(newwhole);
+ if (e == ZE_MISS && amatch)
+ e = ZE_OK;
+ return e;
+}
+
+int wild(p)
+char *p;
+{
+ char *path;
+ int toret;
+
+ /* special handling of stdin request */
+ if (strcmp(p, "-") == 0) /* if compressing stdin */
+ return newname(p, 0, 0);
+
+ path=p;
+ if (strchr(p, ':')==NULL && *p!='@') {
+ if (!(path=malloc(strlen(p)+3))) {
+ return ZE_MEM;
+ }
+ strcpy(path,"@.");
+ strcat(path,p);
+ }
+
+ toret=wild_recurse(path, path);
+
+ if (path!=p) {
+ free(path);
+ }
+ return toret;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '.')
+ strcpy(a, ".");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ char *tmp;
+ int dosflag;
+ char *lastlastdir=NULL; /* pointer to 2 dirs before... */
+ char *lastdir=NULL; /* pointer to last dir... */
+
+ /* Malloc space for internal name and copy it */
+ if ((tmp = malloc(strlen(x) + 1)) == NULL)
+ return NULL;
+ strcpy(tmp, x);
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ for(t=tmp;*t;t++) {
+ if (*t=='/') {
+ *t='.';
+ }
+ else if (*t=='.') {
+ *t='/';
+ lastlastdir=lastdir;
+ lastdir=t+1;
+ }
+ }
+
+ t=strchr(tmp,'$'); /* skip FS name */
+ if (t!=NULL)
+ t+=2; /* skip '.' after '$' */
+ else
+ t=tmp;
+ if (*t=='@') /* skip @. at the beginning of filenames */
+ t+=2;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+
+ /* return a pointer to '\0' if the file is a directory with the same
+ same name as an extension to swap (eg. 'c', 'h', etc.) */
+ if (isdir && exts2swap!=NULL) {
+ if (lastlastdir==NULL)
+ lastlastdir=t;
+ if (checkext(lastlastdir)) {
+ free((void *)tmp);
+ n=malloc(1);
+ if (n!=NULL)
+ *n='\0';
+ return n;
+ }
+ }
+
+ if (exts2swap!=NULL && lastdir!=NULL) {
+ if (lastlastdir==NULL)
+ lastlastdir=t;
+ if (checkext(lastlastdir)) {
+ if (swapext(lastlastdir,lastdir-1)) {
+ free((void *)tmp);
+ return NULL;
+ }
+ }
+ }
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL) {
+ free((void *)tmp);
+ return NULL;
+ }
+ strcpy(n, t);
+
+ free((void *)tmp);
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+ char *t; /* scans name */
+ char *lastext=NULL; /* pointer to last extension */
+ char *lastdir=NULL; /* pointer to last dir */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+
+ for(t=x;*t;t++) {
+ if (*t=='.') {
+ *t='/';
+ lastext=t+1;
+ }
+ else if (*t=='/') {
+ *t='.';
+ lastdir=t+1;
+ }
+ }
+
+ if (exts2swap!=NULL && (int)lastext>(int)lastdir) {
+ if (lastdir==NULL)
+ lastdir=x;
+ if (checkext(lastext)) {
+ if (swapext(lastdir,lastext-1)) {
+ free((void *)x);
+ return NULL;
+ }
+ }
+ }
+
+ return x;
+}
+
+local int uxtime2acornftime(unsigned *pexadr, unsigned *pldadr, time_t ut)
+{
+ unsigned timlo; /* 3 lower bytes of acorn file-time plus carry byte */
+ unsigned timhi; /* 2 high bytes of acorn file-time */
+
+ timlo = ((unsigned)ut & 0x00ffffffU) * 100 + 0x00996a00U;
+ timhi = ((unsigned)ut >> 24);
+ timhi = timhi * 100 + 0x0000336eU + (timlo >> 24);
+ if (timhi & 0xffff0000U)
+ return 1; /* calculation overflow, do not change time */
+
+ /* insert the five time bytes into loadaddr and execaddr variables */
+ *pexadr = (timlo & 0x00ffffffU) | ((timhi & 0x000000ffU) << 24);
+ *pldadr = (*pldadr & 0xffffff00U) | ((timhi >> 8) & 0x000000ffU);
+
+ return 0; /* subject to future extension to signal overflow */
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ time_t m_time;
+ unsigned int loadaddr, execaddr;
+ int attr;
+
+ /* Convert DOS time to time_t format in m_time */
+ m_time = dos2unixtime(d);
+
+ /* set the file's modification time */
+ SWI_OS_File_5(f,NULL,&loadaddr,NULL,NULL,&attr);
+
+ if (uxtime2acornftime(&execaddr, &loadaddr, m_time) != 0)
+ return;
+
+ SWI_OS_File_1(f,loadaddr,execaddr,attr);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ unsigned int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '.')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (strcmp(f, "-") == 0) {
+ /* forge stat values for stdin since Amiga and RISCOS have no fstat() */
+ s.st_mode = (S_IREAD|S_IWRITE|S_IFREG);
+ s.st_size = -1;
+ s.st_mtime = time(&s.st_mtime);
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFDIR) != 0) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime((time_t *) &s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+{
+#ifdef USE_EF_UT_TIME
+ char *eb_ptr;
+#endif /* USE_EF_UT_TIME */
+ char *name;
+ extra_block *block;
+
+#define EB_SPARK_LEN 20
+#define EB_SPARK_SIZE (EB_HEADSIZE+EB_SPARK_LEN)
+#ifdef USE_EF_UT_TIME
+# ifdef IZ_CHECK_TZ
+# define EB_UTTIME_SIZE (zp_tz_is_valid ? EB_HEADSIZE+EB_UT_LEN(1) : 0)
+# else
+# define EB_UTTIME_SIZE (EB_HEADSIZE+EB_UT_LEN(1))
+# endif
+#else
+# define EB_UTTIME_SIZE 0
+#endif
+#define EF_SPARK_TOTALSIZE (EB_SPARK_SIZE + EB_UTTIME_SIZE)
+
+ if ((name=(char *)malloc(strlen(z->name)+1))==NULL) {
+ fprintf(stderr," set_extra_field: not enough memory for directory name\n");
+ return ZE_MEM;
+ }
+
+ strcpy(name,z->name);
+
+ if (name[strlen(name)-1]=='.') { /* remove the last '.' in directory names */
+ name[strlen(name)-1]=0;
+ }
+
+ z->extra=(char *)malloc(EF_SPARK_TOTALSIZE);
+ if (z->extra==NULL) {
+ fprintf(stderr," set_extra_field: not enough memory\n");
+ free(name);
+ return ZE_MEM;
+ }
+ z->cextra = z->extra;
+ z->cext = z->ext = EF_SPARK_TOTALSIZE;
+
+ block=(extra_block *)z->extra;
+ block->ID=SPARKID;
+ block->size=EB_SPARK_LEN;
+ block->ID_2=SPARKID_2;
+ block->zero=0;
+
+ if (SWI_OS_File_5(name,NULL,&block->loadaddr,&block->execaddr,
+ NULL,&block->attr) != NULL) {
+ fprintf(stderr," OS error while set_extra_field of %s\n",name);
+ }
+
+ free(name);
+
+#ifdef USE_EF_UT_TIME
+# ifdef IZ_CHECK_TZ
+ if (zp_tz_is_valid) {
+# endif
+ eb_ptr = z->extra + EB_SPARK_SIZE;
+
+ eb_ptr[0] = 'U';
+ eb_ptr[1] = 'T';
+ eb_ptr[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ eb_ptr[3] = 0;
+ eb_ptr[4] = EB_UT_FL_MTIME;
+ eb_ptr[5] = (char)(z_utim->mtime);
+ eb_ptr[6] = (char)(z_utim->mtime >> 8);
+ eb_ptr[7] = (char)(z_utim->mtime >> 16);
+ eb_ptr[8] = (char)(z_utim->mtime >> 24);
+# ifdef IZ_CHECK_TZ
+ }
+# endif
+#endif /* USE_EF_UT_TIME */
+
+ return ZE_OK;
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+
+ printf(CompiledWith,
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+# ifdef __CC_NORCROFT
+ "Norcroft ", "cc",
+# else
+ "cc", "",
+# endif
+#endif
+
+ "RISC OS",
+
+ " (Acorn Computers Ltd)",
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
diff --git a/acorn/makefile b/acorn/makefile
new file mode 100644
index 0000000..323ffca
--- /dev/null
+++ b/acorn/makefile
@@ -0,0 +1,115 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# add -g to CC to debug
+# add -d to BIND to debug
+CC = cc
+BIND = link
+AS = $(CC) -c
+ASM = objasm
+SQUEEZE = squeeze -v
+E =
+
+# flags
+# CFLAGS flags for C compile
+# LFLAGS1 flags after output file spec, before obj file list
+# LFLAGS2 flags after obj file list (libraries, etc)
+#
+LIB =
+CBASE = -throwback -wn -DASMV -apcs 3/26
+CFLAGS = $(CBASE) -IC:,@.
+ASMFLAGS = -Throwback -Stamp -NoCache -CloseExec -quit -apcs 3/26
+LFLAGS1 =
+LFLAGS2 = $(LIB) C:o.Stubs
+
+# Uncomment the following line to enable support for Unix
+# Extra Field (Timezone)
+#CFLAGS = $(CFLAGS) -DUSE_EF_UT_TIME
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crc32.o \
+ crypt.o ttyio.o riscos.o acornzip.o swiven.o
+
+OBJI = deflate.o trees.o
+OBJA = match.o sendbits.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o riscos.o acornzip_.o swiven.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h acorn/osdep.h acorn/riscos.h acorn/swiven.h
+
+all: zip zipnote zipsplit zipcloak
+
+
+install: %.zip %.zipnote %.zipsplit %.zipcloak %.zipsfx \
+ zip zipnote zipsplit zipcloak zipsfx
+ $(SQUEEZE) zip %.zip
+ $(SQUEEZE) zipnote %.zipnote
+ $(SQUEEZE) zipsplit %.zipsplit
+ $(SQUEEZE) zipcloak %.zipcloak
+ copy acorn.zipsfx %.zipsfx ~CVF
+
+# suffix rules
+.SUFFIXES: _.o .o .c
+.c_.o:
+ $(CC) $(CFLAGS) -DUTIL -c $*.c -o $*_.o
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.s.o:
+ $(ASM) $(ASMFLAGS) -from @*.s -to @*.o
+
+# rules for zip, zipnote, zipcloak and zipsplit
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+
+crc32_.o: crc32.c
+ $(CC) $(CFLAGS) -DUTIL -c c.crc32 -o o.crc32_
+crypt_.o: crypt.c
+ $(CC) $(CFLAGS) -DUTIL -c c.crypt -o o.crypt_
+util_.o: util.c
+ $(CC) $(CFLAGS) -DUTIL -c c.util -o o.util_
+fileio_.o: fileio.c
+ $(CC) $(CFLAGS) -DUTIL -c c.fileio -o o.fileio_
+zipfile_.o: zipfile.c
+ $(CC) $(CFLAGS) -DUTIL -c c.zipfile -o o.zipfile_
+acornzip_.o: acorn/acornzip.c $(ZIP_H)
+ $(CC) $(CFLAGS) -DUTIL -c acorn/acornzip.c -o o.acornzip_
+
+riscos.o: acorn/riscos.c acorn/riscos.h
+ $(CC) $(CFLAGS) -c acorn/riscos.c
+
+acornzip.o: acorn/acornzip.c $(ZIP_H)
+ $(CC) $(CFLAGS) -c acorn/acornzip.c
+
+match.o: acorn/match.s
+ $(ASM) $(ASMFLAGS) -from acorn.s.match -to o.match
+
+sendbits.o: acorn/sendbits.s
+ $(ASM) $(ASMFLAGS) -from acorn.s.sendbits -to o.sendbits
+
+swiven.o: acorn/swiven.s
+ $(ASM) $(ASMFLAGS) -from acorn.s.swiven -to o.swiven
+
+zip: $(OBJZ) $(OBJI) $(OBJA)
+ $(BIND) -o zip$(E) $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote: $(OBJN)
+ $(BIND) -o zipnote$(E) $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+ $(BIND) -o zipcloak$(E) $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+ $(BIND) -o zipsplit$(E) $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+clean: ;remove zip; remove zipcloak;
+ remove zipsplit; remove zipnote;
+ create o.!fake! 0
+ wipe o.* ~cf
+
+# end of Makefile
diff --git a/acorn/match.s b/acorn/match.s
new file mode 100644
index 0000000..ee68ce6
--- /dev/null
+++ b/acorn/match.s
@@ -0,0 +1,217 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match.s for ARM by Sergio Monesi.
+
+r0 RN 0
+r1 RN 1
+r2 RN 2
+r3 RN 3
+r4 RN 4
+r5 RN 5
+r6 RN 6
+r7 RN 7
+r8 RN 8
+r9 RN 9
+sl RN 10
+fp RN 11
+ip RN 12
+sp RN 13
+lr RN 14
+pc RN 15
+
+MAX_DIST EQU 32506
+WMASK EQU 32767
+MAX_MATCH EQU 258
+
+ AREA |C$$code|, CODE, READONLY
+
+
+; r1 = chain_lenght
+; r2 = scan
+; r3 = match
+; r4 = len (tmp)
+; r5 = best_len
+; r6 = limit
+; r7 = strend
+; r8 = scan_end1
+; r9 = scan_end
+; lr = window
+; fp = prev
+
+|__max_chain_length|
+ IMPORT max_chain_length
+ DCD max_chain_length
+|__window|
+ IMPORT window
+ DCD window
+|__prev|
+ IMPORT prev
+ DCD prev
+|__prev_length|
+ IMPORT prev_length
+ DCD prev_length
+|__strstart|
+ IMPORT strstart
+ DCD strstart
+|__good_match|
+ IMPORT good_match
+ DCD good_match
+|__nice_match|
+ IMPORT nice_match
+ DCD nice_match
+|__match_start|
+ IMPORT match_start
+ DCD match_start
+
+ DCB "longest_match"
+ DCB &00,&00,&00
+ DCD &ff000010
+
+ EXPORT longest_match
+longest_match
+ STMFD sp!, {r4-r9,fp,lr}
+
+ LDR fp, [pc, #|__prev|-.-8]
+
+ LDR r1, [pc, #|__max_chain_length|-.-8]
+ LDR r1, [r1]
+ LDR lr, [pc, #|__window|-.-8]
+
+ LDR ip, [pc, #|__strstart|-.-8]
+ LDR ip, [ip]
+ ADD r2, lr, ip
+ LDR r5, [pc, #|__prev_length|-.-8]
+ LDR r5, [r5]
+ SUBS ip, ip, #MAX_DIST-250 ; if r6 > MAX_DIST
+ SUBCSS r6, ip, #250 ; r6 = r6 - MAXDIST
+ MOVLS r6, #0 ; else r6 = 0
+
+ ADD r7, r2, #MAX_MATCH-256
+ ADD r7, r7, #256 ; r7 = r2 + MAX_MATCH (=258);
+
+ SUB ip, r5, #1
+ LDRB r8, [r2, ip]
+ LDRB r9, [r2, r5]
+
+ LDR ip, [pc, #|__good_match|-.-8]
+ LDR ip, [ip]
+ CMP r5, ip
+ MOVCS r1, r1, LSR #2
+
+cycle
+ ADD r3, lr, r0
+
+ LDRB ip, [r3, r5]
+ CMP ip, r9
+ BNE cycle_end
+
+ SUB ip, r5, #1
+ LDRB ip, [r3, ip]
+ CMP ip, r8
+ BNE cycle_end
+
+ LDRB ip, [r2]
+ LDRB r4, [r3]
+ CMP ip, r4
+ BNE cycle_end
+
+ LDRB ip, [r3, #1]
+ LDRB r4, [r2, #1]
+ CMP ip, r4
+ BNE cycle_end
+
+ ADD r2, r2, #2
+ ADD r3, r3, #2
+
+inn_cycle
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ LDRB ip, [r2, #1]!
+ LDRB r4, [r3, #1]!
+ CMP ip, r4
+ BNE exit_inn_cycle
+
+ CMP r2, r7
+ BCC inn_cycle
+
+exit_inn_cycle
+ SUB r4, r2, r7 ; len = MAX_MATCH - (int)(strend - scan);
+ ADD r4, r4, #MAX_MATCH-256
+ ADD r4, r4, #256
+
+ SUB r2, r2, r4 ; scan = strend - MAX_MATCH
+
+ CMP r4, r5 ; if (len > best_len) {
+ BLE cycle_end
+
+ LDR ip, [pc, #|__match_start|-.-8] ; match_start = cur_match;
+ STR r0, [ip]
+ MOV r5, r4 ; best_len = len;
+
+ LDR ip, [pc, #|__nice_match|-.-8] ; if (len >= nice_match)
+ LDR ip, [ip]
+ CMP r4, ip
+ BGE exit_match ; break;
+
+ SUB ip, r5, #1 ; scan_end1 = scan[best_len-1];
+ LDRB r8, [r2, ip]
+ LDRB r9, [r2, r5] ; scan_end = scan[best_len];
+
+cycle_end
+ MOV ip, r0, LSL #17 ; cur_match & WMASK
+ MOV ip, ip, LSR #17
+
+ LDR r0, [fp, ip, ASL #1] ; cur_match = prev[cur_match & WMASK]
+ MOV r0, r0, ASL #16
+ MOV r0, r0, LSR #16
+
+ CMP r0, r6 ; cur_match > limit
+ BLS exit_match
+ SUBS r1, r1, #1 ; --chain_length
+ BNE cycle ; chain_length != 0
+
+exit_match
+ MOV r0, r5
+
+ LDMFD sp!, {r4-r9,fp,pc}^
+
+ END
diff --git a/acorn/osdep.h b/acorn/osdep.h
new file mode 100644
index 0000000..9f7783e
--- /dev/null
+++ b/acorn/osdep.h
@@ -0,0 +1,28 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "riscos.h"
+
+#define RISCOS
+#define NO_SYMLINKS
+#define NO_FCNTL_H
+#define NO_UNISTD_H
+#define NO_MKTEMP
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#define isatty(a) 1
+#define fseek(f,o,t) riscos_fseek((f),(o),(t))
+
+#define localtime riscos_localtime
+#define gmtime riscos_gmtime
+
+#ifdef ZCRYPT_INTERNAL
+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as seed pattern */
+#endif
diff --git a/acorn/riscos.c b/acorn/riscos.c
new file mode 100644
index 0000000..84dd2d3
--- /dev/null
+++ b/acorn/riscos.c
@@ -0,0 +1,394 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* riscos.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zip.h"
+#include "riscos.h"
+
+#define MAXEXT 256
+
+/* External globals */
+extern int scanimage;
+
+/* Local globals (!?!?) */
+char *exts2swap = NULL; /* Extensions to swap (actually, directory names) */
+
+int stat(char *filename,struct stat *res)
+{
+ int attr; /* object attributes */
+ unsigned int load; /* load address */
+ unsigned int exec; /* exec address */
+ int type; /* type: 0 not found, 1 file, 2 dir, 3 image */
+
+ if (!res)
+ return -1;
+
+ if (SWI_OS_File_5(filename,&type,&load,&exec,(int *)&res->st_size,&attr)!=NULL)
+ return -1;
+
+ if (type==0)
+ return -1;
+
+ res->st_dev=0;
+ res->st_ino=0;
+ res->st_nlink=0;
+ res->st_uid=1;
+ res->st_gid=1;
+ res->st_rdev=0;
+ res->st_blksize=1024;
+
+ res->st_mode = ((attr & 0001) << 8) | ((attr & 0002) << 6) |
+ ((attr & 0020) >> 2) | ((attr & 0040) >> 4);
+
+ switch (type) {
+ case 1: /* File */
+ res->st_mode |= S_IFREG;
+ break;
+ case 2: /* Directory */
+ res->st_mode |= S_IFDIR | 0700;
+ break;
+ case 3: /* Image file */
+ if (scanimage)
+ res->st_mode |= S_IFDIR | 0700;
+ else
+ res->st_mode |= S_IFREG;
+ break;
+ }
+
+ if ((((unsigned int) load) >> 20) == 0xfff) { /* date stamped file */
+ unsigned int t1, t2, tc;
+
+ t1 = (unsigned int) (exec);
+ t2 = (unsigned int) (load & 0xff);
+
+ tc = 0x6e996a00U;
+ if (t1 < tc)
+ t2--;
+ t1 -= tc;
+ t2 -= 0x33; /* 00:00:00 Jan. 1 1970 = 0x336e996a00 */
+
+ t1 = (t1 / 100) + (t2 * 42949673U); /* 0x100000000 / 100 = 42949672.96 */
+ t1 -= (t2 / 25); /* compensate for .04 error */
+
+ res->st_atime = res->st_mtime = res->st_ctime = t1;
+ }
+ else
+ res->st_atime = res->st_mtime = res->st_ctime = 0;
+
+ return 0;
+}
+
+#ifndef SFX
+
+DIR *opendir(char *dirname)
+{
+ DIR *thisdir;
+ int type;
+ int attr;
+ os_error *er;
+
+ thisdir=(DIR *)malloc(sizeof(DIR));
+ if (thisdir==NULL)
+ return NULL;
+
+ thisdir->dirname=(char *)malloc(strlen(dirname)+1);
+ if (thisdir->dirname==NULL) {
+ free(thisdir);
+ return NULL;
+ }
+
+ strcpy(thisdir->dirname,dirname);
+ if (thisdir->dirname[strlen(thisdir->dirname)-1]=='.')
+ thisdir->dirname[strlen(thisdir->dirname)-1]=0;
+
+ if (er=SWI_OS_File_5(thisdir->dirname,&type,NULL,NULL,NULL,&attr),er!=NULL ||
+ type<=1 || (type==3 && !scanimage))
+ {
+ free(thisdir->dirname);
+ free(thisdir);
+ return NULL;
+ }
+
+ thisdir->buf=malloc(DIR_BUFSIZE);
+ if (thisdir->buf==NULL) {
+ free(thisdir->dirname);
+ free(thisdir);
+ return NULL;
+ }
+
+ thisdir->size=DIR_BUFSIZE;
+ thisdir->offset=0;
+ thisdir->read=0;
+
+ return thisdir;
+}
+
+struct dirent *readdir(DIR *d)
+{
+ static struct dirent dent;
+
+ if (d->read==0) { /* no more objects read in the buffer */
+ if (d->offset==-1) { /* no more objects to read */
+ return NULL;
+ }
+
+ d->read=255;
+ if (SWI_OS_GBPB_9(d->dirname,d->buf,&d->read,&d->offset,DIR_BUFSIZE,NULL)!=NULL)
+ return NULL;
+
+ if (d->read==0) {
+ d->offset=-1;
+ return NULL;
+ }
+ d->read--;
+ d->act=(char *)d->buf;
+ }
+ else { /* some object is ready in buffer */
+ d->read--;
+ d->act=(char *)(d->act+strlen(d->act)+1);
+ }
+
+ strcpy(dent.d_name,d->act);
+ dent.d_namlen=strlen(dent.d_name);
+
+ return &dent;
+}
+
+void closedir(DIR *d)
+{
+ if (d->buf!=NULL)
+ free(d->buf);
+ if (d->dirname!=NULL)
+ free(d->dirname);
+ free(d);
+}
+
+int unlink(f)
+char *f; /* file to delete */
+/* Delete the file *f, returning non-zero on failure. */
+{
+ os_error *er;
+ char canon[256];
+ int size=255;
+
+ er=SWI_OS_FSControl_37(f,canon,&size);
+ if (er==NULL) {
+ er=SWI_OS_FSControl_27(canon,0x100);
+ }
+ else {
+ er=SWI_OS_FSControl_27(f,0x100);
+ }
+ return (int)er;
+}
+
+int deletedir(char *d)
+{
+ int objtype;
+ char *s;
+ int len;
+ os_error *er;
+
+ len = strlen(d);
+ if ((s = malloc(len + 1)) == NULL)
+ return -1;
+
+ strcpy(s,d);
+ if (s[len-1]=='.')
+ s[len-1]=0;
+
+ if (er=SWI_OS_File_5(s,&objtype,NULL,NULL,NULL,NULL),er!=NULL) {
+ free(s);
+ return -1;
+ }
+ if (objtype<2 || (!scanimage && objtype==3)) {
+ /* this is a file or it doesn't exist */
+ free(s);
+ return -1;
+ }
+
+ if (er=SWI_OS_File_6(s),er!=NULL) {
+ /* maybe this is a problem with the DDEUtils module, try to canonicalise the path */
+ char canon[256];
+ int size=255;
+
+ if (er=SWI_OS_FSControl_37(s,canon,&size),er!=NULL) {
+ free(s);
+ return -1;
+ }
+ if (er=SWI_OS_File_6(canon),er!=NULL) {
+ free(s);
+ return -1;
+ }
+ }
+ free(s);
+ return 0;
+}
+
+#endif /* !SFX */
+
+int chmod(char *file, int mode)
+{
+/*************** NOT YET IMPLEMENTED!!!!!! ******************/
+/* I don't know if this will be needed or not... */
+ file=file;
+ mode=mode;
+ return 0;
+}
+
+void setfiletype(char *fname,int ftype)
+{
+ char str[256];
+ sprintf(str,"SetType %s &%3.3X",fname,ftype);
+ SWI_OS_CLI(str);
+}
+
+void getRISCOSexts(char *envstr)
+{
+ char *envptr; /* value returned by getenv */
+
+ envptr = getenv(envstr);
+ if (envptr == NULL || *envptr == 0) return;
+
+ exts2swap=malloc(1+strlen(envptr));
+ if (exts2swap == NULL)
+ return;
+
+ strcpy(exts2swap, envptr);
+}
+
+int checkext(char *suff)
+{
+ register char *extptr=exts2swap;
+ register char *suffptr;
+ register int e,s;
+
+ if (extptr != NULL) while(*extptr) {
+ suffptr=suff;
+ e=*extptr; s=*suffptr;
+ while (e && e!=':' && s && s!='.' && s!='/' && e==s) {
+ e=*++extptr; s=*++suffptr;
+ }
+ if (e==':') e=0;
+ if (s=='.' || s=='/') s=0;
+ if (!e && !s) {
+ return 1;
+ }
+ while(*extptr!=':' && *extptr!='\0') /* skip to next extension */
+ extptr++;
+ if (*extptr!='\0')
+ extptr++;
+ }
+ return 0;
+}
+
+int swapext(char *name, char *exptr)
+{
+ char *ext;
+ char *p1=exptr;
+ char *p2;
+ int extchar=*exptr;
+ unsigned int i=0;
+
+ while(*++p1 && *p1!='.' && *p1!='/')
+ ;
+ ext=malloc(i=p1-exptr);
+ if (!ext)
+ return 1;
+ memcpy(ext, exptr+1, i);
+ p2=exptr-1;
+ p1=exptr+i-1;
+ while(p2 >= name)
+ *p1--=*p2--;
+ strcpy(name,ext);
+ *p1=(extchar=='/'?'.':'/');
+ free(ext);
+ return 0;
+}
+
+void remove_prefix(void)
+{
+ SWI_DDEUtils_Prefix(NULL);
+}
+
+void set_prefix(void)
+{
+ char *pref;
+ int size=0;
+
+ if (SWI_OS_FSControl_37("@",pref,&size)!=NULL)
+ return;
+
+ size=1-size;
+
+ if (pref=malloc(size),pref!=NULL) {
+ if (SWI_OS_FSControl_37("@",pref,&size)!=NULL) {
+ free(pref);
+ return;
+ }
+
+ if (SWI_DDEUtils_Prefix(pref)==NULL) {
+ atexit(remove_prefix);
+ }
+
+ free(pref);
+ }
+}
+
+#ifdef localtime
+# undef localtime
+#endif
+
+#ifdef gmtime
+# undef gmtime
+#endif
+
+/* Acorn's implementation of localtime() and gmtime()
+ * doesn't consider the timezone offset, so we have to
+ * add it before calling the library functions
+ */
+
+struct tm *riscos_localtime(const time_t *timer)
+{
+ time_t localt=*timer;
+
+ localt+=SWI_Read_Timezone()/100;
+
+ return localtime(&localt);
+}
+
+struct tm *riscos_gmtime(const time_t *timer)
+{
+ time_t localt=*timer;
+
+ localt+=SWI_Read_Timezone()/100;
+
+ return gmtime(&localt);
+}
+
+
+int riscos_fseek(FILE *fd, long offset, int whence)
+{
+ int ret;
+ switch (whence)
+ {
+ case SEEK_END:
+ ret = (fseek) (fd, 0, SEEK_END);
+ if (ret)
+ return ret;
+ /* fall through */
+ case SEEK_CUR:
+ offset += ftell (fd);
+ /* fall through */
+ default: /* SEEK_SET */
+ return (fseek) (fd, offset < 0 ? 0 : offset, SEEK_SET);
+ }
+}
diff --git a/acorn/riscos.h b/acorn/riscos.h
new file mode 100644
index 0000000..c45a148
--- /dev/null
+++ b/acorn/riscos.h
@@ -0,0 +1,119 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* riscos.h */
+
+#ifndef __riscos_h
+#define __riscos_h
+
+#include <time.h>
+#include <stdio.h>
+
+typedef struct {
+ int errnum;
+ char errmess[252];
+} os_error;
+
+#ifndef __swiven_h
+# include "swiven.h"
+#endif
+
+#define MAXPATHLEN 256
+#define MAXFILENAMELEN 64 /* should be 11 for ADFS, 13 for DOS, 64 seems a sensible value... */
+#define DIR_BUFSIZE 1024 /* this should be enough to read a whole E-Format directory */
+
+struct stat {
+ unsigned int st_dev;
+ int st_ino;
+ unsigned int st_mode;
+ int st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned int st_rdev;
+ unsigned int st_size;
+ unsigned int st_blksize;
+ time_t st_atime;
+ time_t st_mtime;
+ time_t st_ctime;
+};
+
+typedef struct {
+ char *dirname;
+ void *buf;
+ int size;
+ char *act;
+ int offset;
+ int read;
+} DIR;
+
+#define dstrm DIR
+
+struct dirent {
+ unsigned int d_off; /* offset of next disk directory entry */
+ int d_fileno; /* file number of entry */
+ size_t d_reclen; /* length of this record */
+ size_t d_namlen; /* length of d_name */
+ char d_name[MAXFILENAMELEN]; /* name */
+};
+
+typedef struct {
+ unsigned int load_addr;
+ unsigned int exec_addr;
+ int lenght;
+ int attrib;
+ int objtype;
+ char name[13];
+} riscos_direntry;
+
+#define SPARKID 0x4341 /* = "AC" */
+#define SPARKID_2 0x30435241 /* = "ARC0" */
+
+typedef struct {
+ short ID;
+ short size;
+ int ID_2;
+ unsigned int loadaddr;
+ unsigned int execaddr;
+ int attr;
+ int zero;
+} extra_block;
+
+
+#define S_IFMT 0770000
+
+#define S_IFDIR 0040000
+#define S_IFREG 0100000 /* 0200000 in UnixLib !?!?!?!? */
+
+#ifndef S_IEXEC
+# define S_IEXEC 0000100
+# define S_IWRITE 0000200
+# define S_IREAD 0000400
+#endif
+
+extern char *exts2swap; /* Extensions to swap */
+
+int stat(char *filename,struct stat *res);
+DIR *opendir(char *dirname);
+struct dirent *readdir(DIR *d);
+char *readd(DIR *d);
+void closedir(DIR *d);
+int unlink(char *f);
+int chmod(char *file, int mode);
+void setfiletype(char *fname,int ftype);
+void getRISCOSexts(char *envstr);
+int checkext(char *suff);
+int swapext(char *name, char *exptr);
+void remove_prefix(void);
+void set_prefix(void);
+struct tm *riscos_localtime(const time_t *timer);
+struct tm *riscos_gmtime(const time_t *timer);
+
+int riscos_fseek(FILE *fd, long offset, int whence);
+/* work around broken assumption that fseek() is OK with -ve file offsets */
+
+#endif /* !__riscos_h */
diff --git a/acorn/sendbits.s b/acorn/sendbits.s
new file mode 100644
index 0000000..f12921a
--- /dev/null
+++ b/acorn/sendbits.s
@@ -0,0 +1,105 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; sendbits.s for ARM by Sergio Monesi and Darren Salt.
+
+r0 RN 0
+r1 RN 1
+r2 RN 2
+r3 RN 3
+r4 RN 4
+r5 RN 5
+r6 RN 6
+r7 RN 7
+r8 RN 8
+r9 RN 9
+sl RN 10
+fp RN 11
+ip RN 12
+sp RN 13
+lr RN 14
+pc RN 15
+
+ AREA |Asm$$Code|, CODE, READONLY
+
+ = "send_bits",0
+ ALIGN
+ & &FF00000C
+
+ IMPORT __rt_stkovf_split_small
+ IMPORT flush_outbuf
+
+ IMPORT bi_valid
+ IMPORT bi_buf
+ IMPORT out_size
+ IMPORT out_offset
+ IMPORT out_buf
+
+ EXPORT send_bits
+send_bits
+ MOV ip,sp
+ STMDB sp!,{r4,r5,fp,ip,lr,pc}
+ SUB fp,ip,#4
+ LDR r5,=bi_buf
+ LDR r3,=bi_valid
+ LDR r4,[r5]
+ LDR r2,[r3]
+ ORR r4,r4,r0,LSL r2 ; |= value<<bi_valid
+ ADD r2,r2,r1 ; += length
+ CMP r2,#&10
+ STRLE r2,[r3] ; short? store & return
+ STRLE r4,[r5]
+ LDMLEDB fp,{r4,r5,fp,sp,pc}^
+
+ SUB r2,r2,#&10 ; adjust bi_valid, bi_buf
+ MOV ip,r4,LSR #16 ; (done early, keeping the old bi_buf
+ STR r2,[r3] ; in R4 for later storage)
+ STR ip,[r5]
+
+ LDR r0,=out_size
+ LDR r1,=out_offset
+ LDR r0,[r0]
+ LDR r2,[r1]
+ SUB r0,r0,#1
+ CMP r2,r0 ; if out_offset >= out_size-1
+ LDRHS r0,=out_buf
+ LDRHS r0,[r0]
+ BLHS flush_outbuf ; then flush the buffer
+ LDR r0,=out_buf
+ LDR r1,=out_offset
+ LDR r0,[r0]
+ LDR r2,[r1]
+ MOV r5,r4,LSR #8
+ STRB r4,[r0,r2]! ; store 'old' bi_buf
+ STRB r5,[r0,#1]
+ ADD r2,r2,#2
+ STR r2,[r1]
+
+ LDMDB fp,{r4,r5,fp,sp,pc}^
+
+
+ptr_bi & bi_valid
+ & bi_buf
+
+
+ = "bi_reverse",0
+ ALIGN
+ & &FF00000C
+
+ EXPORT bi_reverse
+bi_reverse
+ MOV r2,#0
+loop MOVS r0,r0,LSR #1
+ ADCS r2,r2,r2
+ SUBS r1,r1,#1
+ BNE loop
+ MOV r0,r2
+ MOVS pc,lr
+
+
+ END
diff --git a/acorn/srcrename b/acorn/srcrename
new file mode 100644
index 0000000..7bd6119
--- /dev/null
+++ b/acorn/srcrename
Binary files differ
diff --git a/acorn/swiven.h b/acorn/swiven.h
new file mode 100644
index 0000000..c860d7d
--- /dev/null
+++ b/acorn/swiven.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* swiven.h */
+
+#ifndef __swiven_h
+#define __swiven_h
+
+os_error *SWI_OS_FSControl_26(char *source, char *dest, int actionmask);
+/* copy */
+
+os_error *SWI_OS_FSControl_27(char *filename, int actionmask);
+/* wipe */
+
+os_error *SWI_OS_GBPB_9(char *dirname, void *buf, int *number,
+ int *offset, int size, char *match);
+/* read dir */
+
+os_error *SWI_OS_File_1(char *filename, unsigned int loadaddr,
+ unsigned int execaddr, int attrib);
+/* write file attributes */
+
+os_error *SWI_OS_File_5(char *filename, int *objtype, unsigned int *loadaddr,
+ unsigned int *execaddr, int *length, int *attrib);
+/* read file info */
+
+os_error *SWI_OS_File_6(char *filename);
+/* delete */
+
+os_error *SWI_OS_File_7(char *filename, int loadaddr, int execaddr, int size);
+/* create an empty file */
+
+os_error *SWI_OS_CLI(char *cmd);
+/* execute a command */
+
+int SWI_OS_ReadC(void);
+/* get a key from the keyboard buffer */
+
+os_error *SWI_OS_ReadVarVal(char *var, char *buf, int len, int *bytesused);
+/* reads an OS varibale */
+
+os_error *SWI_OS_FSControl_54(char *buffer, int dir, char *fsname, int *size);
+/* reads the path of a specified directory */
+
+os_error *SWI_OS_FSControl_37(char *pathname, char *buffer, int *size);
+/* canonicalise path */
+
+os_error *SWI_DDEUtils_Prefix(char *dir);
+/* sets the 'prefix' directory */
+
+int SWI_Read_Timezone(void);
+/* returns the timezone offset (centiseconds) */
+
+#endif /* !__swiven_h */
diff --git a/acorn/swiven.s b/acorn/swiven.s
new file mode 100644
index 0000000..1630124
--- /dev/null
+++ b/acorn/swiven.s
@@ -0,0 +1,276 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; SWI veneers used by Zip/Unzip
+;
+
+r0 RN 0
+r1 RN 1
+r2 RN 2
+r3 RN 3
+r4 RN 4
+r5 RN 5
+r6 RN 6
+r7 RN 7
+r8 RN 8
+r9 RN 9
+r10 RN 10
+r11 RN 11
+r12 RN 12
+sp RN 13
+lr RN 14
+pc RN 15
+
+sl RN 10
+fp RN 11
+ip RN 12
+
+
+XOS_Bit EQU &020000
+
+OS_GBPB EQU &00000C
+OS_File EQU &000008
+OS_FSControl EQU &000029
+OS_CLI EQU &000005
+OS_ReadC EQU &000004
+OS_ReadVarVal EQU &000023
+DDEUtils_Prefix EQU &042580
+Territory_ReadCurrentTimeZone EQU &043048
+
+ MACRO
+ STARTCODE $name
+ EXPORT $name
+$name
+ MEND
+
+
+ AREA |C$$code|, CODE, READONLY
+
+; os_error *SWI_OS_FSControl_26(char *source, char *dest, int actionmask);
+
+ STARTCODE SWI_OS_FSControl_26
+
+ MOV ip, lr
+
+ MOV r3, r2
+ MOV r2, r1
+ MOV r1, r0
+ MOV r0, #26
+
+ SWI OS_FSControl + XOS_Bit
+
+ MOVVC r0, #0
+
+ MOVS pc, ip
+
+
+; os_error *SWI_OS_FSControl_27(char *filename, int actionmask);
+
+ STARTCODE SWI_OS_FSControl_27
+
+ MOV ip, lr
+
+ MOV r3, r1
+ MOV r1, r0
+ MOV r0, #27
+
+ SWI OS_FSControl + XOS_Bit
+
+ MOVVC r0, #0
+
+ MOVS pc, ip
+
+
+; os_error *SWI_OS_GBPB_9(char *dirname, void *buf, int *number,
+; int *offset, int size, char *match);
+
+ STARTCODE SWI_OS_GBPB_9
+
+ MOV ip, sp
+ STMFD sp!, {r2-r6,lr}
+ LDMIA ip, {r5,r6}
+ LDR r4, [r3]
+ LDR r3, [r2]
+ MOV r2, r1
+ MOV r1, r0
+ MOV r0, #9
+ SWI OS_GBPB + XOS_Bit
+ LDMVSFD sp!, {r2-r6,pc}^
+ MOV r0, #0
+ LDMFD sp, {r5,r6}
+ STR r3, [r5]
+ STR r4, [r6]
+ LDMFD sp!, {r2-r6,pc}^
+
+
+; os_error *SWI_OS_File_1(char *filename, int loadaddr, int execaddr, int attrib);
+
+ STARTCODE SWI_OS_File_1
+
+ STMFD sp!, {r5,lr}
+ MOV r5, r3
+ MOV r3, r2
+ MOV r2, r1
+ MOV r1, r0
+ MOV r0, #1
+ SWI OS_File + XOS_Bit
+ MOVVC r0, #0
+ LDMFD sp!, {r5,pc}^
+
+
+
+; os_error *SWI_OS_File_5(char *filename, int *objtype, int *loadaddr,
+; int *execaddr, int *length, int *attrib);
+
+ STARTCODE SWI_OS_File_5
+
+ STMFD sp!, {r1-r5,lr}
+ MOV r1, r0
+ MOV r0, #5
+ SWI OS_File + XOS_Bit
+ LDMVSFD sp!, {r1-r5,pc}^
+ LDR lr, [sp]
+ TEQ lr, #0
+ STRNE r0, [lr]
+ LDR lr, [sp, #4]
+ TEQ lr ,#0
+ STRNE r2, [lr]
+ LDR lr, [sp, #8]
+ TEQ lr, #0
+ STRNE r3, [lr]
+ LDR lr, [sp ,#24]
+ TEQ lr, #0
+ STRNE r4, [lr]
+ LDR lr, [sp ,#28]
+ TEQ lr, #0
+ STRNE r5, [lr]
+ MOV r0, #0
+ LDMFD sp!, {r1-r5,pc}^
+
+
+; os_error *SWI_OS_File_6(char *filename);
+
+ STARTCODE SWI_OS_File_6
+
+ STMFD sp!, {r4-r5,lr}
+ MOV r1, r0
+ MOV r0, #6
+ SWI OS_File + XOS_Bit
+ MOVVC r0, #0
+ LDMFD sp!, {r4-r5,pc}^
+
+
+; os_error *SWI_OS_File_7(char *filename, int loadaddr, int execaddr, int size);
+
+ STARTCODE SWI_OS_File_7
+
+ STMFD sp!, {r4-r5,lr}
+ MOV r5, r3
+ MOV r4, #0
+ MOV r3, r2
+ MOV r2, r1
+ MOV r1, r0
+ MOV r0, #7
+ SWI OS_File + XOS_Bit
+ MOVVC r0, #0
+ LDMFD sp!, {r4-r5,pc}^
+
+
+; os_error *SWI_OS_CLI(char *cmd);
+
+ STARTCODE SWI_OS_CLI
+
+ MOV ip, lr
+ SWI OS_CLI + XOS_Bit
+ MOVVC r0, #0
+ MOVS pc, ip
+
+
+; int SWI_OS_ReadC(void);
+
+ STARTCODE SWI_OS_ReadC
+
+ MOV ip, lr
+ SWI OS_ReadC + XOS_Bit
+ MOVS pc, ip
+
+
+; os_error *SWI_OS_ReadVarVal(char *var, char *buf, int len, int *bytesused);
+
+ STARTCODE SWI_OS_ReadVarVal
+
+ STMFD sp!, {r4,lr}
+ MOV ip, r3
+ MOV r3, #0
+ MOV r4, #0
+ SWI OS_ReadVarVal + XOS_Bit
+ LDMVSFD sp!, {r4,pc}^
+ TEQ ip, #0
+ STRNE r2, [ip]
+ MOV r0, #0
+ LDMFD sp!, {r4,pc}^
+
+
+; os_error *SWI_OS_FSControl_54(char *buffer, int dir, char *fsname, int *size);
+
+ STARTCODE SWI_OS_FSControl_54
+
+ STMFD sp!, {r3-r6,lr}
+ LDR r5, [r3]
+ MOV r3, r2
+ MOV r2, r1
+ MOV r1, r0
+ MOV r0, #54
+ SWI OS_FSControl + XOS_Bit
+ LDMVSFD sp!, {r3-r6,pc}^
+ MOV r0, #0
+ LDMFD sp!, {r3}
+ STR r5, [r3]
+ LDMFD sp!, {r4-r6,pc}^
+
+
+; os_error *SWI_OS_FSControl_37(char *pathname, char *buffer, int *size);
+
+ STARTCODE SWI_OS_FSControl_37
+
+ STMFD sp!, {r2,r3-r5,lr}
+ LDR r5, [r2]
+ MOV r3, #0
+ MOV r4, #0
+ MOV r2, r1
+ MOV r1, r0
+ MOV r0, #37
+ SWI OS_FSControl + XOS_Bit
+ LDMVSFD sp!, {r2,r3-r5,pc}^
+ MOV r0, #0
+ LDMFD sp!, {r2}
+ STR r5, [r2]
+ LDMFD sp!, {r3-r5,pc}^
+
+
+; os_error *SWI_DDEUtils_Prefix(char *dir);
+
+ STARTCODE SWI_DDEUtils_Prefix
+
+ MOV ip, lr
+ SWI DDEUtils_Prefix + XOS_Bit
+ MOVVC r0, #0
+ MOVS pc, ip
+
+; int SWI_Read_Timezone(void);
+
+ STARTCODE SWI_Read_Timezone
+
+ MOV ip, lr
+ SWI Territory_ReadCurrentTimeZone + XOS_Bit
+ MOVVC r0, r1
+ MOVVS r0, #0
+ MOVS pc, ip
+
+
+ END
diff --git a/acorn/zipsfx b/acorn/zipsfx
new file mode 100644
index 0000000..7d63492
--- /dev/null
+++ b/acorn/zipsfx
@@ -0,0 +1,9 @@
+| zipsfx 0.1
+| Written by Darren Salt
+| Assumes that unzipsfx is on Run$Path (eg. in !Boot.Library)
+| Assumes that IfThere is available as either *command or utility
+
+If "%1" = "" Then Error 220 Syntax: zipsfx |<archive> |<SEA>
+If "%0" = "" Then Error 220 Syntax: zipsfx |<archive> |<SEA>
+Copy Run:unzipsfx %1 A~C~D~F~L~N~R~S~T~V
+Print %0 { >> %1 } \ No newline at end of file
diff --git a/acorn/zipup.h b/acorn/zipup.h
new file mode 100644
index 0000000..47c3536
--- /dev/null
+++ b/acorn/zipup.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow "r"
+#define fbad (NULL)
+typedef FILE *ftype;
+#define zopen(n,p) fopen(n,p)
+#define zread(f,b,n) fread((b),1,(n),(FILE*)(f))
+#define zclose(f) fclose(f)
+#define zerr(f) (k==(extent)(-1L))
+#define zstdin 0
diff --git a/amiga/LMKfile b/amiga/LMKfile
new file mode 100644
index 0000000..8c838ea
--- /dev/null
+++ b/amiga/LMKfile
@@ -0,0 +1,117 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit, Amiga SAS/C 5.10b
+# See the master Makefile under the top level Zip/Unzip source directory
+# for more information on compiler macros and flags for this version.
+# Last update: Jan 07, 2007
+# -John Bush, <J.Bush@MD-B.Prime.COM>, <JBush@BIX.COM>
+
+
+#######################
+# MACROBE DEFINITIONS #
+#######################
+
+# Compiler and loader debug flags. Omit comments as req'd.
+# Do not set when building production version.
+# CDBG = -d3
+# LDBG = ADDSYM
+
+DEFINES = -DNO_MKTEMP
+CC = lc
+OPT = -O
+CFLAGS = $(OPT) $(DEFINES) $(CDBG) -v -mat -cuisf -b0 -j85i86i87i100i
+
+LD = blink
+LDSTART = LIB:c.o
+LDFLAGS = LIB LIB:lc.lib+LIB:amiga.lib
+
+TMPFILE = ram:MakeZip.tmp
+
+###############################################
+# BASIC COMPILE INSTRUCTIONS AND DEPENDENCIES #
+###############################################
+
+# default C rules
+.c.o:
+ $(CC) $(CFLAGS) -o$@ $*.c
+
+# Alternate rules for routines containing entries needed by utilities
+.c.oo:
+ $(CC) $(CFLAGS) -DUTIL -o$*.oo $*.c
+
+# object file macrough lists
+
+HFILES = zip.h ziperr.h tailor.h revision.h crc32.h crypt.h ttyio.h \
+ amiga/amiga.h amiga/zipup.h amiga/osdep.h
+
+OBJA = zipfile.o zipup.o fileio.o util.o globals.o crc32.o crypt.o \
+ timezone.o ttyio.o amiga.o amigazip.o filedate.o
+OBJI = deflate.o trees.o
+OBJU = zipfile.oo fileio.oo util.oo globals.o timezone.o \
+ amiga.o amigazip.oo filedate.o
+
+OBJZ = zip.o $(OBJA) $(OBJI)
+
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32.oo crypt.oo ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIPS = zip zipnote zipcloak zipsplit
+
+all: Message $(ZIPS)
+
+Message:
+ -echo " "
+ -echo "WARNING: Lattice 5.x HAS NOT BEEN TESTED WITH THIS ZIP VERSION"
+ -echo "Report problems to <zip-bugs@lists.wku.edu>"
+ -echo " "
+
+zip: $(OBJZ) $(HFILES)
+ -echo "$(OBJZ)" > $(TMPFILE)
+ $(LD) TO Zip FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+ -delete $(TMPFILE) Zip.info
+
+zipnote: $(OBJN) $(HFILES)
+ -echo "$(OBJN)" > $(TMPFILE)
+ $(LD) TO ZipNote FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+ -delete $(TMPFILE) ZipNote.info
+
+zipcloak: $(OBJC) $(HFILES)
+ -echo "$(OBJC)" > $(TMPFILE)
+ $(LD) TO ZipCloak FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+ -delete $(TMPFILE) ZipCloak.info
+
+zipsplit: $(OBJS) $(HFILES)
+ -echo "$(OBJS)" > $(TMPFILE)
+ $(LD) TO ZipSplit FROM $(LDSTART) WITH $(TMPFILE) $(LDFLAGS) $(LDBG)
+ -delete $(TMPFILE) ZipSplit.info
+
+clean:
+ -delete $(OBJZ) all quiet force >nil:
+ -delete $(OBJU) all quiet force >nil:
+ -delete $(OBJA) all quiet force >nil:
+ -delete $(OBJI) all quiet force >nil:
+ -delete $(OBJN) all quiet force >nil:
+ -delete $(OBJC) all quiet force >nil:
+ -delete $(OBJS) all quiet force >nil:
+
+zip.o: zip.c $(HFILES)
+zipnote.o: zipnote.c $(HFILES)
+zipcloak.o: zipcloak.c $(HFILES)
+crypt.o: crypt.c $(HFILES)
+ttyio.o: ttyio.c $(HFILES)
+zipsplit.o: zipsplit.c $(HFILES)
+deflate.o: deflate.c $(HFILES)
+trees.o: trees.c $(HFILES)
+zipfile.o: zipfile.c $(HFILES)
+zipup.o: zipup.c $(HFILES)
+fileio.o: fileio.c $(HFILES)
+util.o: util.c $(HFILES)
+timezone.o: timezone.c $(HFILES) timezone.h
+crc32.o: crc32.c $(HFILES)
+crctab.o: crctab.c $(HFILES)
+globals.o: globals.c $(HFILES)
+
+# Amiga specific objects
+amiga.o: amiga/amiga.c $(HFILES)
+amigazip.o: amiga/amigazip.c $(HFILES)
+
+# end of Makefile
diff --git a/amiga/README b/amiga/README
new file mode 100644
index 0000000..861ff85
--- /dev/null
+++ b/amiga/README
@@ -0,0 +1 @@
+the -A option currently does not work for the amiga.
diff --git a/amiga/amiga.c b/amiga/amiga.c
new file mode 100644
index 0000000..797d6d8
--- /dev/null
+++ b/amiga/amiga.c
@@ -0,0 +1,138 @@
+/*
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* OS specific routines for AMIGA platform.
+ *
+ * John Bush <John.Bush@east.sun.com> BIX: jbush
+ * Paul Kienitz <kie@pacbell.net>
+ *
+ * History:
+ *
+ * Date DoBee Comments
+ * ------- -------- -----------------------------------------------
+ * 21Jan93 JBush Original coding.
+ * Incorporated filedate.c (existing routine).
+ *
+ * 31Jan93 JBush Made filedate.c include unconditional.
+ *
+ * 18Jul93 PaulK Moved Aztec _abort() here from stat.c because we
+ * can't share the same one between Zip and UnZip.
+ * Added close_leftover_open_dirs() call to it.
+ *
+ * 17Apr95 PaulK Added Amiga internal version string so that
+ * installer programs can compare the version being
+ * installed to see if the copy the user already has
+ * is older or newer. Added Prestart_Hook to support
+ * debug tracing in deflate.a.
+ *
+ * 6May95 PaulK Added GetComment() for filenote support.
+ *
+ * 12Nov95 PaulK Added #define ZIP in front of filedate.c, for
+ * new options in there; removed declare of set_con()
+ * since echon() no longer expands to it (or anything).
+ *
+ * 12Feb96 PaulK Removed call of echon() entirely.
+ *
+ * 12Jul97 PaulK Made both Aztec and SAS define USE_TIME_LIB for filedate.c
+ *
+ * 26Aug97 PaulK Added ClearIOErr_exit()
+ *
+ * 2Jan98 HWalt Adapted for SAS/C using stat.c replacement functions
+ *
+ * 6Jun00 PaulK Removed references to time_lib, since new filedate.c
+ * supercedes it
+ */
+
+#include <exec/memory.h>
+#ifdef AZTEC_C
+# include <libraries/dos.h>
+# include <libraries/dosextens.h>
+# include <clib/exec_protos.h>
+# include <clib/dos_protos.h>
+# include <pragmas/exec_lib.h>
+# include <pragmas/dos_lib.h>
+#else
+# include <proto/exec.h>
+# include <proto/dos.h>
+#endif
+#include <stdlib.h>
+#include "ziperr.h"
+void ziperr(int c, const char *h);
+
+#define ZIP
+#if !defined(UTIL)
+# define NO_MKTIME
+#endif
+
+#ifdef AZTEC_C
+
+/* ============================================================= */
+/* filedate.c is an external file, since it's shared with UnZip. */
+/* Aztec includes it here, but SAS/C now compiles it separately. */
+# include "amiga/filedate.c"
+
+/* the same applies to stat.c */
+# include "amiga/stat.c"
+
+# define setenv BOGUS_INCOMPATIBLE_setenv
+# include <fcntl.h>
+# undef setenv
+# ifdef DEBUG
+# define PRESTART_HOOK
+# endif
+#endif
+
+extern void close_leftover_open_dirs(void);
+
+
+/* the following handles cleanup when a ^C interrupt happens: */
+
+void _abort(void) /* called when ^C is pressed */
+{
+ close_leftover_open_dirs();
+ ziperr(ZE_ABORT, "^C");
+}
+
+void ClearIOErr_exit(int e) /* EXIT is defined as this */
+{
+ if (!e)
+ ((struct Process *) FindTask(NULL))->pr_Result2 = 0;
+ /* we clear IoErr() since we are successful, in a 1.x-compatible way */
+ exit(e);
+}
+
+
+/* Make sure the version number here matches the number in revision.h */
+/* as closely as possible in strict decimal "#.#" form: */
+const char version_id[] = "\0$VER: Zip 2.3 ("
+# include "env:VersionDate"
+")\r\n";
+
+/* call this with an arg of NULL to free storage: */
+
+char *GetComment(char *filename)
+{
+ BPTR lk;
+ static struct FileInfoBlock *fib = NULL;
+
+ if (!filename) {
+ if (fib) FreeMem(fib, sizeof(*fib));
+ fib = NULL;
+ return NULL;
+ }
+ if (!fib) {
+ if (!(fib = AllocMem(sizeof(*fib), MEMF_PUBLIC)))
+ ziperr(ZE_MEM, "was checking filenotes");
+ }
+ if (!(lk = Lock(filename, ACCESS_READ)))
+ return NULL;
+ if (!Examine(lk, fib))
+ fib->fib_Comment[0] = '\0';
+ UnLock(lk);
+ return fib->fib_Comment[0] ? &fib->fib_Comment[0] : NULL;
+}
diff --git a/amiga/amiga.h b/amiga/amiga.h
new file mode 100644
index 0000000..a1461d8
--- /dev/null
+++ b/amiga/amiga.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef __amiga_amiga_h
+#define __amiga_amiga_h
+
+/* amiga.h
+ *
+ * Globular definitions that affect all of AmigaDom.
+ *
+ * Originally included in unzip.h, extracted for simplicity and eeze of
+ * maintenance by John Bush.
+ *
+ * This version is for use with Zip. It is not globally included, but used
+ * only by functions in amiga/amigazip.c. Much material that was needed for
+ * UnZip is absent here.
+ *
+ */
+
+#include <fcntl.h> /* O_BINARY for open() w/o CR/LF translation */
+#include "amiga/z-stat.h" /* substitute for <stat.h> and <dire(c|n)t.h> */
+#define direct dirent
+
+#ifndef MODERN
+# define MODERN
+#endif
+
+#ifdef AZTEC_C /* Manx Aztec C, 5.0 or newer only */
+# include <clib/dos_protos.h>
+# include <pragmas/dos_lib.h> /* do inline dos.library calls */
+# define O_BINARY 0
+#endif /* AZTEC_C */
+
+
+#ifdef __SASC
+# include <dirent.h>
+# include <dos.h>
+# define disk_not_mounted 0
+# if ( (!defined(O_BINARY)) && defined(O_RAW))
+# define O_BINARY O_RAW
+# endif
+#endif /* SASC */
+
+
+/* Funkshine Prough Toe Taipes */
+
+LONG FileDate (char *, time_t[]);
+
+#endif /* __amiga_amiga_h */
diff --git a/amiga/amigazip.c b/amiga/amigazip.c
new file mode 100644
index 0000000..4e69d62
--- /dev/null
+++ b/amiga/amigazip.c
@@ -0,0 +1,507 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+#include "amiga/amiga.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#define utime FileDate
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Local globals (kinda like "military intelligence" or "broadcast quality") */
+
+extern char *label; /* still declared in fileio.c */
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+local int wild_recurse OF((char *, char *));
+
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+
+/* What we have here is a mostly-generic routine using opendir()/readd() and */
+/* isshexp()/MATCH() to find all the files matching a multi-part filespec */
+/* using the portable pattern syntax. It shouldn't take too much fiddling */
+/* to make it usable for any other platform that has directory hierarchies */
+/* but no shell-level pattern matching. It works for patterns throughout */
+/* the pathname, such as "foo:*.?/source/x*.[ch]". */
+
+#define ONENAMELEN 30
+/* the length of one filename component on the Amiga */
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the */
+/* middle of it. All wildcards to be expanded must come AFTER wildtail. */
+
+local int wild_recurse(whole, wildtail) char *whole; char *wildtail;
+{
+ DIR *dir;
+ char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+ ush newlen, amatch = 0;
+ BPTR lok;
+ int e = ZE_MISS;
+
+ if (!isshexp(wildtail))
+ if (lok = Lock(whole, ACCESS_READ)) { /* p exists? */
+ UnLock(lok);
+ return procname(whole, 0);
+ } else
+ return ZE_MISS; /* woops, no wildcards! */
+
+ /* back up thru path components till existing dir found */
+ do {
+ name = wildtail + strlen(wildtail) - 1;
+ for (;;)
+ if (name-- <= wildtail || *name == PATH_END) {
+ subwild = name + 1;
+ plug2 = *subwild;
+ *subwild = 0;
+ break;
+ }
+ if (glue)
+ *glue = plug;
+ glue = subwild;
+ plug = plug2;
+ dir = opendir(whole);
+ } while (!dir && !disk_not_mounted && subwild > wildtail);
+ wildtail = subwild; /* skip past non-wild components */
+
+ if ((subwild = strchr(wildtail + 1, PATH_END)) != NULL) {
+ /* this "+ 1" dodges the ^^^ hole left by *glue == 0 */
+ *(subwild++) = 0; /* wildtail = one component pattern */
+ newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
+ } else
+ newlen = strlen(whole) + (ONENAMELEN + 1);
+ if (!dir || !(newwhole = malloc(newlen))) {
+ if (glue)
+ *glue = plug;
+
+ e = dir ? ZE_MEM : ZE_MISS;
+ goto ohforgetit;
+ }
+ strcpy(newwhole, whole);
+ newlen = strlen(newwhole);
+ if (glue)
+ *glue = plug; /* repair damage to whole */
+ if (!isshexp(wildtail)) {
+ e = ZE_MISS; /* non-wild name not found */
+ goto ohforgetit;
+ }
+
+ while (name = readd(dir)) {
+ if (MATCH(wildtail, name, 0)) {
+ strcpy(newwhole + newlen, name);
+ if (subwild) {
+ name = newwhole + strlen(newwhole);
+ *(name++) = PATH_END;
+ strcpy(name, subwild);
+ e = wild_recurse(newwhole, name);
+ } else
+ e = procname(newwhole, 0);
+ newwhole[newlen] = 0;
+ if (e == ZE_OK)
+ amatch = 1;
+ else if (e != ZE_MISS)
+ break;
+ }
+ }
+
+ ohforgetit:
+ if (dir) closedir(dir);
+ if (subwild) *--subwild = PATH_END;
+ if (newwhole) free(newwhole);
+ if (e == ZE_MISS && amatch)
+ e = ZE_OK;
+ return e;
+}
+
+int wild(p) char *p;
+{
+ char *use;
+
+ /* special handling of stdin request */
+ if (strcmp(p, "-") == 0) /* if compressing stdin */
+ return newname(p, 0, 0);
+
+ /* wild_recurse() can't handle colons in wildcard part: */
+ if (use = strchr(p, ':')) {
+ if (strchr(++use, ':'))
+ return ZE_PARMS;
+ } else
+ use = p;
+
+ return wild_recurse(p, use);
+}
+
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (*p && a[-1] != '/' && a[-1] != ':')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ if ((t = strrchr(x, ':')) != NULL) /* reject ":" */
+ t++;
+ else
+ t = x;
+ { /* reject "//" */
+ char *tt = t;
+ while (tt = strchr(tt, '/'))
+ while (*++tt == '/')
+ t = tt;
+ }
+ while (*t == '/') /* reject leading "/" on what's left */
+ t++;
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+ return x;
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ time_t u[2]; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u */
+ u[0] = u[1] = dos2unixtime(d);
+
+ /* Set updated and accessed times of f */
+ utime(f, u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0)
+ error("fstat(stdin)");
+ } else if (SSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFDIR) != 0) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid) return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME;
+ z->extra[5] = (char)(z_utim->mtime);
+ z->extra[6] = (char)(z_utim->mtime >> 8);
+ z->extra[7] = (char)(z_utim->mtime >> 16);
+ z->extra[8] = (char)(z_utim->mtime >> 24);
+
+ z->cextra = z->extra;
+ z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+
+ return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+ return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ return rmdir(d);
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+
+/* NOTE: the following include depends upon the environment
+ * variable $Workbench to be set correctly. (Set by
+ * default, by Version command in Startup-sequence.)
+ */
+int WBversion = (int)
+#include "ENV:Workbench"
+;
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s under %s%s%s%s.\n\n";
+
+/* Define buffers. */
+
+ char buf1[16]; /* compiler name */
+ char buf2[16]; /* revstamp */
+ char buf3[16]; /* OS */
+ char buf4[16]; /* Date */
+/* char buf5[16]; /* Time */
+
+/* format "with" name strings */
+
+#ifdef AMIGA
+# ifdef __SASC
+ strcpy(buf1,"SAS/C ");
+# else
+# ifdef LATTICE
+ strcpy(buf1,"Lattice C ");
+# else
+# ifdef AZTEC_C
+ strcpy(buf1,"Manx Aztec C ");
+# else
+ strcpy(buf1,"UNKNOWN ");
+# endif
+# endif
+# endif
+/* "under" */
+ sprintf(buf3,"AmigaDOS v%d",WBversion);
+#else
+ strcpy(buf1,"Unknown compiler ");
+ strcpy(buf3,"Unknown OS");
+#endif
+
+/* Define revision, date, and time strings.
+ * NOTE: Do not calculate run time, be sure to use time compiled.
+ * Pass these strings via your makefile if undefined.
+ */
+
+#if defined(__VERSION__) && defined(__REVISION__)
+ sprintf(buf2,"version %d.%d",__VERSION__,__REVISION__);
+#else
+# ifdef __VERSION__
+ sprintf(buf2,"version %d",__VERSION__);
+# else
+ sprintf(buf2,"unknown version");
+# endif
+#endif
+
+#ifdef __DATE__
+ sprintf(buf4," on %s",__DATE__);
+#else
+ strcpy(buf4," unknown date");
+#endif
+
+/******
+#ifdef __TIME__
+ sprintf(buf5," at %s",__TIME__);
+#else
+ strcpy(buf5," unknown time");
+#endif
+******/
+
+/* Print strings using "CompiledWith" mask defined above.
+ * ("Compiled with %s%s under %s%s%s%s.")
+ */
+
+ printf(CompiledWith,
+ buf1,
+ buf2,
+ buf3,
+ buf4,
+ /* buf5, */ "",
+ "" ); /* buf6 not used */
+
+} /* end function version_local() */
diff --git a/amiga/crc_68.a b/amiga/crc_68.a
new file mode 100644
index 0000000..4cc2a25
--- /dev/null
+++ b/amiga/crc_68.a
@@ -0,0 +1,144 @@
+;===========================================================================
+; Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_68 created by Paul Kienitz, last modified 04 Jan 96.
+;
+; Return an updated 32 bit CRC value, given the old value and a block of data.
+; The CRC table used to compute the value is gotten by calling get_crc_table().
+; This replaces the older updcrc() function used in Zip and fUnZip. The
+; prototype of the function is:
+;
+; ulg crc32(ulg crcval, uch *text, extent textlen);
+;
+; On the Amiga, type extent is always unsigned long, not unsigned int, because
+; int can be short or long at whim, but size_t is long.
+;
+; If using this source on a non-Amiga 680x0 system, note that we treat
+; a0/a1/d0/d1 as scratch registers not preserved across function calls.
+; We do not bother to support registerized arguments for crc32() -- the
+; textlen parm is usually large enough so that savings outside the loop
+; are pointless.
+;
+; Define NO_UNROLLED_LOOPS to use a simple short loop which might be more
+; efficient on certain machines with dinky instruction caches ('020?), or for
+; processing short strings. If loops are unrolled, the textlen parm must be
+; less than 512K; if not unrolled, it must be less than 64K.
+
+ xdef _crc32 ; (ulg val, uch *buf, extent bufsize)
+
+DO_CRC0 MACRO
+ moveq #0,ltemp
+ move.b (textbuf)+,ltemp
+ eor.b crcval,ltemp
+ lsl.w #2,ltemp
+ move.l (crc_table,ltemp.w),ltemp
+ lsr.l #8,crcval
+ eor.l ltemp,crcval
+ ENDM
+
+ machine mc68020
+
+DO_CRC2 MACRO
+ move.b (textbuf)+,btemp
+ eor.b crcval,btemp
+ lsr.l #8,crcval
+ move.l (crc_table,btemp.w*4),ltemp
+ eor.l ltemp,crcval
+ ENDM
+
+crc_table equr a0 array of unsigned long
+crcval equr d0 unsigned long initial value
+textbuf equr a1 array of unsigned char
+textbufsize equr d1 unsigned long (count of bytes in textbuf)
+btemp equr d2
+ltemp equr d3
+
+
+ xref _get_crc_table ; ulg *get_crc_table(void)
+
+ NOLIST
+ INCLUDE 'exec/execbase.i'
+ LIST
+ xref _SysBase ; struct ExecBase *
+
+
+_crc32:
+ move.l 8(sp),d0
+ bne.s valid
+ moveq #0,d0
+ rts
+valid: movem.l btemp/ltemp,-(sp)
+ jsr _get_crc_table
+ move.l d0,ltemp
+ move.l 12(sp),crcval
+ move.l 16(sp),textbuf
+ move.l 20(sp),textbufsize
+ not.l crcval
+ move.l _SysBase,crc_table
+ move.w AttnFlags(crc_table),btemp
+ move.l ltemp,crc_table
+ btst #AFB_68020,btemp
+ bne twenty
+
+ IFD NO_UNROLLED_LOOPS
+
+ bra.s decr
+loop: DO_CRC0
+decr: dbra textbufsize,loop
+ bra.s done
+
+twenty: moveq #0,btemp
+ bra.s decr2
+loop2: DO_CRC2
+decr2: dbra textbufsize,loop2
+
+ ELSE ; !NO_UNROLLED_LOOPS
+
+ move.l textbufsize,btemp
+ lsr.l #3,textbufsize
+ bra decr8
+loop8: DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+decr8: dbra textbufsize,loop8
+ and.w #7,btemp
+ bra.s decr1
+loop1: DO_CRC0
+decr1: dbra btemp,loop1
+ bra done
+
+twenty: moveq #0,btemp
+ move.l textbufsize,-(sp)
+ lsr.l #3,textbufsize
+ bra decr82
+loop82: DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+decr82: dbra textbufsize,loop82
+ move.l (sp)+,textbufsize
+ and.w #7,textbufsize
+ bra.s decr12
+loop12: DO_CRC2
+decr12: dbra textbufsize,loop12
+
+ ENDC ; ?NO_UNROLLED_LOOPS
+
+done: movem.l (sp)+,btemp/ltemp
+ not.l crcval
+;;;;; move.l crcval,d0 ; crcval already is d0
+ rts
diff --git a/amiga/deflate.a b/amiga/deflate.a
new file mode 100644
index 0000000..b21adae
--- /dev/null
+++ b/amiga/deflate.a
@@ -0,0 +1,1053 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; This is a 680x0 assembly language translation of the Info-ZIP source file
+; deflate.c, by Paul Kienitz. The function longest_match is based in part
+; on match.a by Carsten Steger, which in turn is partly based on match.s
+; for 386 by Jean-loup Gailly and Kai Uwe Rommel. Mostly, however, this
+; material is based on deflate.c, by Gailly, Rommel, and Igor Mandrichenko.
+; This code is not commented very much; see deflate.c for comments that explain
+; what the functions are doing.
+;
+; The symbols that can be used to select different versions are as follows:
+;
+; CPU020 if defined, use 68020 instructions always.
+;
+; CPUTEST if defined, check at runtime for CPU type. Another symbol
+; specifying the platform-specific test must be used with this.
+; If neither of these is defined, use 68000 instructions only.
+; Runtime test is nonportable; it is different for each OS.
+;
+; AMIGA use Amiga-specific test for 68020, if CPUTEST defined. Also
+; tells it that registers d0/a0/d1/a1 are not preserved by
+; function calls. At present, if AMIGA is not defined, it
+; causes functions to preserve all registers. ALL OF THIS CODE
+; CURRENTLY ASSUMES THAT REGISTERS D2-D7/A2-A6 WILL BE PRESERVED
+; BY ANY FUNCTIONS THAT IT CALLS.
+;
+; DYN_ALLOC should be defined here if it is defined for C source; tells us
+; that big arrays are allocated instead of static.
+;
+; WSIZE must be defined as the same number used for WSIZE in the C
+; source, and must be a power of two <= 32768. As elsewhere,
+; the default value is 32768.
+;
+; INT16 define this if ints are 16 bits; otherwise 32 bit ints assumed.
+;
+; SMALL_MEM define this if it is defined in the C source; otherwise it uses
+; the MEDIUM_MEM model. BIG_MEM and MMAP are *not* supported.
+; The FULL_SEARCH option in deflate.c is also not supported.
+;
+; DEBUG activates some tracing output, as in the C source.
+;
+; QUADLONG this selects a different version of the innermost longest_match
+; loop code for 68020 operations, comparing bytes four at a time
+; instead of two at a time. It seems to be a tiny bit faster on
+; average, but it's slower often enough that one can't generalize.
+;
+; This code currently assumes that function results are returned in D0 for
+; all platforms. It assumes that args to functions are pushed onto the stack,
+; last arg first. It also currently assumes that all C symbols have an
+; underscore prepended when referenced from assembly.
+
+ IFND CPU020
+ IFND CPUTEST
+CPU000 equ 1
+ ENDC
+ ENDC
+
+; Use these macros for accessing variables of type int:
+ IFD INT16
+MOVINT MACRO
+ move.w \1,\2
+ ENDM
+CLRINT MACRO
+ clr.w \1
+ ENDM
+INTSIZE equ 2
+ ELSE ; !INT16
+MOVINT MACRO
+ move.l \1,\2
+ ENDM
+CLRINT MACRO
+ clr.l \1
+ ENDM
+INTSIZE equ 4
+ ENDC
+
+ IFD DYN_ALLOC
+BASEPTR MACRO
+ move.l \1,\2
+ ENDM
+ ELSE
+BASEPTR MACRO
+ lea \1,\2
+ ENDM
+ ENDC
+
+; constants we use, many of them adjustable:
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+TOO_FAR equ 4096
+ IFND WSIZE
+WSIZE equ 32768
+ ENDC
+WMASK equ WSIZE-1
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+MIN_LOOKAHEAD equ MAX_MATCH+MIN_MATCH+1
+; IFD BIG_MEM ; NOT supported -- type Pos needs to be 32 bits
+;HASH_BITS equ 15
+; ELSE
+ IFD SMALL_MEM
+HASH_BITS equ 13
+ ELSE
+HASH_BITS equ 14 ; default -- MEDIUM_MEM
+ ENDC
+; ENDC ; BIG_MEM
+HASH_SIZE equ 1<<HASH_BITS
+HASH_MASK equ HASH_SIZE-1
+H_SHIFT equ (HASH_BITS+MIN_MATCH-1)/MIN_MATCH
+B_SLOW equ 1
+B_FAST equ 2
+ZE_MEM equ 4
+EOF equ -1
+
+; struct config is defined by these offsets:
+Good_length equ 0
+Max_lazy equ 2
+Nice_length equ 4
+Max_chain equ 6
+Sizeof_config equ 8
+
+
+; external functions we call:
+ xref _ct_tally ; int ct_tally(int, int)
+ xref _flush_block ; unsigned long F(char *, unsigned long, int)
+ xref _ziperr ; void ziperr(int, char *)
+ xref _error ; void error(char *)
+ xref _calloc ; stdlib function: void *calloc(size_t, size_t)
+ xref _free ; stdlib function: void free(void *)
+ IFD DEBUG
+ xref _fputc ; stdio function: int fputc(int, FILE *)
+ xref _stderr ; pointer to FILE, which we pass to fputc
+ ENDC
+
+; our entry points:
+ xdef _lm_init ; void lm_init(int level, unsigned short *flags)
+ xdef _lm_free ; void lm_free(void)
+ xdef _deflate ; void deflate(void) ...the big one
+ xdef _fill_window ; this line is just for debugging
+
+
+; ============================================================================
+; Here is where we have our global variables.
+
+ section deflatevars,data
+
+; external global variables we reference:
+ xref _verbose ; signed int
+ xref _level ; signed int
+ xref _read_buf ; int (*read_buf)(char *, unsigned int)
+
+; global variables we make available:
+
+ xdef _window
+ xdef _prev
+ xdef _head
+ xdef _window_size
+ xdef _block_start
+ xdef _strstart
+
+ IFD DYN_ALLOC
+_prev: ds.l 1 ; pointer to calloc()'d unsigned short array
+_head: ds.l 1 ; pointer to calloc()'d unsigned short array
+_window: ds.l 1 ; pointer to calloc()'d unsigned char array
+ ELSE ; !DYN_ALLOC
+_prev: ds.w WSIZE ; array of unsigned short
+_head: ds.w HASH_SIZE ; array of unsigned short
+_window: ds.b 2*WSIZE ; array of unsigned char
+ ENDC ; ?DYN_ALLOC
+_window_size: ds.l 1 ; unsigned long
+_block_start: ds.l 1 ; unsigned long
+_strstart: ds.w INTSIZE/2 ; unsigned int
+
+; Now here are our private variables:
+
+ IFD CPUTEST
+is020: ds.w 1 ; bool: CPU type is '020 or higher
+ ENDC
+ins_h: ds.w 1 ; unsigned short
+sliding: ds.w 1 ; bool: the file is read a piece at a time
+eofile: ds.w 1 ; bool: we have read in the end of the file
+max_lazy_match: ds.w 1 ; unsigned short
+lookahead: ds.w 1 ; unsigned short
+
+; These are NOT DECLARED AS STATIC in deflate.c, but currently could be:
+max_chain_len: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+prev_length: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+good_match: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+nice_match: ds.w 1 ; unsigned short (signed int in deflate.c)
+match_start: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+
+; This array of struct config is a constant and could be in the code section:
+config_table: dc.w 0,0,0,0 ; level 0: store uncompressed
+ dc.w 4,4,8,4 ; level 1: fastest, loosest compression
+ dc.w 4,5,16,8 ; level 2
+ dc.w 4,6,32,32 ; level 3: highest to use deflate_fast
+ dc.w 4,4,16,16 ; level 4: lowest to use lazy matches
+ dc.w 8,16,32,32 ; level 5
+ dc.w 8,16,128,128 ; level 6: the default level
+ dc.w 8,32,128,256 ; level 7
+ dc.w 32,128,258,1024 ; level 8
+ dc.w 32,258,258,4096 ; level 9: maximum compression, slow
+
+
+;;CAL_SH MACRO ; macro for calling zcalloc()
+;; IFD INT16
+;; move.w #2,-(sp)
+;; move.w #\1,-(sp)
+;; jsr _zcalloc
+;; addq #4,sp
+;; ELSE
+;; pea 2
+;; pea \1
+;; jsr _zcalloc
+;; addq #8,sp
+;; ENDC
+;; ENDM
+
+CAL_SH MACRO ; Okay, we're back to using regular calloc()...
+ pea 2
+ pea \1
+ jsr _calloc
+ addq #8,sp
+ ENDM
+
+; ============================================================================
+; And here we begin our functions. match_init is for internal use only:
+
+ section deflate,code
+
+match_init:
+ IFD CPUTEST ; now check for platform type
+ IFD AMIGA ; Amiga specific test for '020 CPU:
+ xref _SysBase
+ NOLIST
+ INCLUDE 'exec/execbase.i'
+ LIST
+
+ clr.w is020 ; default value is 68000
+ move.l _SysBase,a0
+ btst #AFB_68020,AttnFlags+1(a0)
+ beq.s cheap
+ move.w #1,is020
+cheap:
+ ELSE ; !AMIGA
+
+ FAIL Write an '020-detector for your system here!
+; On the Macintosh, I believe GetEnvironment() provides the information.
+
+ ENDC ; AMIGA
+ ENDC ; CPUTEST
+ rts ; match_init consists only of rts if CPUTEST unset
+
+
+; ============================================================================
+; Here is longest_match(), the function that the rest of this was built up
+; from, the hottest hot spot in the program and therefore the most heavily
+; optimized. It has two different versions, one for '020 and higher CPUs, and
+; one for 68000/68010. It can test at runtime which version to use if you
+; create a test function in match_init for your platform. Currently such a
+; test is implemented for the Amiga. It can also be assembled to use '000 or
+; '020 code only.
+
+Cur_Match equr d0 ; unsigned int, kept valid as long
+Best_Len equr d1 ; unsigned int, kept valid as long
+Scan_Start equr d3 ; pair of bytes
+Scan_End equr d4 ; pair of bytes
+Limit equr d5 ; unsigned int
+Chain_Length equr d6 ; unsigned int
+Scan_Test equr d7 ; counter, pair of bytes sometimes
+Scan equr a0 ; pointer to unsigned char
+Match equr a1 ; pointer to unsigned char
+Prev_Address equr a2 ; pointer to unsigned short
+Scan_Ini equr a3 ; pointer to unsigned char
+Match_Ini equr a5 ; pointer to unsigned char
+; Note: "pair of bytes" means the two low order bytes of the register in
+; 68020 code, but means the lowest and third lowest bytes on the 68000.
+ IFD AMIGA
+SAVEREGS reg d3-d7/a2/a3/a5 ; don't protect d0/d1/a0/a1
+ ELSE ; !AMIGA
+SAVEREGS reg d1/d3-d7/a0-a3/a5 ; protect all except d0 return val
+ ENDC ; ?AMIGA
+; d2, a4, a6 not used... on Amiga, a4 is used by small-data memory model
+
+
+longest_match:
+ movem.l SAVEREGS,-(sp)
+
+; setup steps common to byte and word versions:
+ IFD INT16
+ and.l #$0000FFFF,Cur_Match ; upper half must be zero!
+; we use an and.l down here for the sake of ATSIGN/REGARGS.
+ moveq #0,Limit ; so adding to Scan_Ini works
+ ENDC
+ move.w max_chain_len,Chain_Length
+ move.w prev_length,Best_Len
+ MOVINT _strstart,Limit
+ BASEPTR _prev,Prev_Address
+ BASEPTR _window,Match_Ini
+ move.l Match_Ini,Scan_Ini
+ addq #MIN_MATCH,Match_Ini ; optimizes inner loop
+ add.l Limit,Scan_Ini
+ sub.w #MAX_DIST,Limit
+ bhi.s limit_ok
+ moveq #0,Limit
+limit_ok:
+ cmp.w good_match,Best_Len
+ blo.s length_ok
+ lsr.w #2,Chain_Length
+length_ok:
+ subq.w #1,Chain_Length
+
+ IFD CPUTEST
+ tst.w is020 ; can we use '020 stuff today?
+ bne WORD_match
+ ENDC
+
+ IFND CPU020
+
+; for 68000 or 68010, use byte operations:
+ moveq #0,Scan_Start ; clear 2nd & 4th bytes, use 1st & 3rd
+ moveq #0,Scan_End ; likewise
+ moveq #0,Scan_Test ; likewise
+ move.b (Scan_Ini),Scan_Start
+ swap Scan_Start ; swap is faster than 8 bit shift
+ move.b 1(Scan_Ini),Scan_Start
+ move.b -1(Scan_Ini,Best_Len.w),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len.w),Scan_End
+ bra.s bdo_scan
+
+blong_loop:
+ move.b -1(Scan_Ini,Best_Len.w),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len.w),Scan_End
+
+bshort_loop:
+ add.w Cur_Match,Cur_Match ; assert value before doubling < 32K
+ IFNE 32768-WSIZE
+ and.w #(WMASK*2),Cur_Match
+ ENDC
+ move.w (Prev_Address,Cur_Match.l),Cur_Match
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,bdo_scan
+ bra return
+
+bdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ move.b -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH(Match,Best_Len.w),Scan_Test
+ cmp.l Scan_Test,Scan_End
+ bne.s bshort_loop
+ move.b -MIN_MATCH(Match),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.l Scan_Test,Scan_Start
+ bne.s bshort_loop
+ move.w #(MAX_MATCH-3),Scan_Test
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+bscan_loop:
+ cmp.b (Match)+,(Scan)+
+ dbne Scan_Test,bscan_loop
+ subq #1,Scan
+
+ sub.l Scan_Ini,Scan ; assert difference is 16 bits
+ cmp.w Best_Len,Scan
+ bls.s bshort_loop
+ MOVINT Scan,Best_Len
+ move.w Cur_Match,match_start
+ cmp.w nice_match,Best_Len
+ blo.s blong_loop
+ IFD CPUTEST
+ bra return
+ ENDC
+
+ ENDC ; !CPU020
+
+ IFND CPU000
+ MACHINE MC68020
+
+; for 68020 or higher, use word operations even on odd addresses:
+WORD_match:
+ move.w (Scan_Ini),Scan_Start
+ move.w -1(Scan_Ini,Best_Len.w),Scan_End
+ bra.s wdo_scan
+
+wlong_loop:
+ move.w -1(Scan_Ini,Best_Len.w),Scan_End
+
+wshort_loop:
+ and.w #WMASK,Cur_Match
+ move.w (Prev_Address,Cur_Match.w*2),Cur_Match ; '020 addressing mode
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,wdo_scan
+ bra.s return
+
+wdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ cmp.w -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+ bne.s wshort_loop
+ cmp.w -MIN_MATCH(Match),Scan_Start
+ bne.s wshort_loop
+ IFD QUADLONG
+; By some measurements, this version of the code is a little tiny bit faster.
+; But on some files it's slower. It probably pays off only when there are
+; long match strings, and costs in the most common case of three-byte matches.
+ moveq #((MAX_MATCH-MIN_MATCH)/16),Scan_Test ; value = 15
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+wscan_loop:
+ cmp.l (Match)+,(Scan)+ ; test four bytes at a time
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ dbne Scan_Test,wscan_loop ; '020 can cache a bigger loop
+odd:
+ subq #4,Scan
+ subq #4,Match
+ cmp.b (Match)+,(Scan)+ ; find good bytes in bad longword
+ bne.s even
+ cmp.b (Match)+,(Scan)+
+ bne.s even
+ cmp.b (Match)+,(Scan)+
+ beq.s steven
+even: subq #1,Scan
+ ELSE ; !QUADLONG
+ moveq #((MAX_MATCH-MIN_MATCH)/2),Scan_Test ; value = 127
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+wscan_loop:
+ cmp.w (Match)+,(Scan)+
+ dbne Scan_Test,wscan_loop
+ subq #2,Scan
+ move.b -2(Match),Scan_Test
+ cmp.b (Scan),Scan_Test
+ bne.s steven
+ addq #1,Scan
+ ENDC ; ?QUADLONG
+steven:
+ sub.l Scan_Ini,Scan ; assert: difference is 16 bits
+ cmp.w Best_Len,Scan
+ bls.s wshort_loop
+ MOVINT Scan,Best_Len
+ move.w Cur_Match,match_start
+ cmp.w nice_match,Best_Len
+ blo.s wlong_loop
+
+ MACHINE MC68000
+ ENDC ; !CPU000
+
+return:
+ MOVINT Best_Len,d0 ; return value (upper half should be clear)
+ movem.l (sp)+,SAVEREGS
+ rts
+
+
+; =============================================================================
+; This is the deflate() function itself, our main entry point. It calls
+; longest_match, above, and some outside functions. It is a hot spot, but not
+; as hot as longest_match. It uses no special '020 code.
+
+; ================== Several macros used in deflate() and later functions:
+
+; Arg 1 is D-reg that new ins_h value is to be left in,
+; arg 2 is the byte value to be hashed into it, which must not be the same reg
+UP_HASH MACRO
+ move.w ins_h,\1
+ asl.w #H_SHIFT,\1
+ eor.b \2,\1
+ and.w #HASH_MASK,\1 ; ((ins_h << H_SHIFT) ^ c) & HASH_MASK
+ move.w \1,ins_h ; ins_h = that
+ ENDM
+
+; Arg 1 is scratch A, arg 2 is scratch D
+IN_STR MACRO
+ move.l Strst,\2
+ addq.w #MIN_MATCH-1,\2
+ move.b (Window,\2.l),\2 ; window[strstart + MIN_MATCH - 1]
+ UP_HASH Head,\2
+ add.l Head,Head ; assert upper word is zero before add
+ BASEPTR _head,\1
+ add.l Head,\1
+ move.w (\1),Head ; hash_head = head[ins_h]
+ move.w Strst,(\1) ; head[ins_h] = strstart
+ move.l Strst,\2
+ IFNE WSIZE-32768
+ and.w #WMASK,\2
+ ENDC
+ add.w \2,\2 ; masks implicitly when WSIZE == 32768
+ move.w Head,(Prev,\2.l) ; prev[str_start & WMASK] = hash_head
+ ENDM
+
+; Arg 1 is bool (int) EOF flag, flush_block result is in d0, trashes d1/a0/a1
+FLUSH_B MACRO
+ IFC '\1','#0'
+ CLRINT -(sp)
+ ELSE
+ MOVINT \1,-(sp)
+ ENDC
+ move.l _block_start,d0
+ blt.s nenu\@
+ move.l Window,a0
+ add.l d0,a0
+ bra.s nun\@
+nenu\@: sub.l a0,a0 ; if block_start < 0, push NULL
+nun\@: sub.l Strst,d0
+ neg.l d0
+ move.l d0,-(sp)
+ move.l a0,-(sp)
+ jsr _flush_block
+ lea 8+INTSIZE(sp),sp
+ ENDM
+
+; This expands to nothing unless DEBUG is defined.
+; Arg 1 is a byte to be trace-outputted -- if it is d0 it must be a valid int
+TRACE_C MACRO
+ IFD DEBUG
+ cmp.w #1,_verbose+INTSIZE-2 ; test lower word only
+ ble.s qui\@
+ IFNC '\1','d0'
+ moveq #0,d0
+ move.b \1,d0
+ ENDC
+ move.l _stderr,-(sp)
+ MOVINT d0,-(sp)
+ jsr _fputc
+ addq #4+INTSIZE,sp
+qui\@:
+ ENDC ; DEBUG
+ ENDM
+
+; ================== Here are the register vars we use, and deflate() itself:
+
+Window equr a2 ; cached address of window[]
+Prev equr a3 ; cached address of prev[]
+Strst equr d7 ; strstart cached as a longword
+Look equr d6 ; lookahead cached as short
+Head equr d5 ; local variable hash_head, short
+PrevL equr d4 ; prev_length cached as short
+MatchL equr d3 ; local variable match_length, unsigned short
+Avail equr d2 ; local variable available_match, bool
+PrevM equr a5 ; local variable prev_match, int in an A-reg
+
+ IFD AMIGA
+DEFREGS reg d2-d7/a2/a3/a5
+ ELSE
+DEFREGS reg d0-d7/a0/a2/a3/a5 ; play it safe, preserve all regs
+ ENDC
+
+
+_deflate: ; first, setup steps common to deflate and deflate_fast:
+ movem.l DEFREGS,-(sp)
+ IFD INT16
+ moveq #0,Strst ; make sure strstart is valid as a long
+ ENDC
+ moveq #0,Head ; ditto for hash_head
+ MOVINT _strstart,Strst
+ move.w lookahead,Look
+ move.w prev_length,PrevL
+ BASEPTR _window,Window
+ BASEPTR _prev,Prev
+ MOVINT _level,d0
+ cmp.w #3,d0
+ ble deflate_fast
+ moveq #MIN_MATCH-1,MatchL
+ moveq #0,Avail
+
+look_loop:
+ tst.w Look
+ beq last_tally
+ IN_STR a0,d0
+ move.w MatchL,PrevL
+ move.w match_start,PrevM
+ move.w #MIN_MATCH-1,MatchL
+
+ tst.w Head
+ beq.s no_new_match
+ cmp.w max_lazy_match,PrevL
+ bhs.s no_new_match
+ move.w Strst,d0
+ sub.w Head,d0
+ cmp.w #MAX_DIST,d0
+ bhi.s no_new_match
+ move.w PrevL,prev_length ; longest_match reads these variables
+ MOVINT Strst,_strstart
+ MOVINT Head,d0 ; parm for longest_match
+ bsr longest_match ; sets match_start
+ cmp.w Look,d0 ; does length exceed valid data?
+ bls.s stml
+ move.w Look,d0
+stml: move.w d0,MatchL ; valid length of match
+ cmp.w #MIN_MATCH,MatchL ; is the match only three bytes?
+ bne.s no_new_match
+ move.w match_start,d0
+ sub.w Strst,d0
+ cmp.w #-TOO_FAR,d0
+ bge.s no_new_match
+ moveq #MIN_MATCH-1,MatchL ; mark the current match as no good
+
+no_new_match:
+ cmp.w #MIN_MATCH,PrevL
+ blo literal
+ cmp.w MatchL,PrevL
+ blo literal
+ ; CHECK_MATCH Strst-1,PrevM,PrevL
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ move.l PrevL,d0
+ subq.w #MIN_MATCH,d0
+ MOVINT d0,-(sp)
+ move.l Strst,d0
+ sub.w PrevM,d0
+ subq.w #1,d0
+ MOVINT d0,-(sp)
+ jsr _ct_tally ; sets d0 true if we have to flush
+ addq #2*INTSIZE,sp
+ subq.w #3,PrevL ; convert for dbra (prev_length - 2)
+ sub.w PrevL,Look
+ subq.w #2,Look
+insertmatch:
+ addq.w #1,Strst
+ IN_STR a0,d1 ; don't clobber d0
+ dbra PrevL,insertmatch
+ moveq #0,Avail
+ moveq #0,PrevL ; not needed?
+ moveq #MIN_MATCH-1,MatchL
+ addq.w #1,Strst
+ tst.w d0
+ beq refill
+ FLUSH_B #0
+ move.l Strst,_block_start
+ bra.s refill
+
+literal:
+ tst.w Avail
+ bne.s yeslit
+ moveq #1,Avail
+ bra.s skipliteral
+yeslit: TRACE_C <-1(Window,Strst.l)>
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b -1(Window,Strst.l),d0
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally
+ addq #2*INTSIZE,sp
+ tst.w d0
+ beq.s skipliteral
+ FLUSH_B #0
+ move.l Strst,_block_start
+skipliteral:
+ addq.w #1,Strst
+ subq.w #1,Look
+
+refill:
+ cmp.w #MIN_LOOKAHEAD,Look
+ bhs look_loop
+ bsr fill_window
+ bra look_loop
+
+last_tally:
+ tst.w Avail
+ beq last_flush
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b -1(Window,Strst.l),d0
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally
+ addq #2*INTSIZE,sp
+last_flush:
+ FLUSH_B #1
+ bra deflate_exit
+
+; ================== This is another version used for low compression levels:
+
+deflate_fast:
+ moveq #0,MatchL
+ moveq #MIN_MATCH-1,PrevL
+flook_loop:
+ tst.w Look
+ beq flast_flush
+
+ IN_STR a0,d0
+ tst.w Head
+ beq.s fno_new_match
+ move.w Strst,d0
+ sub.w Head,d0
+ cmp.w #MAX_DIST,d0
+ bhi.s fno_new_match
+ move.w PrevL,prev_length ; longest_match reads these variables
+ MOVINT Strst,_strstart
+ MOVINT Head,d0 ; parm for longest_match
+ bsr longest_match ; sets match_start
+ cmp.w Look,d0 ; does length exceed valid data?
+ bls.s fstml
+ move.w Look,d0
+fstml: move.w d0,MatchL ; valid length of match
+
+fno_new_match:
+ cmp.w #MIN_MATCH,MatchL
+ blo fliteral
+ ; CHECK_MATCH Strst,match_start,MatchL
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ move.l MatchL,d0
+ subq.w #MIN_MATCH,d0
+ MOVINT d0,-(sp)
+ move.l Strst,d0
+ sub.w match_start,d0
+ MOVINT d0,-(sp)
+ jsr _ct_tally ; sets d0 true if we have to flush
+ addq #2*INTSIZE,sp
+ sub.w MatchL,Look
+ cmp.w max_lazy_match,MatchL
+ bhi ftoolong
+ subq.w #2,MatchL
+finsertmatch:
+ addq.w #1,Strst
+ IN_STR a0,d1 ; preserve d0
+ dbra MatchL,finsertmatch
+ moveq #0,MatchL ; not needed?
+ addq.w #1,Strst
+ bra.s flushfill
+
+ftoolong:
+ add.w MatchL,Strst
+ moveq #0,MatchL
+ moveq #0,d1 ; preserve d0
+ move.b (Window,Strst.l),d1
+ move.w d1,ins_h
+; My assembler objects to passing <1(Window,Strst.l)> directly to UP_HASH...
+ move.b 1(Window,Strst.l),Avail ; Avail is not used in deflate_fast
+ UP_HASH d1,Avail ; preserve d0
+ IFNE MIN_MATCH-3
+ FAIL needs to UP_HASH another MIN_MATCH-3 times, but with what arg?
+ ENDC
+ bra.s flushfill
+
+fliteral:
+ TRACE_C <(Window,Strst.l)>
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b (Window,Strst.l),d0
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally ; d0 set if we need to flush
+ addq #2*INTSIZE,sp
+ addq.w #1,Strst
+ subq.w #1,Look
+
+flushfill:
+ tst.w d0
+ beq.s frefill
+ FLUSH_B #0
+ move.l Strst,_block_start
+frefill:
+ cmp.w #MIN_LOOKAHEAD,Look
+ bhs flook_loop
+ bsr fill_window
+ bra flook_loop
+
+flast_flush:
+ FLUSH_B #1 ; sets our return value
+
+deflate_exit:
+ MOVINT Strst,_strstart ; save back cached values
+ move.w PrevL,prev_length
+ move.w Look,lookahead
+ movem.l (sp)+,DEFREGS
+ rts
+
+
+; =========================================================================
+; void fill_window(void) calls the input function to refill the sliding
+; window that we use to find substring matches in.
+
+More equr Head ; local variable in fill_window
+WindTop equr Prev ; local variable used for sliding
+SlidIx equr PrevL ; local variable used for sliding
+
+ IFD AMIGA
+FWREGS reg d2-d5/a2-a6 ; does NOT include Look and Strst
+ ELSE
+FWREGS reg d1-d5/a0-a6 ; likewise
+ ENDC
+; all registers available to be clobbered by the sliding operation:
+; we exclude More, WindTop, SlidIx, Look, Strst, Window, a4 and a7.
+SPAREGS reg d0-d3/a0-a1/a5-a6
+SPCOUNT equ 8 ; number of registers in SPAREGS
+
+
+_fill_window: ; C-callable entry point
+ movem.l Strst/Look,-(sp)
+ IFD INT16
+ moveq #0,Strst ; Strst must be valid as a long
+ ENDC
+ MOVINT _strstart,Strst
+ move.w lookahead,Look
+ BASEPTR _window,Window
+ bsr.s fill_window
+ MOVINT Strst,_strstart
+ move.w Look,lookahead
+ movem.l (sp)+,Strst/Look
+ rts
+
+; strstart, lookahead, and window must be cached in Strst, Look, and Window:
+fill_window: ; asm-callable entry point
+ movem.l FWREGS,-(sp)
+ tst.w eofile ; we put this up here for speed
+ bne fwdone
+ and.l #$FFFF,Look ; make sure Look is valid as long
+fw_refill:
+ move.l _window_size,More ; <= 64K
+ sub.l Look,More
+ sub.l Strst,More ; Strst is already valid as long
+ cmp.w #EOF,More
+ bne.s notboundary
+ subq.w #1,More
+ bra checkend
+
+notboundary:
+ tst.w sliding
+ beq checkend
+ cmp.w #WSIZE+MAX_DIST,Strst
+ blo checkend
+ IFGT 32768-WSIZE
+ lea WSIZE(Window),WindTop ; WindTop is aligned when Window is
+ ELSE
+ move.l Window,WindTop
+ add.l #WSIZE,WindTop
+ ENDC
+ move.l Window,d0
+ and.w #3,d0
+ beq.s isaligned
+ subq.w #1,d0
+align: move.b (WindTop)+,(Window)+ ; copy up to a longword boundary
+ dbra d0,align
+isaligned:
+; This is faster than a simple move.l (WindTop)+,(Window)+ / dbra loop:
+ move.w #(WSIZE-1)/(4*SPCOUNT),SlidIx
+slide: movem.l (WindTop)+,SPAREGS ; copy, 32 bytes at a time!
+ movem.l SPAREGS,(Window) ; a slight overshoot doesn't matter.
+ lea 4*SPCOUNT(Window),Window ; can't use (aN)+ as movem.l dest
+ dbra SlidIx,slide
+ BASEPTR _window,Window ; restore cached value
+ sub.w #WSIZE,match_start
+ sub.w #WSIZE,Strst
+ sub.l #WSIZE,_block_start
+ add.w #WSIZE,More
+ BASEPTR _head,a0
+ move.w #HASH_SIZE-1,d0
+fixhead:
+ move.w (a0),d1
+ sub.w #WSIZE,d1
+ bpl.s headok
+ moveq #0,d1
+headok: move.w d1,(a0)+
+ dbra d0,fixhead
+ BASEPTR _prev,a0
+ move.w #WSIZE-1,d0
+fixprev:
+ move.w (a0),d1
+ sub.w #WSIZE,d1
+ bpl.s prevok
+ moveq #0,d1
+prevok: move.w d1,(a0)+
+ dbra d0,fixprev
+ TRACE_C #'.'
+
+checkend: ; assert eofile is false
+ MOVINT More,-(sp) ; assert More's upper word is zero
+ move.l Strst,d0
+ add.w Look,d0
+ add.l Window,d0
+ move.l d0,-(sp)
+ move.l _read_buf,a0
+ jsr (a0) ; refill the upper part of the window
+ addq #4+INTSIZE,sp
+ tst.w d0
+ beq.s iseof
+ cmp.w #EOF,d0
+ beq.s iseof
+ add.w d0,Look
+ cmp.w #MIN_LOOKAHEAD,Look
+ blo fw_refill ; eofile is still false
+
+ bra.s fwdone
+iseof: move.w #1,eofile
+fwdone: movem.l (sp)+,FWREGS
+ rts
+
+
+; =========================================================================
+; void lm_free(void) frees dynamic arrays in the DYN_ALLOC version.
+
+ xdef _lm_free ; the entry point
+
+_lm_free:
+ IFD DYN_ALLOC
+ move.l _window,d0
+ beq.s lf_no_window
+ move.l d0,-(sp)
+ jsr _free
+ addq #4,sp
+ clr.l _window
+lf_no_window:
+ move.l _prev,d0
+ beq.s lf_no_prev
+ move.l d0,-(sp)
+ jsr _free
+ move.l _head,(sp) ; reuse the same stack arg slot
+ jsr _free
+ addq #4,sp
+ clr.l _prev
+ clr.l _head
+lf_no_prev:
+ ENDC
+ rts
+
+; ============================================================================
+; void lm_init(int pack_level, unsigned short *flags) allocates dynamic arrays
+; if any, and initializes all variables so that deflate() is ready to go.
+
+ xdef _lm_init ; the entry point
+
+Level equr d2
+;Window equr a2 ; as in deflate()
+ IFD AMIGA
+INIREGS reg d2/a2
+ ELSE
+INIREGS reg d0-d2/a0-a1
+ ENDC
+
+_lm_init:
+ MOVINT 4(sp),d0
+ move.l 4+INTSIZE(sp),a0
+ movem.l INIREGS,-(sp)
+ move.w d0,Level
+ cmp.w #1,Level
+ blt.s levelerr
+ bgt.s try9
+ bset.b #B_FAST,1(a0)
+try9: cmp.w #9,Level
+ bgt.s levelerr
+ blt.s levelok
+ bset.b #B_SLOW,1(a0)
+ bra.s levelok
+levelerr:
+ pea level_message
+ jsr _error ; never returns
+levelok:
+ clr.w sliding
+ tst.l _window_size
+ bne.s gotawindowsize
+ move.w #1,sliding
+ move.l #2*WSIZE,_window_size
+gotawindowsize:
+
+ BASEPTR _window,Window
+ IFD DYN_ALLOC
+ move.l Window,d0 ; fake tst.l
+ bne.s gotsomewind
+ CAL_SH WSIZE
+ move.l d0,Window
+ move.l d0,_window
+ bne.s gotsomewind
+ pea window_message
+ MOVINT #ZE_MEM,-(sp)
+ jsr _ziperr ; never returns
+gotsomewind:
+ tst.l _prev
+ bne.s gotsomehead
+ CAL_SH WSIZE
+ move.l d0,_prev
+ beq.s nohead
+ CAL_SH HASH_SIZE
+ move.l d0,_head
+ bne.s gotfreshhead ; newly calloc'd memory is zeroed
+nohead: pea hash_message
+ MOVINT #ZE_MEM,-(sp)
+ jsr _ziperr ; never returns
+gotsomehead:
+ ENDC ; DYN_ALLOC
+
+ move.w #(HASH_SIZE/2)-1,d0 ; two shortwords per loop
+ BASEPTR _head,a0
+wipeh: clr.l (a0)+
+ dbra d0,wipeh
+gotfreshhead:
+ move.l Level,d0
+ IFEQ Sizeof_config-8
+ asl.l #3,d0
+ ELSE
+ mulu #Sizeof_config,d0
+ ENDC
+ lea config_table,a0
+ add.l d0,a0
+ move.w Max_lazy(a0),max_lazy_match
+ move.w Good_length(a0),good_match
+ move.w Nice_length(a0),nice_match
+ move.w Max_chain(a0),max_chain_len
+ CLRINT _strstart
+ clr.l _block_start
+ bsr match_init
+
+ clr.w eofile
+ MOVINT #WSIZE,-(sp) ; We read only 32K because lookahead is short
+ move.l Window,-(sp) ; even when int size is long, as if deflate.c
+ move.l _read_buf,a0 ; were compiled with MAXSEG_64K defined.
+ jsr (a0)
+ addq #4+INTSIZE,sp
+ move.w d0,lookahead
+ beq.s noread
+ cmp.w #EOF,d0
+ bne.s irefill
+noread: move.w #1,eofile
+ clr.w lookahead
+ bra.s init_done
+
+irefill:
+ move.w lookahead,d0
+ cmp.w #MIN_LOOKAHEAD,d0
+ bhs.s hashify
+ bsr _fill_window ; use the C-callable version
+hashify:
+ clr.w ins_h
+ moveq #MIN_MATCH-2,d0
+hash1: move.b (Window)+,d1
+ UP_HASH Level,d1
+ dbra d0,hash1
+
+init_done:
+ movem.l (sp)+,INIREGS
+ rts
+
+; strings for error messages:
+hash_message dc.b 'hash table allocation',0
+window_message dc.b 'window allocation',0
+level_message dc.b 'bad pack level',0
+
+ end
diff --git a/amiga/filedate.c b/amiga/filedate.c
new file mode 100644
index 0000000..9ccbdda
--- /dev/null
+++ b/amiga/filedate.c
@@ -0,0 +1,599 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Low-level Amiga routines shared between Zip and UnZip.
+ *
+ * Contains: FileDate()
+ * getenv() [replaces inadequate standard library version]
+ * setenv() [SAS/C only, replaces standard library version]
+ * set_TZ() [SAS/C only]
+ * GetPlatformLocalTimezone() [callback from timezone.c tzset()]
+ * time()
+ * sendpkt()
+ * Agetch()
+ *
+ * The first five are used by most Info-ZIP programs except fUnZip.
+ * The last two are used by all except the non-CRYPT version of fUnZip.
+ * Probably some of the stuff in here is unused by ZipNote and ZipSplit too...
+ * sendpkt() is used by Agetch() and FileDate(), and by screensize() in
+ * amiga/amiga.c (UnZip); time() is used only by Zip.
+ */
+
+
+/* HISTORY/CHANGES
+ * 2 Sep 92, Greg Roelofs, Original coding.
+ * 6 Sep 92, John Bush, Incorporated into UnZip 5.1
+ * 6 Sep 92, John Bush, Interlude "FileDate()" defined, which calls or
+ * redefines SetFileDate() depending upon AMIGADOS2 definition.
+ * 11 Oct 92, John Bush, Eliminated AMIGADOS2 switch by determining
+ * revision via OpenLibrary() call. Now only one version of
+ * the program runs on both platforms (1.3.x vs. 2.x)
+ * 11 Oct 92, John Bush, Merged with Zip version and changed arg passing
+ * to take time_t input instead of struct DateStamp.
+ * Arg passing made to conform with utime().
+ * 22 Nov 92, Paul Kienitz, fixed includes for Aztec and cleaned up some
+ * lint-ish errors; simplified test for AmigaDOS version.
+ * 11 Nov 95, Paul Kienitz, added Agetch() for crypt password input and
+ * UnZip's "More" prompt -- simplifies crypt.h and avoids
+ * use of library code redundant with sendpkt(). Made it
+ * available to fUnZip, which does not use FileDate().
+ * 22 Nov 95, Paul Kienitz, created a new tzset() that gets the current
+ * timezone from the Locale preferences. These exist only under
+ * AmigaDOS 2.1 and up, but it is probably correctly set on more
+ * Amigas than the TZ environment variable is. We check that
+ * only if TZ is not validly set. We do not parse daylight
+ * savings syntax except to check for presence vs. absence of a
+ * DST part; United States rules are assumed. This is better
+ * than the tzset()s in the Amiga compilers' libraries do.
+ * 15 Jan 96, Chr. Spieler, corrected the logic when to select low level
+ * sendpkt() (when FileDate(), Agetch() or windowheight() is used),
+ * and AMIGA's Agetch() (CRYPT, and UnZip(SFX)'s UzpMorePause()).
+ * 10 Feb 96, Paul Kienitz, re-fiddled that selection logic again, moved
+ * stuff around for clarity.
+ * 16 Mar 96, Paul Kienitz, created a replacement localtime() to go with the
+ * new tzset(), because Aztec's is hopelessly broken. Also
+ * gmtime(), which localtime() calls.
+ * 12 Apr 96, Paul Kienitz, daylight savings was being handled incorrectly.
+ * 21 Apr 96, Paul Kienitz, had to replace time() as well, Aztec's returns
+ * local time instead of GMT. That's why their localtime() was bad,
+ * because it assumed time_t was already local, and gmtime() was
+ * the one that checked TZ.
+ * 23 Apr 96, Chr. Spieler, deactivated time() replacement for UnZip stuff.
+ * Currently, the UnZip sources do not make use of time() (and do
+ * not supply the working mktime() replacement, either!).
+ * 29 Apr 96, Paul Kienitz, created a replacement getenv() out of code that
+ * was previously embedded in tzset(), for reliable global test
+ * of whether TZ is set or not.
+ * 19 Jun 96, Haidinger Walter, re-adapted for current SAS/C compiler.
+ * 7 Jul 96, Paul Kienitz, smoothed together compiler-related changes.
+ * 4 Feb 97, Haidinger Walter, added set_TZ() for SAS/C.
+ * 23 Apr 97, Paul Kienitz, corrected Unix->Amiga DST error by adding
+ * mkgmtime() so localtime() could be used.
+ * 28 Apr 97, Christian Spieler, deactivated mkgmtime() definition for ZIP;
+ * the Zip sources supply this function as part of util.c.
+ * 24 May 97, Haidinger Walter, added time_lib support for SAS/C and moved
+ * set_TZ() to time_lib.c.
+ * 12 Jul 97, Paul Kienitz, adapted time_lib stuff for Aztec.
+ * 26 Jul 97, Chr. Spieler, old mkgmtime() fixed (ydays[] def, sign vs unsign).
+ * 30 Dec 97, Haidinger Walter, adaptation for SAS/C using z-stat.h functions.
+ * 19 Feb 98, Haidinger Walter, removed alloc_remember, more SAS.C fixes.
+ * 23 Apr 98, Chr. Spieler, removed mkgmtime(), changed FileDate to convert to
+ * Amiga file-time directly.
+ * 24 Apr 98, Paul Kienitz, clip Unix dates earlier than 1978 in FileDate().
+ * 02 Sep 98, Paul Kienitz, C. Spieler, always include zip.h to get a defined
+ * header inclusion sequence that resolves all header dependencies.
+ * 06 Jun 00, Paul Kienitz, removed time_lib.c due to its incompatible license,
+ * moved set_TZ() back here, replaced minimal tzset() and localtime()
+ * with new versions derived from GNU glibc source. Gave locale_TZ()
+ * reasonable European defaults for daylight savings.
+ * 17 Jun 00, Paul Kienitz, threw out GNU code because of objections to the GPL
+ * virus, replaced with similar functions based on the public domain
+ * timezone code at ftp://elsie.nci.nih.gov/pub. As with the GNU
+ * stuff, support for timezone files and leap seconds was removed.
+ * 23 Aug 00, Paul Kienitz, moved timezone code out from here into separate
+ * platform-independent module 'timezone.c'.
+ * 31 Dec 00, Christian Spieler, moved system-specific timezone help funcions
+ * back in here, from 'timezone.c'.
+ * 07 Jan 01, Paul Kienitz, Chr. Spieler, added missing #include "timezone.h"
+ * and "symbolic" preprocessor constants for time calculations.
+ * 15 Jan 02, Paul Kienitz, excluded all time handling code from compilation
+ * for Zip utilities (when "defined(UTIL)")
+ */
+
+#ifndef __amiga_filedate_c
+#define __amiga_filedate_c
+
+
+#include "zip.h"
+#include <ctype.h>
+#include <errno.h>
+
+#include <exec/types.h>
+#include <exec/execbase.h>
+#include <exec/memory.h>
+#include <dos/dosextens.h>
+
+#ifdef AZTEC_C
+# include <libraries/dos.h>
+# include <libraries/dosextens.h>
+# include <clib/exec_protos.h>
+# include <clib/dos_protos.h>
+# include <clib/locale_protos.h>
+# include <pragmas/exec_lib.h>
+# include <pragmas/dos_lib.h>
+# include <pragmas/locale_lib.h>
+# define ESRCH ENOENT
+# define EOSERR EIO
+#endif
+
+#ifdef __SASC
+# include <stdlib.h>
+# if (defined(_M68020) && (!defined(__USE_SYSBASE)))
+ /* on 68020 or higher processors it is faster */
+# define __USE_SYSBASE /* to use the pragma libcall instead of syscall */
+# endif /* to access functions of the exec.library */
+# include <proto/exec.h> /* see SAS/C manual:part 2,chapter 2,pages 6-7 */
+# include <proto/dos.h>
+# include <proto/locale.h>
+# ifdef DEBUG
+# include <sprof.h>
+# endif
+# ifdef MWDEBUG
+# include <stdio.h> /* include both before memwatch.h again just */
+# include <stdlib.h> /* to be safe */
+# include "memwatch.h"
+# endif /* MWDEBUG */
+#endif /* __SASC */
+
+#include "crypt.h" /* just so we can tell if CRYPT is supported */
+
+
+#if (!defined(FUNZIP) && !defined(UTIL))
+
+#include "timezone.h" /* for AMIGA-specific timezone callbacks */
+
+#ifndef SUCCESS
+# define SUCCESS (-1L)
+# define FAILURE 0L
+#endif
+
+#define ReqVers 36L /* required library version for SetFileDate() */
+#define ENVSIZE 100 /* max space allowed for an environment var */
+
+extern struct ExecBase *SysBase;
+
+#ifndef min
+# define min(a, b) ((a) < (b) ? (a) : (b))
+# define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+#if defined(ZIP) || defined(HAVE_MKTIME)
+static const unsigned short ydays[] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+#else
+extern const unsigned short ydays[]; /* in unzip's fileio.c */
+#endif
+
+#define LEAP(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+#define YDAYS(m, y) (ydays[m] + (m > 1 && LEAP(y)))
+/* Number of leap years from 1978 to `y' (not including `y' itself). */
+#define ANLEAP(y) (((y) - 1977) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY 86400L
+
+/* prototypes */
+char *getenv(const char *var);
+#ifdef __SASC
+/* XXX !! We have really got to find a way to operate without these. */
+int setenv(const char *var, const char *value, int overwrite);
+void set_TZ(long time_zone, int day_light);
+#endif
+
+LONG FileDate(char *filename, time_t u[]);
+LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+int Agetch(void);
+
+/* =============================================================== */
+
+/***********************/
+/* Function filedate() */
+/***********************/
+
+/* FileDate() (originally utime.c), by Paul Wells. Modified by John Bush
+ * and others (see also sendpkt() comments, below); NewtWare SetFileDate()
+ * clone cheaply ripped off from utime().
+ */
+
+/* DESCRIPTION
+ * This routine chooses between 2 methods to set the file date on AMIGA.
+ * Since AmigaDOS 2.x came out, SetFileDate() was available in ROM (v.36
+ * and higher). Under AmigaDOS 1.3.x (less than v.36 ROM), SetFileDate()
+ * must be accomplished by constructing a message packet and sending it
+ * to the file system handler of the file to be stamped.
+ *
+ * The system's ROM version is extracted from the external system Library
+ * base.
+ *
+ * NOTE: although argument passing conforms with utime(), note the
+ * following differences:
+ * - Return value is boolean success/failure.
+ * - If a structure or array is passed, only the first value
+ * is used, which *may* correspond to date accessed and not
+ * date modified.
+ */
+
+LONG FileDate(filename, u)
+ char *filename;
+ time_t u[];
+{
+ LONG SetFileDate(UBYTE *filename, struct DateStamp *pDate);
+ LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+ struct MsgPort *taskport;
+ BPTR dirlock, lock;
+ struct FileInfoBlock *fib;
+ LONG pktargs[4];
+ UBYTE *ptr;
+ long ret;
+
+ struct DateStamp pDate;
+ struct tm *ltm;
+ int years;
+
+ tzset();
+ /* Amiga file date is based on 01-Jan-1978 00:00:00 (local time):
+ * 8 years and 2 leapdays difference from Unix time.
+ */
+ ltm = localtime(&u[0]);
+ years = ltm->tm_year + 1900;
+ if (years < 1978)
+ pDate.ds_Days = pDate.ds_Minute = pDate.ds_Tick = 0;
+ else {
+ pDate.ds_Days = (years - 1978) * 365L + (ANLEAP(years)) +
+ YDAYS(ltm->tm_mon, years) + (ltm->tm_mday - 1);
+ pDate.ds_Minute = ltm->tm_hour * 60 + ltm->tm_min;
+ pDate.ds_Tick = ltm->tm_sec * TICKS_PER_SECOND;
+ }
+
+ if (SysBase->LibNode.lib_Version >= ReqVers)
+ {
+ return (SetFileDate(filename,&pDate)); /* native routine at 2.0+ */
+ }
+ else /* !(SysBase->lib_Version >=ReqVers) */
+ {
+ if( !(taskport = (struct MsgPort *)DeviceProc(filename)) )
+ {
+ errno = ESRCH; /* no such process */
+ return FAILURE;
+ }
+
+ if( !(lock = Lock(filename,SHARED_LOCK)) )
+ {
+ errno = ENOENT; /* no such file */
+ return FAILURE;
+ }
+
+ if( !(fib = (struct FileInfoBlock *)AllocMem(
+ (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
+ {
+ errno = ENOMEM; /* insufficient memory */
+ UnLock(lock);
+ return FAILURE;
+ }
+
+ if( Examine(lock,fib)==FAILURE )
+ {
+ errno = EOSERR; /* operating system error */
+ UnLock(lock);
+ FreeMem(fib,(long)sizeof(*fib));
+ return FAILURE;
+ }
+
+ dirlock = ParentDir(lock);
+ ptr = (UBYTE *)AllocMem(64L,MEMF_PUBLIC);
+ strcpy((ptr+1),fib->fib_FileName);
+ *ptr = strlen(fib->fib_FileName);
+ FreeMem(fib,(long)sizeof(*fib));
+ UnLock(lock);
+
+ /* now fill in argument array */
+
+ pktargs[0] = 0;
+ pktargs[1] = (LONG)dirlock;
+ pktargs[2] = (LONG)&ptr[0] >> 2;
+ pktargs[3] = (LONG)&pDate;
+
+ errno = ret = sendpkt(taskport,ACTION_SET_DATE,pktargs,4L);
+
+ FreeMem(ptr,64L);
+ UnLock(dirlock);
+
+ return SUCCESS;
+ } /* ?(SysBase->lib_Version >= ReqVers) */
+} /* FileDate() */
+
+
+char *getenv(const char *var) /* not reentrant! */
+{
+ static char space[ENVSIZE];
+ struct Process *me = (void *) FindTask(NULL);
+ void *old_window = me->pr_WindowPtr;
+ char *ret = NULL;
+
+ me->pr_WindowPtr = (void *) -1; /* suppress any "Please insert" popups */
+ if (SysBase->LibNode.lib_Version >= ReqVers) {
+ if (GetVar((char *) var, space, ENVSIZE - 1, /*GVF_GLOBAL_ONLY*/ 0) > 0)
+ ret = space;
+ } else { /* early AmigaDOS, get env var the crude way */
+ BPTR hand, foot, spine;
+ int z = 0;
+ if (foot = Lock("ENV:", ACCESS_READ)) {
+ spine = CurrentDir(foot);
+ if (hand = Open((char *) var, MODE_OLDFILE)) {
+ z = Read(hand, space, ENVSIZE - 1);
+ Close(hand);
+ }
+ UnLock(CurrentDir(spine));
+ }
+ if (z > 0) {
+ space[z] = '\0';
+ ret = space;
+ }
+ }
+ me->pr_WindowPtr = old_window;
+ return ret;
+}
+
+#ifdef __SASC
+int setenv(const char *var, const char *value, int overwrite)
+{
+ struct Process *me = (void *) FindTask(NULL);
+ void *old_window = me->pr_WindowPtr;
+ int ret = -1;
+
+ me->pr_WindowPtr = (void *) -1; /* suppress any "Please insert" popups */
+ if (SysBase->LibNode.lib_Version >= ReqVers)
+ ret = !SetVar((char *)var, (char *)value, -1, GVF_GLOBAL_ONLY | LV_VAR);
+ else {
+ BPTR hand, foot, spine;
+ long len = value ? strlen(value) : 0;
+ if (foot = Lock("ENV:", ACCESS_READ)) {
+ spine = CurrentDir(foot);
+ if (len) {
+ if (hand = Open((char *) var, MODE_NEWFILE)) {
+ ret = Write(hand, (char *) value, len + 1) >= len;
+ Close(hand);
+ }
+ } else
+ ret = DeleteFile((char *) var);
+ UnLock(CurrentDir(spine));
+ }
+ }
+ me->pr_WindowPtr = old_window;
+ return ret;
+}
+
+/* Stores data from timezone and daylight to ENV:TZ. */
+/* ENV:TZ is required to exist by some other SAS/C library functions, */
+/* like stat() or fstat(). */
+void set_TZ(long time_zone, int day_light)
+{
+ char put_tz[MAXTIMEZONELEN]; /* string for putenv: "TZ=aaabbb:bb:bbccc" */
+ int offset;
+ void *exists; /* dummy ptr to see if global envvar TZ already exists */
+ exists = (void *)getenv(TZ_ENVVAR);
+ /* see if there is already an envvar TZ_ENVVAR. If not, create it */
+ if (exists == NULL) {
+ /* create TZ string by pieces: */
+ sprintf(put_tz, "GMT%+ld", time_zone / 3600L);
+ if (time_zone % 3600L) {
+ offset = (int) labs(time_zone % 3600L);
+ sprintf(put_tz + strlen(put_tz), ":%02d", offset / 60);
+ if (offset % 60)
+ sprintf(put_tz + strlen(put_tz), ":%02d", offset % 60);
+ }
+ if (day_light)
+ strcat(put_tz,"DST");
+ setenv(TZ_ENVVAR, put_tz, 1);
+ }
+}
+#endif /* __SASC */
+
+/* set state as well as possible from settings found in locale.library */
+int GetPlatformLocalTimezone(sp, fill_tzstate_from_rules)
+ register struct state * ZCONST sp;
+ void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
+ ZCONST struct rule * ZCONST start,
+ ZCONST struct rule * ZCONST end);
+{
+ struct Library *LocaleBase;
+ struct Locale *ll;
+ struct Process *me = (void *) FindTask(NULL);
+ void *old_window = me->pr_WindowPtr;
+ BPTR eh;
+ int z, valid = FALSE;
+
+ /* read timezone from locale.library if TZ envvar missing */
+ me->pr_WindowPtr = (void *) -1; /* suppress any "Please insert" popups */
+ if (LocaleBase = OpenLibrary("locale.library", 0)) {
+ if (ll = OpenLocale(NULL)) {
+ z = ll->loc_GMTOffset; /* in minutes */
+ if (z == -300) {
+ if (eh = Lock("ENV:sys/locale.prefs", ACCESS_READ)) {
+ UnLock(eh);
+ valid = TRUE;
+ } else
+ z = 300; /* bug: locale not initialized, default bogus! */
+ } else
+ valid = TRUE;
+ if (valid) {
+ struct rule startrule, stoprule;
+
+ sp->timecnt = 0;
+ sp->typecnt = 1;
+ sp->charcnt = 2;
+ sp->chars[0] = sp->chars[1] = '\0';
+ sp->ttis[0].tt_abbrind = 0;
+ sp->ttis[1].tt_abbrind = 1;
+ sp->ttis[0].tt_gmtoff = -z * MINSPERHOUR;
+ sp->ttis[1].tt_gmtoff = -z * MINSPERHOUR + SECSPERHOUR;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[1].tt_isdst = 1;
+ stoprule.r_type = MONTH_NTH_DAY_OF_WEEK;
+ stoprule.r_day = 0;
+ stoprule.r_week = 5;
+ stoprule.r_mon = 10;
+ stoprule.r_time = 2 * SECSPERHOUR;
+ startrule = stoprule;
+ startrule.r_mon = 4;
+ startrule.r_week = 1;
+ if (z >= -180 && z < 150) {
+ /* At this point we make a really gratuitous assumption: */
+ /* if the time zone could be Europe, we use the European */
+ /* Union rules without checking what country we're in. */
+ /* The AmigaDOS locale country codes do not, at least in */
+ /* 2.x versions of the OS, recognize very many countries */
+ /* outside of Europe and North America. */
+ sp->typecnt = 2;
+ startrule.r_mon = 3; /* one week earlier than US DST */
+ startrule.r_week = 5;
+ } else if (z >= 150 && z <= 480 &&
+ /* no DST in alaska, hawaii */
+ (ll->loc_CountryCode == 0x55534100 /*"USA"*/ ||
+ ll->loc_CountryCode == 0x43414E00 /*"CAN"*/))
+ sp->typecnt = 2;
+ /* We check the country code for U.S. or Canada because */
+ /* most of Latin America has no DST. Even in these two */
+ /* countries there are some exceptions... */
+ /* else if... Feel free to add more cases here! */
+
+ if (sp->typecnt > 1)
+ (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
+ }
+ CloseLocale(ll);
+ }
+ CloseLibrary(LocaleBase);
+ }
+ me->pr_WindowPtr = old_window;
+ return valid;
+}
+
+#ifdef ZIP
+time_t time(time_t *tp)
+{
+ time_t t;
+ struct DateStamp ds;
+ DateStamp(&ds);
+ t = ds.ds_Tick / TICKS_PER_SECOND + ds.ds_Minute * 60
+ + (ds.ds_Days + 2922) * SECSPERDAY;
+ t = mktime(gmtime(&t));
+ /* gmtime leaves ds in the local timezone, mktime converts it to GMT */
+ if (tp) *tp = t;
+ return t;
+}
+#endif /* ZIP */
+
+#endif /* !FUNZIP && !UTIL */
+
+
+#if CRYPT || !defined(FUNZIP)
+
+/* sendpkt.c
+ * by A. Finkel, P. Lindsay, C. Sheppner
+ * returns Res1 of the reply packet
+ */
+/*
+#include <exec/types.h>
+#include <exec/memory.h>
+#include <libraries/dos.h>
+#include <libraries/dosextens.h>
+#include <proto/exec.h>
+#include <proto/dos.h>
+*/
+
+LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+
+LONG sendpkt(pid,action,args,nargs)
+struct MsgPort *pid; /* process identifier (handler message port) */
+LONG action, /* packet type (desired action) */
+ *args, /* a pointer to argument list */
+ nargs; /* number of arguments in list */
+{
+
+ struct MsgPort *replyport, *CreatePort(UBYTE *, long);
+ void DeletePort(struct MsgPort *);
+ struct StandardPacket *packet;
+ LONG count, *pargs, res1;
+
+ replyport = CreatePort(NULL,0L);
+ if( !replyport ) return(0);
+
+ packet = (struct StandardPacket *)AllocMem(
+ (long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
+ if( !packet )
+ {
+ DeletePort(replyport);
+ return(0);
+ }
+
+ packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
+ packet->sp_Pkt.dp_Link = &(packet->sp_Msg);
+ packet->sp_Pkt.dp_Port = replyport;
+ packet->sp_Pkt.dp_Type = action;
+
+ /* copy the args into the packet */
+ pargs = &(packet->sp_Pkt.dp_Arg1); /* address of 1st argument */
+ for( count=0; count<nargs; count++ )
+ pargs[count] = args[count];
+
+ PutMsg(pid,(struct Message *)packet); /* send packet */
+
+ WaitPort(replyport);
+ GetMsg(replyport);
+
+ res1 = packet->sp_Pkt.dp_Res1;
+
+ FreeMem((char *)packet,(long)sizeof(*packet));
+ DeletePort(replyport);
+
+ return(res1);
+
+} /* sendpkt() */
+
+#endif /* CRYPT || !FUNZIP */
+
+
+#if CRYPT || (defined(UNZIP) && !defined(FUNZIP))
+
+/* Agetch() reads one raw keystroke -- uses sendpkt() */
+
+int Agetch(void)
+{
+ LONG sendpkt(struct MsgPort *pid, LONG action, LONG *args, LONG nargs);
+ struct Task *me = FindTask(NULL);
+ struct CommandLineInterface *cli = BADDR(((struct Process *) me)->pr_CLI);
+ BPTR fh = cli->cli_StandardInput; /* this is immune to < redirection */
+ void *conp = ((struct FileHandle *) BADDR(fh))->fh_Type;
+ char longspace[8];
+ long *flag = (long *) ((ULONG) &longspace[4] & ~3); /* LONGWORD ALIGNED! */
+ UBYTE c;
+
+ *flag = 1;
+ sendpkt(conp, ACTION_SCREEN_MODE, flag, 1); /* assume success */
+ Read(fh, &c, 1);
+ *flag = 0;
+ sendpkt(conp, ACTION_SCREEN_MODE, flag, 1);
+ if (c == 3) /* ^C in input */
+ Signal(me, SIGBREAKF_CTRL_C);
+ return c;
+}
+
+#endif /* CRYPT || (UNZIP && !FUNZIP) */
+
+#endif /* __amiga_filedate_c*/
diff --git a/amiga/makefile.azt b/amiga/makefile.azt
new file mode 100644
index 0000000..d9390c8
--- /dev/null
+++ b/amiga/makefile.azt
@@ -0,0 +1,304 @@
+# Makefile for Zip, ZipNote, ZipCloak, ZipSplit for Aztec C 5.2
+# Also ZipLM, a version of Zip that needs much less free memory
+# -- Paul Kienitz, last updated 07 Jan 2007
+
+# Make sure platform is defined correctly, and select memory usage options:
+DEFINES = -d AMIGA -d DYN_ALLOC -d ASM_CRC
+
+CC = cc
+AS = as
+LD = ln
+LDLIBS = -lc16
+
+
+# -------- RELEASE VERSION:
+CFLAGS = -psb0e -sabfmnpu -wcr0u $(DEFINES)
+# -pbs means unsigned chars and short ints, -sabfmnpu is various small
+# optimizations, -wcr0u adjusts type checking strictness
+ASOPTS = -n -eAMIGA -eDYN_ALLOC -eCPUTEST -eINT16
+LDFLAGS = -m +q
+
+# -------- DEBUG VERSION:
+CFLAGD = -bs -psb0e -s0f0n -wcr0u $(DEFINES)
+# -bs is include source debugging info, -s0f0n is avoid hard-to-debug
+# optimizations
+LDFLAGD = -m +q -g -w
+
+# -------- MINIMUM MEMORY USAGE RELEASE VERSION:
+WSIZ = WSIZE=4096
+LOWFLAGS = $(CFLAGS) -d $(WSIZ) -d SMALL_MEM
+LOWASOPTS = $(ASOPTS) -e$(WSIZ) -eSMALL_MEM
+# Options used for assembling amiga/deflate.a; must generally match the
+# settings in DEFINES.
+
+# -------- MINIMUM MEMORY USAGE DEBUG VERSION:
+LOWFLAGD = $(CFLAGD) -d $(WSIZ) -d SMALL_MEM
+
+# the directory where we stick all the object files:
+O = obA/
+
+
+# default C rules
+.c.o :
+ $(CC) $(CFLAGS) -o $@ $*.c
+
+# rules for routines containing entries needed by utilities
+.c.oo :
+ $(CC) $(CFLAGS) -d UTIL -o $@ $*.c
+
+# rules for the low-memory version:
+
+.c.ol :
+ $(CC) $(LOWFLAGS) -o $@ $*.c
+
+# default C rules for debugging
+.c.od :
+ $(CC) $(CFLAGD) -o $@ $*.c
+
+# debugging rules for routines containing entries needed by utilities
+.c.dd :
+ $(CC) $(CFLAGD) -d UTIL -o $@ $*.c
+
+# rules for the debugging low-memory version:
+
+.c.dl :
+ $(CC) $(LOWFLAGD) -o $@ $*.c
+
+
+# object file lists
+
+ZIP_H = zip.h ziperr.h tailor.h amiga/osdep.h amiga/z-stat.h
+
+
+OBJZ = $(O)zip.o $(O)deflate.o \
+ $(O)trees.o $(O)zipfile.o $(O)zipup.o $(O)util.o $(O)timezone.o \
+ $(O)fileio.o $(O)globals.o $(O)crc32.o $(O)crypt.o $(O)ttyio.o \
+ $(O)amiga.o $(O)amigazip.o $(O)crc_68.o
+
+OBJL = $(O)zip.ol $(O)deflate.ol \
+ $(O)trees.ol $(O)zipfile.ol $(O)zipup.ol $(O)util.ol $(O)timezone.ol \
+ $(O)fileio.ol $(O)globals.ol $(O)crc32.ol $(O)crypt.ol $(O)ttyio.ol \
+ $(O)amiga.ol $(O)amigazip.ol $(O)crc_68.o
+
+OBJU = $(O)zipfile.oo $(O)fileio.oo \
+ $(O)util.oo $(O)globals.o $(O)amiga.oo $(O)amigazip.oo
+OBJN = $(O)zipnote.o $(OBJU)
+OBJC = $(O)zipcloak.o $(OBJU) $(O)crc32.oo \
+ $(O)crypt.oo $(O)ttyio.o
+OBJS = $(O)zipsplit.o $(OBJU)
+
+# These are the debuggable versions:
+
+DBJZ = $(O)zip.od $(O)deflate.od \
+ $(O)trees.od $(O)zipfile.od $(O)zipup.od $(O)util.od $(O)timezone.od \
+ $(O)fileio.od $(O)globals.od $(O)crc32.od $(O)crypt.od $(O)ttyio.od \
+ $(O)amiga.od $(O)amigazip.od $(O)crc_68.o
+
+DBJL = $(O)zip.dl $(O)deflate.dl \
+ $(O)trees.dl $(O)zipfile.dl $(O)zipup.dl $(O)util.dl $(O)timezone.dl \
+ $(O)fileio.dl $(O)globals.dl $(O)crc32.dl $(O)crypt.dl $(O)ttyio.dl \
+ $(O)amiga.dl $(O)amigazip.dl $(O)crc_68.o
+
+DBJU = $(O)zipfile.dd $(O)fileio.dd \
+ $(O)util.dd $(O)globals.od $(O)amiga.dd $(O)amigazip.dd
+DBJN = $(O)zipnote.od $(DBJU)
+DBJC = $(O)zipcloak.od $(DBJU) $(O)crc32.dd \
+ $(O)crypt.dd $(O)ttyio.od
+DBJS = $(O)zipsplit.od $(DBJU)
+
+
+# HERE WE GO:
+
+all : Zip ZipNote ZipSplit ZipCloak ZipLM
+
+z : Zip
+
+n : ZipNote
+
+s : ZipSplit
+
+c : ZipCloak
+
+l : ZipLM
+
+# Debug versions:
+
+dall : Zip.dbg ZipNote.dbg ZipSplit.dbg ZipCloak.dbg ZipLM.dbg
+
+dz : Zip.dbg
+
+dn : ZipNote.dbg
+
+ds : ZipSplit.dbg
+
+dc : ZipCloak.dbg
+
+dl : ZipLM.dbg
+
+
+Zip : $(OBJZ) $(ZIP_H)
+ $(LD) $(LDFLAGS) -o $@ $(OBJZ) $(LDLIBS)
+ -@delete Zip.dbg
+
+ZipNote : $(OBJN) $(ZIP_H)
+ $(LD) $(LDFLAGS) -o $@ $(OBJN) $(LDLIBS)
+ -@delete ZipNote.dbg
+
+ZipSplit : $(OBJS) $(ZIP_H)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
+ -@delete ZipSplit.dbg
+
+ZipCloak : $(OBJC) $(ZIP_H)
+ $(LD) $(LDFLAGS) -o $@ $(OBJC) $(LDLIBS)
+ -@delete ZipCloak.dbg
+
+ZipLM : $(OBJL) $(ZIP_H)
+ $(LD) $(LDFLAGS) -o $@ $(OBJL) $(LDLIBS)
+ -@delete ZipLM.dbg
+
+
+Zip.dbg : $(DBJZ) $(ZIP_H)
+ $(LD) $(LDFLAGD) -o Zip $(DBJZ) $(LDLIBS)
+
+ZipNote.dbg : $(DBJN) $(ZIP_H)
+ $(LD) $(LDFLAGD) -o ZipNote $(DBJN) $(LDLIBS)
+
+ZipSplit.dbg : $(DBJS) $(ZIP_H)
+ $(LD) $(LDFLAGD) -o ZipSplit $(DBJS) $(LDLIBS)
+
+ZipCloak.dbg : $(DBJC) $(ZIP_H)
+ $(LD) $(LDFLAGD) -o ZipCloak $(DBJC) $(LDLIBS)
+
+ZipLM.dbg : $(DBJL) $(ZIP_H)
+ $(LD) $(LDFLAGD) -o ZipLM $(DBJL) $(LDLIBS)
+
+
+clean : bugclean
+ -delete quiet $(OBJZ)
+ -delete quiet $(OBJL)
+ -delete quiet $(O)zipnote.o $(O)zipcloak.o $(O)zipsplit.o \
+ $(O)crypt.oo $(OBJU)
+
+bugclean :
+ -delete quiet $(DBJZ)
+ -delete quiet $(DBJL)
+ -delete quiet $(O)zipnote.od $(O)zipcloak.od $(O)zipsplit.od \
+ $(O)crypt.dd $(DBJU)
+
+cleaner : clean
+ -delete quiet Zip ZipNote ZipSplit ZipCloak ZipLM
+ -delete quiet Zip.dbg ZipNote.dbg ZipSplit.dbg ZipCloak.dbg ZipLM.dbg
+
+
+# header dependencies:
+
+$(O)zip.o $(O)zipnote.o $(O)zipcloak.o $(O)zipsplit.o $(O)crypt.o $(O)ttyio.o \
+ $(O)deflate.o $(O)trees.o $(O)zipfile.o $(O)zipup.o $(O)fileio.o $(O)util.o \
+ $(O)timezone.o $(O)crc32.o $(O)globals.o $(O)amiga.o : $(ZIP_H)
+
+$(O)zip.ol $(O)zipnote.ol $(O)zipcloak.ol $(O)zipsplit.ol $(O)crypt.ol \
+ $(O)ttyio.ol $(O)deflate.ol $(O)trees.ol $(O)zipfile.ol $(O)zipup.ol \
+ $(O)fileio.ol $(O)util.ol $(O)timezone.ol $(O)crc32.ol $(O)globals.ol \
+ $(O)amiga.ol : $(ZIP_H)
+
+$(O)crc32.oo $(O)crypt.oo $(O)zipfile.oo $(O)fileio.oo $(O)util.oo : $(ZIP_H)
+
+$(O)amigazip.o $(O)amigazip.ol $(O)amigazip.oo : amiga/amiga.h $(ZIP_H)
+
+$(O)zip.o $(O)zipnote.o $(O)zipcloak.o $(O)zipsplit.o $(O)zipup.o \
+ $(O)zip.ol $(O)zipnote.ol $(O)zipcloak.ol $(O)zipsplit.ol \
+ $(O)zipup.ol : revision.h
+
+$(O)amiga.o $(O)amiga.ol : crypt.h
+
+$(O)crc32.o $(O)crc32.oo $(O)crc32.ol $(O)crypt.o $(O)crypt.oo $(O)crypt.ol \
+ $(O)zipcloak.o $(O)zipcloak.ol $(O)zip.o $(O)zip.ol \
+ $(O)zipup.o $(O)zipup.ol \
+ $(O)zipfile.o $(O)zipfile.oo $(O)zipfile.ol \
+ $(O)fileio.o $(O)fileio.oo $(O)fileio.ol : crc32.h
+
+$(O)crypt.o $(O)crypt.oo $(O)crypt.ol $(O)ttyio.o $(O)ttyio.ol \
+ $(O)zipcloak.o $(O)zipcloak.ol $(O)zip.o $(O)zip.ol \
+ $(O)zipup.o $(O)zipup.ol : crypt.h ttyio.h
+
+$(O)timezone.o $(O)timezone.ol $(O)timezone.od $(O)timezone.dl \
+ $(O)amiga.o $(O)amiga.ol $(O)amiga.oo : timezone.h
+
+$(O)zipup.o $(O)zipup.ol : amiga/zipup.h
+
+
+# SPECIAL CASES:
+
+# -mr changes expression parsing; avoids a bogus "expression too complex" error:
+$(O)trees.o : trees.c
+ $(CC) $(CFLAGS) -mr -o $@ trees.c
+
+$(O)trees.ol : trees.c
+ $(CC) $(LOWFLAGS) -mr -o $@ trees.c
+
+$(O)trees.od : trees.c
+ $(CC) $(CFLAGD) -mr -o $@ trees.c
+
+$(O)trees.ld : trees.c
+ $(CC) $(LOWFLAGD) -mr -o $@ trees.c
+
+# Substitute the assembly version of deflate.c: (but not in debug version)
+$(O)deflate.o : amiga/deflate.a
+ $(AS) $(ASOPTS) -o $@ amiga/deflate.a
+
+$(O)deflate.ol : amiga/deflate.a
+ $(AS) $(LOWASOPTS) -o $@ amiga/deflate.a
+
+# The assembly CRC function:
+$(O)crc_68.o : amiga/crc_68.a
+ $(AS) -n -o $@ amiga/crc_68.a
+
+# Put the Amiga internal version data with today's date into amiga.c:
+$(O)amiga.o : amiga/amiga.c amiga/filedate.c amiga/stat.c
+ rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+ $(CC) $(CFLAGS) -o $@ amiga/amiga.c
+ delete env:VersionDate
+
+$(O)amiga.ol : amiga/amiga.c amiga/filedate.c amiga/stat.c
+ rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+ $(CC) $(LOWFLAGS) -o $@ amiga/amiga.c
+ delete env:VersionDate
+
+$(O)amiga.od : amiga/amiga.c amiga/filedate.c amiga/stat.c
+ rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+ $(CC) $(CFLAGD) -o $@ amiga/amiga.c
+ delete env:VersionDate
+
+$(O)amiga.ld : amiga/amiga.c amiga/filedate.c amiga/stat.c
+ rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+ $(CC) $(LOWFLAGD) -o $@ amiga/amiga.c
+ delete env:VersionDate
+
+$(O)amiga.oo : amiga/amiga.c amiga/filedate.c amiga/stat.c
+ rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+ $(CC) $(CFLAGS) -d UTIL -o $@ amiga/amiga.c
+ delete env:VersionDate
+
+$(O)amiga.dd : amiga/amiga.c amiga/filedate.c amiga/stat.c
+ rx > env:VersionDate "say '""'translate(date('E'), '.', '/')'""'"
+ $(CC) $(CFLAGD) -d UTIL -o $@ amiga/amiga.c
+ delete env:VersionDate
+
+# Put the compiler version number into amigazip.c:
+$(O)amigazip.o : amiga/amigazip.c
+ $(CC) $(CFLAGS) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.ol : amiga/amigazip.c
+ $(CC) $(LOWFLAGS) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.od : amiga/amigazip.c
+ $(CC) $(CFLAGD) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.ld : amiga/amigazip.c
+ $(CC) $(LOWFLAGD) -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.oo : amiga/amigazip.c
+ $(CC) $(CFLAGS) -d UTIL -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
+
+$(O)amigazip.dd : amiga/amigazip.c
+ $(CC) $(CFLAGD) -d UTIL -o $@ -d __VERSION__=5 -d __REVISION__=2 amiga/amigazip.c
diff --git a/amiga/match.a b/amiga/match.a
new file mode 100644
index 0000000..ec5bcf0
--- /dev/null
+++ b/amiga/match.a
@@ -0,0 +1,182 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match.a -- optional optimized asm version of longest match in deflate.c
+; Written by Jean-loup Gailly
+; Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+; using the code in match.S.
+; The major change in this code consists of removing all unaligned
+; word accesses, because they cause 68000-based Amigas to crash.
+; For maximum speed, UNALIGNED_OK can be defined in Makefile.sasc.
+; The program will then only run on 68020-based Amigas, though.
+; If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -dWSIZE=<whatever>.
+;
+; This code will run with registerized parameters too, unless SAS
+; changes parameter passing conventions between new releases of SAS/C.
+
+
+Cur_Match reg d0 ; Must be in d0!
+Best_Len reg d1
+Loop_Counter reg d2
+Scan_Start reg d3
+Scan_End reg d4
+Limit reg d5
+Chain_Length reg d6
+Scan_Test reg d7
+Scan reg a0
+Match reg a1
+Prev_Address reg a2
+Scan_Ini reg a3
+Match_Ini reg a4
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+ ifnd WSIZE
+WSIZE equ 32768
+ endc
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+
+
+ xref _max_chain_length
+ xref _prev_length
+ xref _prev
+ xref _window
+ xref _strstart
+ xref _good_match
+ xref _match_start
+ xref _nice_match
+
+
+ section match,code
+
+ xdef _match_init
+ xdef @match_init
+ xdef _longest_match
+ xdef @longest_match
+
+
+_match_init:
+@match_init:
+ rts
+
+
+_longest_match:
+ move.l 4(sp),Cur_Match
+@longest_match:
+ ifd UNALIGNED_OK
+ movem.l d2-d6/a2-a4,-(sp)
+ else
+ movem.l d2-d7/a2-a4,-(sp)
+ endc
+ move.l _max_chain_length,Chain_Length
+ move.l _prev_length,Best_Len
+ lea _prev,Prev_Address
+ lea _window+MIN_MATCH,Match_Ini
+ move.l _strstart,Limit
+ move.l Match_Ini,Scan_Ini
+ add.l Limit,Scan_Ini
+ subi.w #MAX_DIST,Limit
+ bhi.b limit_ok
+ moveq #0,Limit
+limit_ok:
+ cmp.l _good_match,Best_Len
+ bcs.b length_ok
+ lsr.l #2,Chain_Length
+length_ok:
+ subq.l #1,Chain_Length
+
+ ifd UNALIGNED_OK
+
+ move.w -MIN_MATCH(Scan_Ini),Scan_Start
+ move.w -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+
+ else
+
+ move.b -MIN_MATCH(Scan_Ini),Scan_Start
+ lsl.w #8,Scan_Start
+ move.b -MIN_MATCH+1(Scan_Ini),Scan_Start
+ move.b -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+ lsl.w #8,Scan_End
+ move.b -MIN_MATCH(Scan_Ini,Best_Len.L),Scan_End
+
+ endc
+
+ bra.b do_scan
+
+long_loop:
+
+ ifd UNALIGNED_OK
+
+ move.w -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+
+ else
+
+ move.b -MIN_MATCH-1(Scan_Ini,Best_Len.L),Scan_End
+ lsl.w #8,Scan_End
+ move.b -MIN_MATCH(Scan_Ini,Best_Len.L),Scan_End
+
+ endc
+
+short_loop:
+ lsl.w #1,Cur_Match
+ move.w 0(Prev_Address,Cur_Match.L),Cur_Match
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,do_scan
+ bra.b return
+
+do_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+
+ ifd UNALIGNED_OK
+
+ cmp.w -MIN_MATCH-1(Match,Best_Len.L),Scan_End
+ bne.b short_loop
+ cmp.w -MIN_MATCH(Match),Scan_Start
+ bne.b short_loop
+
+ else
+
+ move.b -MIN_MATCH-1(Match,Best_Len.L),Scan_Test
+ lsl.w #8,Scan_Test
+ move.b -MIN_MATCH(Match,Best_Len.L),Scan_Test
+ cmp.w Scan_Test,Scan_End
+ bne.b short_loop
+ move.b -MIN_MATCH(Match),Scan_Test
+ lsl.w #8,Scan_Test
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.w Scan_Test,Scan_Start
+ bne.b short_loop
+
+ endc
+
+ move.w #(MAX_MATCH-MIN_MATCH),Loop_Counter
+ move.l Scan_Ini,Scan
+scan_loop:
+ cmpm.b (Match)+,(Scan)+
+ dbne Loop_Counter,scan_loop
+
+ sub.l Scan_Ini,Scan
+ addq.l #(MIN_MATCH-1),Scan
+ cmp.l Best_Len,Scan
+ bls.b short_loop
+ move.l Scan,Best_Len
+ move.l Cur_Match,_match_start
+ cmp.l _nice_match,Best_Len
+ bcs.b long_loop
+return:
+ move.l Best_Len,d0
+ ifd UNALIGNED_OK
+ movem.l (sp)+,d2-d6/a2-a4
+ else
+ movem.l (sp)+,d2-d7/a2-a4
+ endc
+ rts
+
+ end
diff --git a/amiga/match_68.a b/amiga/match_68.a
new file mode 100644
index 0000000..d1a6c39
--- /dev/null
+++ b/amiga/match_68.a
@@ -0,0 +1,273 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; This is a 68000 assembly language version of the Zip function
+; longest_match(). It is written for any 680x0 based computer, but at this
+; time the feature for runtime testing of CPU type is only supported for the
+; Amiga. Hopefully a similar test for the Macintosh is possible, and for any
+; other system that supports both 68000 and 68020+ CPUs. This is written by
+; Paul Kienitz, partially derived from a simpler version by Carsten Steger,
+; derived in turn from a 386 assembly function by Jean-loup Gailly and Kai Uwe
+; Rommel... but also based directly on the C original.
+;
+; The main difference of this from other longest_match() implementations is
+; that it includes both byte based and word based versions of the function,
+; and various symbols can be defined to select whether to use one routine or
+; the other, or to do a platform-specific test at runtime. The symbols that
+; can be used to select behavior are as follows:
+;
+; CPU020 if defined, use 68020 instructions always
+; CPUTEST if defined, check at runtime for CPU type. Another symbol
+; specifying the platform-specific test must be used with this.
+; If neither of these is defined, use 68000 instructions only.
+; AMIGA use Amiga-specific test for 68020, if CPUTEST defined. Also
+; tells it to let a0/a1/d1 be clobbered by functions.
+; ATSIGN define entry symbols in @foo form as well as _foo, with
+; @longest_match taking its parm in d0 instead of on the stack.
+; WSIZE if defined, determines the sliding window size for deflate;
+; the default is 32K. If you have reduced WSIZE for the C code,
+; make sure that this module is assembled with an equivalent
+; "-dWSIZE=<whatever>" (or "-e...") switch.
+;
+; NOTE: no provision is made for 16 bit ints. All external int variables are
+; treated as 32 bit values. This also assumes that longest_match's result is
+; returned in D0.
+
+ IFND CPU020
+ IFND CPUTEST
+CPU000 equ 1
+ ENDC
+ ENDC
+
+; global variables:
+ xref _max_chain_length ; unsigned int
+ xref _prev_length ; unsigned int
+ xref _match_start ; unsigned int
+ xref _strstart ; unsigned int
+ xref _good_match ; signed int
+ xref _nice_match ; signed int
+ xref _window ; array of unsigned char
+ xref _prev ; array of unsigned short
+
+; our entry points:
+ xdef _match_init ; void match_init(void);
+ xdef _longest_match ; int longest_match(unsigned cur_match);
+ IFD ATSIGN
+ xdef @match_init ; for SAS assembler
+ xdef @longest_match ; ditto
+ ENDC
+
+; flag variable for remembering CPU type:
+ IFD CPUTEST
+ section cpuflag,data
+is020: ds.w 1
+ ENDC
+
+
+ section match,code
+_match_init:
+ IFD ATSIGN
+@match_init:
+ ENDC
+
+ IFD CPUTEST ; now check for platform type
+ IFD AMIGA ; Amiga specific test for '020 CPU:
+
+ xref _SysBase
+
+ NOLIST
+ INCLUDE 'exec/execbase.i'
+ LIST
+
+ clr.w is020 ; default value is 68000
+ move.l _SysBase,a0
+ btst #AFB_68020,AttnFlags+1(a0)
+ beq.s cheap
+ move.w #1,is020
+
+cheap:
+ ELSE ; !AMIGA
+
+ !! Write an '020-detector for your system here!
+
+ ENDC ; AMIGA
+ ENDC ; CPUTEST
+ rts ; match_init consists only of rts if CPUTEST unset
+
+
+ IFD AMIGA
+SAVEREGS reg d3-d7/a2/a3/a5 ; don't protect d0/d1/a0/a1
+ ELSE
+SAVEREGS reg d1/d3-d7/a0-a3/a5 ; protect all but d0 return val
+ ENDC
+
+Cur_Match equr d0 ; Must be in d0!
+Best_Len equr d1
+Scan_Start equr d3
+Scan_End equr d4
+Limit equr d5
+Chain_Length equr d6
+Scan_Test equr d7
+Scan equr a0
+Match equr a1
+Prev_Address equr a2
+Scan_Ini equr a3
+Match_Ini equr a5
+
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+ IFND WSIZE
+WSIZE equ 32768
+ ENDC
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+
+_longest_match:
+ move.l 4(sp),Cur_Match ; stack arg to register
+ IFD ATSIGN
+@longest_match:
+ ENDC
+ movem.l SAVEREGS,-(sp)
+
+; setup steps common to byte and word versions:
+ move.l _max_chain_length,Chain_Length
+ move.l _prev_length,Best_Len
+ lea _prev,Prev_Address
+ lea _window,Match_Ini
+ move.l _strstart,Limit
+ move.l Match_Ini,Scan_Ini
+ addq #MIN_MATCH,Match_Ini
+ add.l Limit,Scan_Ini
+ subi.w #MAX_DIST,Limit
+ bhi.s limit_ok
+ moveq #0,Limit
+limit_ok:
+ cmp.l _good_match,Best_Len
+ bcs.s length_ok
+ lsr.l #2,Chain_Length
+length_ok:
+ subq.l #1,Chain_Length
+
+ IFD CPUTEST
+ tst.w is020 ; can we use '020 stuff today?
+ bne WORD_match
+ ENDC
+
+ IFND CPU020
+
+; for 68000 or 68010, use byte operations:
+ moveq #0,Scan_Start ; clear 2nd and 4th bytes, use 1st & 3rd
+ moveq #0,Scan_End
+ moveq #0,Scan_Test
+ move.b (Scan_Ini),Scan_Start
+ swap Scan_Start
+ move.b 1(Scan_Ini),Scan_Start
+ move.b -1(Scan_Ini,Best_Len),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len),Scan_End
+ bra.s bdo_scan
+
+blong_loop:
+ move.b -1(Scan_Ini,Best_Len),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len),Scan_End
+
+bshort_loop:
+ add.w Cur_Match,Cur_Match
+ move.w 0(Prev_Address,Cur_Match.l),Cur_Match
+ cmp.l Limit,Cur_Match
+ dbls Chain_Length,bdo_scan
+ bra return
+
+bdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ move.b -MIN_MATCH-1(Match,Best_Len),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH(Match,Best_Len),Scan_Test
+ cmp.l Scan_Test,Scan_End
+ bne.s bshort_loop
+ move.b -MIN_MATCH(Match),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.l Scan_Test,Scan_Start
+ bne.s bshort_loop
+ move.w #(MAX_MATCH-MIN_MATCH),Scan_Test
+ lea MIN_MATCH(Scan_Ini),Scan
+
+bscan_loop:
+ cmpm.b (Match)+,(Scan)+
+ dbne Scan_Test,bscan_loop
+ subq #1,Scan
+
+ sub.l Scan_Ini,Scan
+ cmp.l Best_Len,Scan
+ bls.s bshort_loop
+ move.l Scan,Best_Len
+ move.l Cur_Match,_match_start
+ cmp.l _nice_match,Best_Len
+ bcs.s blong_loop
+ IFD CPUTEST
+ bra return
+ ENDC
+
+ ENDC ; !CPU020
+
+ IFND CPU000
+
+; for 68020 or higher, use word operations even on odd addresses:
+WORD_match:
+ move.w (Scan_Ini),Scan_Start
+ move.w -1(Scan_Ini,Best_Len),Scan_End
+ bra.s wdo_scan
+
+wlong_loop:
+ move.w -1(Scan_Ini,Best_Len),Scan_End
+
+wshort_loop:
+ add.w Cur_Match,Cur_Match
+ move.w (Prev_Address,Cur_Match.l),Cur_Match
+ cmp.l Limit,Cur_Match
+ dbls Chain_Length,wdo_scan
+ bra.s return
+
+wdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ cmp.w -MIN_MATCH-1(Match,Best_Len),Scan_End
+ bne.s wshort_loop
+ cmp.w -MIN_MATCH(Match),Scan_Start
+ bne.s wshort_loop
+ moveq #((MAX_MATCH-MIN_MATCH)/2),Scan_Test ; value = 127
+ lea MIN_MATCH(Scan_Ini),Scan
+
+wscan_loop:
+ cmpm.w (Match)+,(Scan)+
+ dbne Scan_Test,wscan_loop
+ subq #2,Scan
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.b (Scan),Scan_Test
+ bne steven
+ addq #1,Scan
+steven:
+ sub.l Scan_Ini,Scan
+ cmp.l Best_Len,Scan
+ bls.s wshort_loop
+ move.l Scan,Best_Len
+ move.l Cur_Match,_match_start
+ cmp.l _nice_match,Best_Len
+ bcs.s wlong_loop
+
+ ENDC ; !CPU000
+
+return:
+ move.l Best_Len,d0 ; function return value
+ movem.l (sp)+,SAVEREGS
+ rts
+
+ end
diff --git a/amiga/osdep.h b/amiga/osdep.h
new file mode 100644
index 0000000..c573cf8
--- /dev/null
+++ b/amiga/osdep.h
@@ -0,0 +1,119 @@
+/*
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __amiga_osdep_h
+#define __amiga_osdep_h
+
+/* default to MEDIUM_MEM, but allow makefile override */
+#if ( (!defined(BIG_MEM)) && (!defined(SMALL_MEM)))
+# define MEDIUM_MEM
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+# define IZ_CHECK_TZ
+#endif
+
+#ifndef IZTZ_GETLOCALETZINFO
+# define IZTZ_GETLOCALETZINFO GetPlatformLocalTimezone
+#endif
+
+/* AmigaDOS can't even support disk partitions over 4GB, let alone files */
+#define NO_LARGE_FILE_SUPPORT
+#ifdef LARGE_FILE_SUPPORT
+# undef LARGE_FILE_SUPPORT
+#endif
+
+#define USE_CASE_MAP
+#define USE_EF_UT_TIME
+#define HANDLE_AMIGA_SFX
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+#define EXIT(e) ClearIOErr_exit(e)
+void ClearIOErr_exit(int e);
+
+#include "amiga/z-stat.h"
+
+#ifdef __SASC
+# include <sys/types.h>
+# include <exec/execbase.h>
+# if (defined(_M68020) && (!defined(__USE_SYSBASE)))
+ /* on 68020 or higher processors it is faster */
+# define __USE_SYSBASE /* to use the pragma libcall instead of syscall */
+# endif /* to access functions of the exec.library */
+# include <proto/exec.h> /* see SAS/C manual:part 2,chapter 2,pages 6-7 */
+# include <proto/dos.h>
+# if (defined(_M68020) && !defined(UNALIGNED_OK))
+# define UNALIGNED_OK
+# endif
+# ifndef REENTRANT
+# define REENTRANT
+# endif
+# if (defined(_NEAR_DATA) && !defined(DYN_ALLOC))
+# define DYN_ALLOC
+# endif
+# ifdef DEBUG
+# include <sprof.h> /* profiler header file */
+# endif
+# ifndef IZTZ_SETLOCALTZINFO
+ /* XXX !! We have really got to find a way to operate without these. */
+# define IZTZ_SETLOCALTZINFO
+# endif
+
+/*
+ A word on short-integers and SAS/C (a bug of [mc]alloc?)
+ Using short integers (i.e. compiling with option SHORT-INTEGERS) is
+ *not* recommended. To get maximum compression ratio the window size stored
+ in WSIZE should be 32k (0x8000). However, since the size of the window[]
+ array is 2*WSIZE, 65536 bytes must be allocated. The calloc function can
+ only allocate UINT_MAX (defined in limits.h) bytes which is one byte short
+ (65535) of the maximum window size if you are compiling with short-ints.
+ You'll get an error message "Out of memory (window allocation)" whenever
+ you try to deflate. Note that the compiler won't produce any warning.
+ The maximum window size with short-integers is therefore 32768 bytes.
+ The following is only implemented to allow the use of short-integers but
+ it is once again not recommended because of a loss in compression ratio.
+*/
+# if (defined(_SHORTINT) && !defined(WSIZE))
+# define WSIZE 0x4000 /* only half of maximum window size */
+# endif /* possible with short-integers */
+#endif /* __SASC */
+/*
+ With Aztec C, using short integers imposes no size limits and makes
+ the program run faster, even with 32 bit CPUs, so it's recommended.
+*/
+#ifdef AZTEC_C
+# define NO_UNISTD_H
+# define NO_RMDIR
+# define BROKEN_FSEEK
+# ifndef IZTZ_DEFINESTDGLOBALS
+# define IZTZ_DEFINESTDGLOBALS
+# endif
+#endif
+
+extern int real_timezone_is_set;
+void tzset(void);
+#define VALID_TIMEZONE(tempvar) (tzset(), real_timezone_is_set)
+
+#ifdef ZCRYPT_INTERNAL
+# ifndef CLIB_EXEC_PROTOS_H
+ void *FindTask(void *);
+# endif
+# define ZCR_SEED2 (unsigned)(ulg)FindTask(NULL)
+#endif
+
+int Agetch(void); /* getch() like function, in amiga/filedate.c */
+char *GetComment(char *);
+
+#define FOPR "rb"
+#define FOPM "rb+"
+#define FOPW "wb"
+/* prototype for ctrl-C trap function */
+void _abort(void);
+
+#endif /* !__amiga_osdep_h */
diff --git a/amiga/smakefile b/amiga/smakefile
new file mode 100644
index 0000000..ce1317d
--- /dev/null
+++ b/amiga/smakefile
@@ -0,0 +1,662 @@
+#===========================================================================
+# Makefile for Zip, ZipNote, ZipCloak, ZipSplit AMIGA SAS/C Version 6.58
+# Version: 2.3 last revised: 07 Jan 2007
+#===========================================================================
+# -John Bush, <John.Bush@East.Sun.COM>
+# or: <JBush@Bix.COM>
+
+# updated for SAS/C Version 6.56+ and AmigaDOS 3.1 (V40)
+# by Haidinger Walter, <walthaid@unix.ict.tuwien.ac.at>
+
+# additional supplements and maintenance by Paul Kienitz
+
+# This makefile should work with at least AmigaDOS 2.04 (V37) (not tested)
+# and will probably not work with AmigaDOS 1.3 (V34)
+
+# If you have any improvements, critics or else please feel free to mail.
+# Any response is appreciated. Haidinger Walter <walthaid@unix.ict.tuwien.ac.at>
+
+# Available targets:
+# all builds all executeables below
+# zip builds zip executeable
+# zipsplit builds zipsplit executeable
+# zipcloak builds zipcloak executeable
+# zipnote builds zipnote executeable
+# ziplm builds low memory version of zip executable
+# clean remove all files created by the compilation
+# spotless like clean target but removes binaries too
+
+
+##########################
+# USER MACRO DEFINITIONS #
+##########################
+
+# *** NOTE ***
+# The assembly version is not implemented yet.
+# (Un)commenting the assembler macros has no effect unless the
+# file dependencies are changed too.
+# Most of the amiga/*.a files do not assmble with 68000 instructions.
+# Any help is appreciated, of course.
+
+# Set the processor to generate code for.
+# Compiler: ANY 68000 68010 68020 68030 68040 68060
+# Assembler: 0 0 1 2 3 4 n/a
+# Defaults: ANY and 0
+#
+CUSECPU = ANY
+AUSECPU = 0
+
+# UNCOMMENT to use 68020 instructions in the assembly version of deflate.o
+# Only use if code is generated for 68020 or higher processors above.
+# Note: You could use CPUTEST too to enable runtime cpu detection.
+# However, it is not recommended since both 68000 and 68020 code will be
+# included which would be an unnecessary increase in size.
+# (see amiga/deflate.a for more information)
+#
+#AUSE020 = CPU020
+
+# To disable the assembler replacements and use the standard C source,
+# you have to change the Zip and ZipLM dependencies. See below for details.
+# (remember that assembler use is *not* implemented yet)
+
+# Uncomment both CUTIL and LUTIL to make use of utility.library of OS 2.04+
+# The utility.library is *not* used for UnZipSFX to ensure maximum portability
+# between the different Amiga systems (minimal config: 68000 and OS 1.2).
+# You can change this by adding the $(LUTIL) macro in the UnZipSFX linking
+# rules (See below: Final output targets, UnZipSFX:).
+# WARNINGS when using the utility library:
+# 1. All Executables will *only* work with AmigaDOS 2.04 (v37) or higher.
+# 2. You *need not* compile/link with short-integers using the
+# utility.library. It will crash your machine. See Libraries below.
+#
+# Default: commented (not used)
+#
+#CUTIL = UTILLIB DEFINE=_UTILLIB
+#LUTIL = WITH SC:LIB/utillib.with # include necessary linker defines
+# Choose one stack-handling method (default=faster)
+# StackExtend: Dynamic runtime stack extension. You won't notice stack overflows.
+# StackCheck: On a stack overflow a requester appears which allows you to exit.
+# Note that either stack watching will slow down your executable because of the
+# extra code run on each function entry. On the other hand, you won't crash
+# anymore due to stack overflows. However, you should not have *any* stack
+# problems with Info-ZIP programs if you raise your stack to 10000 (which I'd
+# recommend as a minimum default stack for all applications) or more using the
+# shell stack command. Type 'Stack 20000' or add it to your S:Shell-Startup.
+# BTW: Typing 'Stack' prints your current stack size.
+#
+CSTACK = NOSTACKCHECK STACKEXTEND # slow, but always works
+#CSTACK = STACKCHECK NOSTACKEXTEND # slow, requester & graceful exit
+#CSTACK = NOSTACKCHECK NOSTACKEXTEND # faster but relies on larger stack (>=10K)
+
+
+#
+# LIBRARIES
+# ---------
+
+# Choose one DATAOPTS , SASLIB , ASMOPTS and LSTARTUP
+# Always comment/uncomment all macros of a set.
+
+# Library to use with near data and 2-byte integers
+# Notes: o slower than 4-byte integers with 68000 cpu
+# o *not* recommended due to poor overall performance
+# o see comment in amiga/osdep.h
+#DATAOPTS = DATA=NEAR SHORTINTEGERS DEF=_NEAR_DATA
+#SASLIB = scs
+#ASMOPTS = -dINT16
+#LSTARTUP = cres.o
+
+# Library to use with near data and 4-byte integers (DEFAULT)
+# *** use this with the utility.library ***
+DATAOPTS = DATA=NEAR DEF=_NEAR_DATA
+SASLIB = sc
+ASMOPTS =
+LSTARTUP = cres.o
+
+# Library to use with far data and 2-byte integers
+# use if DYN_ALLOC is not defined
+# old default - far data always works but is slower
+#DATAOPTS = DATA=FAR SHORTINTEGERS DEF=_FAR_DATA
+#SASLIB = scsnb
+#ASMOPTS = -dINT16
+#LSTARTUP = c.o
+
+# Library to use with far data and 4-byte integers
+# if everything else fails: try this
+#DATAOPTS = DATA=FAR DEF=_FAR_DATA
+#SASLIB = scnb
+#ASMOPTS =
+#LSTARTUP = c.o
+
+
+#
+# DEBUGGING
+# ---------
+
+# Default: No debugging information added.
+# The three macros below will be overwritten if you choose to add
+# debug info, therefore no need to comment.
+
+CDBG = NODEBUG NOPROFILE NOCOVERAGE # default: no debug info
+ADBG =
+LDBG = STRIPDEBUG # default: no debug info
+
+# Compiler and loader debug flags. Uncomment as needed. Recomment when done.
+# Optimization disabled for faster compilation (by using NOOPT)
+
+#CDBG1 = DEF=DEBUG DEF=DEBUG_TIME # enables Info-Zip's debug output
+
+# Enable profiling and coverage when desired. Option COVERAGE commented
+# seperately because running coverage may corrupt your drive in case of a
+# system crash since a file 'cover.dat' is created in your working directory.
+# Note that the use of COVERAGE forces the use of the c.o startup module.
+
+#CDBG2 = PROFILE
+#CDBG3 = COVERAGE # must use c.o startup code:
+#LSTARTUP = c.o # Uncomment *only* when you use COVERAGE
+
+# *Uncomment* here macros CDBG, ADBG and LDBG to include debugging information
+
+#CDBG = $(CDBG1) $(CDBG2) $(CDBG3) ADDSYM DEBUG=FULLFLUSH STACKCHECK NOOPT
+#ADBG = DEBUG
+#LDBG = ADDSYM
+
+# Optional use of memwatch.library which can be found in your
+# sc:extras/memlib directory. Please read the short docs (memlib.doc).
+# Note that memwatch.library has a small bug: MWTerm() displays always
+# the first entry.
+# Get the latest version from aminet (dev/debug/memlib.lha) or
+# contact me to get the patch. Uncomment all macros to use.
+#CMEMLIB = DEFINE=MWDEBUG=1 # define to enable library
+#LMEMLIB = SC:LIB/memwatch.lib # path to library
+#LSTARTUP = c.o # must use c.o with memlib!
+
+
+#
+# MAPPING
+# -------
+
+# Map filenames used when mapping (no need to comment)
+#
+MAPFZ = zip.map # Zip map filename
+MAPFN = zipnote.map # ZipNote map filename
+MAPFC = zipcloak.map # ZipCloak map filename
+MAPFS = zipsplit.map # ZipSplit map filename
+MAPFL = ziplm.map # Zip low memory version map filename
+
+# Map file output: Uncomment to highlight and bold headings.
+#
+#MAPFSTYLE = FANCY
+
+# Map flags for each EXECUTABLE. Uncomment to enable mapping.
+# For map options please refer to:
+# SAS/C v6 manual, volume 1: user's guide, chapter 8, page 136: map
+# Default: all options enabled: f,h,l,o,s,x
+# |-> options start here
+#LMAPZ = $(MAPFSTYLE) MAP $(MAPFZ) f,h,l,o,s,x # Zip maps
+#LMAPN = $(MAPFSTYLE) MAP $(MAPFN) f,h,l,o,s,x # ZipNote maps
+#LMAPC = $(MAPFSTYLE) MAP $(MAPFC) f,h,l,o,s,x # ZipCloak maps
+#LMAPS = $(MAPFSTYLE) MAP $(MAPFS) f,h,l,o,s,x # ZipSplit maps
+#LMAPL = $(MAPFSTYLE) MAP $(MAPFL) f,h,l,o,s,x # Zip lowmem maps
+
+#
+# LISTINGS
+# --------
+
+# Listfile-extensions for each executable (enter *with* dot)
+#
+LISTEXTZ = .lst # extension for Zip listfiles
+LISTEXTU = .ulst # extension for utility listfiles (ZipNote,ZipCloak,ZipSplit)
+LISTEXTL = .llst # extension for Zip low memory listfiles
+
+
+# List files and cross references for each OBJECT.
+# Add/remove flags as needed. Not all listed by default.
+# Use LISTINCLUDES to determine the dependencies for smake
+#
+CLISTOPT = LISTHEADERS LISTMACROS # LISTSYSTEM LISTINCLUDES
+CXREFOPT = XHEAD XSYS
+#
+# Uncomment to enable listing (default: commented)
+# *** WARNING: List files require *lots* of disk space!
+#
+#CLIST = LIST $(CLISTOPT)
+#CXREF = XREF $(CXREFOPT)
+
+
+#
+# SUPPRESSED COMPILER WARNINGS
+# ----------------------------
+
+# Compiler warnings to ignore
+#
+# Warning 105 : module does not define any externally-known symbols
+# Warning 304 : Dead assignment eliminated...
+# Note 306 : ...function inlined...
+# Warning 317 : possibly uninitialized variable...
+# Comment to enable.
+#
+CIGNORE = IGNORE=105,304,306,317
+
+
+#
+# OBJECT EXTENSIONS
+#
+
+# Extensions used for objects of each executeable.
+# Transformation rules require unique extensions.
+# Enter *with* dot.
+#
+O = .o # extension for Zip objects
+OU = .uo # extension for utility objects (ZipNote, ZipSplit and ZipCloak)
+OL = .lo # extension for low memory Zip objects
+
+
+# Filename used to store converted options from environment variable
+# LOCAL_ZIP. Default: scoptions_local_zip
+#
+CWITHOPT = scoptions_local_zip
+
+
+# Filenames to store compiler options to prevent command line overflow
+#
+# Common options file for Zip and other executables
+CFILE = scoptions-zip
+
+
+# Temp filenames for object lists to load using linker "WITH" command.
+OBJLISTZ = zip_objlist.with # Zip object list
+OBJLISTN = zipnote_objlist.with # ZipNote object list
+OBJLISTC = zipcloak_objlist.with # ZipCloak object list
+OBJLISTS = zipsplit_objlist.with # ZipSplit object list
+OBJLISTL = ziplm_objlist.with # Zip low-mem object list
+
+
+# Filenames to store linker options
+#
+LWITHZ = zip.lnk # zip linker options
+LWITHN = zipnote.lnk # zipnote linker options
+LWITHC = zipcloak.lnk # zipcloak linker options
+LWITHS = zipsplit.lnk # zipsplit linker options
+LWITHL = ziplm.lnk # zip low-mem linker options
+
+
+# Define AMIGA_BETA to print "Beta Notice" up front. See tailor.h.
+# Undefine AMIGA_BETA when building a released version.
+#CDEFBETA = DEF=AMIGA_BETA
+
+#####################################
+# NOTHING TO CHANGE BEYOND HERE ... #
+#####################################
+# (except for C/asm dependencies)
+
+# Define MEDIUM_MEM for production release (per Paul Kienitz).
+# This reduces runtime memory requirement but not speed or compression.
+# Note: Do *not* use BIG_MEM or MMAP since it isn't yet supported by the
+ assembler version of deflate.c : amiga/deflate.a
+CUSEMEM = DEF=MEDIUM_MEM
+AUSEMEM = -DMEDIUM_MEM # for asm deflate.o, must match above
+
+
+# Defines for building low-memory use version of Zip
+WSIZEL = WSIZE=4096 # deflate.c window size for low-mem version
+CLOWMEM = DEF=SMALL_MEM DEF=$(WSIZEL)
+ALOWMEM = -DSMALL_MEM -D$(WSIZEL) # for asm deflate.o, must match above
+
+
+# Compiler definitions
+#
+CC = sc
+#
+# Optimizer flags
+#
+OPTPASSES = 6 # set number of global optimizer passes
+#
+OPT1 = OPT OPTINL OPTINLOCAL OPTTIME OPTLOOP OPTSCHED
+OPT2 = OPTCOMP=$(OPTPASSES) OPTDEP=$(OPTPASSES) OPTRDEP=$(OPTPASSES)
+OPT = $(OPT1) $(OPT2)
+
+
+# Compiler flags
+#
+CDEFINES = $(CMEMLIB) $(CDEFBETA) DEF=AMIGA
+COPTIONS = $(DATAOPTS) CODE=NEAR CPU=$(CUSECPU) VERBOSE PARAMETERS=BOTH NOMINC
+COPTIONS = $(COPTIONS) ERRORREXX NOERRORCONSOLE MEMSIZE=HUGE $(CLIST) $(CXREF)
+COPTIONS = $(COPTIONS) $(CSTACK) $(CUTIL) STRICT UNSCHAR NOICONS STRINGMERGE
+CFLAGS = $(CDEFINES) $(COPTIONS) $(OPT) $(CDBG) $(CIGNORE)
+
+
+# Linker definitions
+# See SASLIB definition above
+#
+LD = slink
+# special linker flags for pure (i.e. resident) binary.
+LDFLAGSS = FROM SC:LIB/$(LSTARTUP)
+# common linker flags for all other executeables
+LDFLAGSC = FROM SC:LIB/c.o
+LDFLAGS2 = NOICONS $(LDBG)
+LIBFLAGS = LIB $(LMEMLIB) SC:LIB/$(SASLIB).lib SC:LIB/amiga.lib
+
+
+# Assembler definitions
+#
+ASM = asm
+#
+# Options used for assembling amiga/deflate.a
+# Must match defines in C-Source.
+#
+AFLAGS0 = -d__SASC -dSASC -dAMIGA
+AFLAGS1 = $(AUSE020) $(ASMOPTS) $(ADBG)
+AFLAGS2 = -m$(AUSECPU) -jm -iINCLUDE:
+AFLAGS = $(AFLAGS0) $(AFLAGS1) $(AFLAGS2)
+ASMOPTSZ = $(AFLAGS) $(AUSEMEM) -dDYN_ALLOC # Zip asm flags
+ASMOPTSL = $(AFLAGS) $(ALOWMEM) # Zip low-mem version asm flags
+
+
+##################
+# TARGET OBJECTS #
+##################
+
+
+# Zip objects
+OBJZ1 = zip$(O) zipfile$(O) zipup$(O) fileio$(O) util$(O) globals$(O)
+OBJZ2 = crc32$(O) crypt$(O) timezone$(O) ttyio$(O)
+OBJZI = deflate$(O) trees$(O)
+OBJZA = amiga$(O) amigazip$(O) stat$(O) filedate$(O)
+OBJZ = $(OBJZ1) $(OBJZ2) $(OBJZI) $(OBJZA)
+
+# Shared utility objects for ZipNote, ZipCloak and ZipSplit
+OBJU1 = globals$(O)
+OBJUU = zipfile$(OU) fileio$(OU) timezone$(O) util$(OU)
+OBJUA = amigazip$(OU) amiga$(O) stat$(O) filedate$(O)
+OBJU = $(OBJU1) $(OBJUU) $(OBJUA)
+
+# ZipNote objects
+OBJN1 = zipnote$(O)
+OBJN = $(OBJN1) $(OBJU)
+
+# ZipCloak objects
+OBJC1 = zipcloak$(O)
+OBJCU = $(OBJU) crypt$(OU)
+OBJCS = crc32$(OU) ttyio$(O)
+OBJC = $(OBJC1) $(OBJCU) $(OBJCS)
+
+#ZipSplit objects
+OBJS1 = zipsplit$(O)
+OBJS = $(OBJS1) $(OBJU)
+
+# ZipLM objects
+OBJL1 = zip$(OL) zipfile$(OL) zipup$(OL) fileio$(OL) util$(OL) globals$(OL)
+OBJL2 = crc32$(OL) crypt$(OL) timezone$(OL) ttyio$(OL)
+OBJLI = deflate$(OL) trees$(OL)
+OBJLA = amiga$(OL) amigazip$(OL) stat$(OL) filedate$(OL)
+OBJL = $(OBJL1) $(OBJL2) $(OBJLI) $(OBJLA)
+
+# Common header files
+ZIP_H1 = zip.h ziperr.h tailor.h
+ZIP_HA = amiga/osdep.h amiga/z-stat.h
+ZIP_H = $(ZIP_H1) $(ZIP_HA)
+
+# Output targets
+ZIPS = Zip ZipNote ZipCloak ZipSplit ZipLM
+
+
+# Temp filenames for object lists to load using linker "WITH" command.
+OBJLISTZ = zip_objlist.with # Zip object list
+OBJLISTN = zipnote_objlist.with # ZipNote object list
+OBJLISTC = zipcloak_objlist.with # ZipCloak object list
+OBJLISTS = zipsplit_objlist.with # ZipSplit object list
+OBJLISTL = ziplm_objlist.with # Zip low-mem object list
+
+#######################################
+# DEFAULT TARGET AND PROCESSING RULES #
+#######################################
+
+all: request flush $(ZIPS)
+
+# Zip transformation rules
+#
+.c$(O):
+ $(CC) WITH=$(CFILE) $(CUSEMEM) LISTFILE=$>$(LISTEXTZ) OBJNAME=$@ $*.c
+
+# Zip low-memory version transformation rules
+#
+.c$(OL):
+ $(CC) WITH=$(CFILE) $(CLOWMEM) LISTFILE=$>$(LISTEXTL) OBJNAME=$@ $*.c
+
+# Utilities (ZipNote, ZipCloak and ZipSplit) transformation rules
+#
+.c$(OU):
+ $(CC) WITH=$(CFILE) $(CUSEMEM) DEF=UTIL LISTFILE=$>$(LISTEXTU) OBJNAME=$@ $*.c
+
+
+#########################
+# Final output targets. #
+#########################
+
+
+zip: local_zip CommonFlags $(OBJZ)
+ @Echo "$(OBJZ)" > $(OBJLISTZ)
+ Type $(OBJLISTZ)
+ @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTZ) $(LIBFLAGS)" \
+ "$(LDFLAGS2) $(LMAPZ)" >$(LWITHZ)
+ Type $(LWITHZ)
+ $(LD) TO Zip WITH $(LWITHZ)
+
+zipnote: local_zip CommonFlags $(OBJN)
+ @Echo "$(OBJN)" > $(OBJLISTN)
+ Type $(OBJLISTN)
+ @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTN) $(LIBFLAGS) " \
+ "$(LDFLAGS2) $(LMAPN)" >$(LWITHN)
+ Type $(LWITHN)
+ $(LD) TO ZipNote WITH $(LWITHN)
+
+zipcloak: local_zip CommonFlags $(OBJC)
+ @Echo "$(OBJC)" > $(OBJLISTC)
+ Type $(OBJLISTC)
+ @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTC) $(LIBFLAGS) " \
+ "$(LDFLAGS2) $(LMAPC)" >$(LWITHC)
+ Type $(LWITHC)
+ $(LD) TO ZipCloak WITH $(LWITHC)
+
+zipsplit: local_zip CommonFlags $(OBJS)
+ @Echo "$(OBJS)" > $(OBJLISTS)
+ Type $(OBJLISTS)
+ @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTS) $(LIBFLAGS) " \
+ "$(LDFLAGS2) $(LMAPS)" >$(LWITHS)
+ Type $(LWITHS)
+ $(LD) TO ZipSplit WITH $(LWITHS)
+
+ziplm: local_zip CommonFlags $(OBJL)
+ @Echo "$(OBJL)" > $(OBJLISTL)
+ Type $(OBJLISTL)
+ @Echo "$(LDFLAGSS) $(LUTIL) WITH $(OBJLISTL) $(LIBFLAGS) " \
+ "$(LDFLAGS2) $(LMAPL)" >$(LWITHL)
+ Type $(LWITHL)
+ $(LD) TO ZipLM WITH $(LWITHL)
+
+
+clean:
+ -Delete >nil: $(OBJZ) quiet
+ -Delete >nil: $(OBJN) quiet
+ -Delete >nil: $(OBJC) quiet
+ -Delete >nil: $(OBJS) quiet
+ -Delete >nil: $(OBJL) quiet
+ -Delete >nil: $(OBJLISTZ) $(OBJLISTL) $(OBJLISTN) $(OBJLISTS) $(OBJLISTC) quiet
+ -Delete >nil: $(MAPFZ) $(MAPFN) $(MAPFC) $(MAPFS) $(MAPFL) quiet
+ -Delete >nil: \#?$(LISTEXTZ) \#?$(LISTEXTU) \#?$(LISTEXTL) quiet
+ -Delete >nil: $(CWITHOPT) $(CFILE) quiet
+ -Delete >nil: $(LWITHZ) $(LWITHN) $(LWITHC) $(LWITHS) $(LWITHL) quiet
+ -Delete >nil: env:VersionDate quiet
+ -Delete >nil: \#?.q.?? \#?.tmp \#?.cov quiet
+
+spotless: clean
+ -Delete >nil: $(ZIPS) quiet
+
+
+################
+# DEPENDENCIES #
+################
+
+# To change between the assembler and C sources, you have to comment/uncomment
+# the approprite lines. C sources are marked by #C-src and assembler sources
+# #asm-src at the end.
+# Zip dependencies:
+#
+
+zip$(O): zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipup$(O): zipup.c $(ZIP_H) revision.h crc32.h crypt.h amiga/zipup.h
+zipfile$(O): zipfile.c $(ZIP_H) revision.h crc32.h
+crypt$(O): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(O): ttyio.c $(ZIP_H) crypt.h ttyio.h
+deflate$(O): deflate.c $(ZIP_H) #C-src
+trees$(O): trees.c $(ZIP_H)
+fileio$(O): fileio.c $(ZIP_H) crc32.h
+util$(O): util.c $(ZIP_H)
+crc32$(O): crc32.c $(ZIP_H) crc32.h
+globals$(O): globals.c $(ZIP_H)
+timezone$(O): timezone.c $(ZIP_H) timezone.h
+# Amiga specific objects
+stat$(O): amiga/stat.c amiga/z-stat.h
+filedate$(O): amiga/filedate.c crypt.h timezone.h
+amiga$(O): amiga/amiga.c ziperr.h
+amigazip$(O): amiga/amigazip.c $(ZIP_H) amiga/amiga.h env:Workbench
+# Substitute assembly version of deflate.c:
+#deflate$(O): amiga/deflate.a #asm-src
+# $(ASM) $(ASMOPTSZ) -o$@ $*.a #asm-src
+
+
+# Utility (ZipNote, ZipCloak, ZipSplit) dependencies:
+#
+zipnote$(O): zipnote.c $(ZIP_H) revision.h
+zipcloak$(O): zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipsplit$(O): zipsplit.c $(ZIP_H) revision.h
+zipfile$(OU): zipfile.c $(ZIP_H) revision.h crc32.h
+fileio$(OU): fileio.c $(ZIP_H) crc32.h
+util$(OU): util.c $(ZIP_H)
+crc32$(OU): crc32.c $(ZIP_H) crc32.h
+crypt$(OU): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+# Amiga specific objects
+amigazip$(OU): amiga/amigazip.c $(ZIP_H) amiga/amiga.h env:Workbench
+
+# ZipLM dependencies:
+#
+zip$(OL): zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipup$(OL): zipup.c $(ZIP_H) revision.h crc32.h crypt.h amiga/zipup.h
+zipfile$(OL): zipfile.c $(ZIP_H) revision.h crc32.h
+crypt$(OL): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OL): ttyio.c $(ZIP_H) crypt.h ttyio.h
+deflate$(OL): deflate.c $(ZIP_H)
+trees$(OL): trees.c $(ZIP_H)
+fileio$(OL): fileio.c $(ZIP_H) crc32.h
+util$(OL): util.c $(ZIP_H)
+crc32$(OL): crc32.c $(ZIP_H)
+globals$(OL): globals.c $(ZIP_H)
+timezone$(OL): timezone.c $(ZIP_H) timezone.h
+# Amiga specific objects
+stat$(OL): amiga/stat.c amiga/z-stat.h
+filedate$(OL): amiga/filedate.c crypt.h timezone.h
+amiga$(OL): amiga/amiga.c ziperr.h
+# Substitute assembly version of deflate.c:
+#deflate$(OL): amiga/deflate.a
+# $(ASM) $(ASMOPTSL) -o$@ $*.a
+
+
+########################
+# DEPENDECIES END HERE #
+########################
+
+# flush all libraries to provide more mem for compilation
+flush:
+ @Avail flush >nil:
+
+# write common compiler flags to file and echo to user
+CommonFlags:
+ @Echo "$(CFLAGS)" >$(CFILE)
+ @Type "$(CWITHOPT)" >>$(CFILE)
+ -Type $(CFILE)
+
+
+# special rules for adding Amiga internal version number to amiga/amiga.c
+amiga$(O):
+ rx > env:VersionDate "say '""'translate(date('E'),'.','/')'""'"
+ $(CC) WITH=$(CFILE) $(CUSEMEM) LISTFILE=$>$(LISTEXTZ) OBJNAME=$@ $*.c
+ -Delete env:VersionDate
+
+amiga$(OL):
+ rx > env:VersionDate "say '""'translate(date('E'),'.','/')'""'"
+ $(CC) WITH=$(CFILE) $(CLOWMEM) LISTFILE=$>$(LISTEXTL) OBJNAME=$@ $*.c
+ -Delete env:VersionDate
+
+
+# needed in amiga/amigazip.c
+# should be set in startup-sequence, but just in case:
+# (only works with OS 2.0 and above)
+
+env\:WorkBench:
+ @Execute < < (Workbench_smk.tmp)
+ FailAt 21
+ If not exists ENV:Workbench
+ Version >nil:
+ SetEnv Workbench $$Workbench
+ Endif
+ <
+
+
+# Read environment variable LOCAL_ZIP and convert options to SAS format
+#
+# e.g.: to define FOO_ONE and FOO_TWO enter:
+#
+# SetEnv LOCAL_ZIP "-DFOO_ONE -DFOO_TWO"
+#
+# Put the statement into your startup-sequence or (for AmigaDOS 2.0 or higher
+# only) make sure LOCAL_ZIP is stored in the ENVARC: directory
+# ( Copy ENV:LOCAL_ZIP ENVARC: )
+#
+
+local_zip:
+ @Execute < < (Local_Zip_smk.tmp)
+ Failat 21
+ If exists ENV:LOCAL_ZIP
+ Echo "Using environment variable LOCAL_ZIP !"
+ Copy >NIL: ENV:LOCAL_ZIP SASCOPTS
+ Else
+ Echo "You could use envvar ZIP_OPT to set your special compilation options."
+ Delete >nil: SASCOPTS quiet
+ Endif
+ ; Do not remove the lctosc command! If LOCAL_ZIP is unset, an
+ ; empty file is created which needed by CommonFlags !
+ lctosc >$(CWITHOPT)
+ <
+
+
+
+# Echo request to the user
+#
+request:
+ @Echo ""
+ @Echo " This makefile is for use with SAS/C version 6.58."
+ @Echo " If you still have an older version, please upgrade!"
+ @Echo " Patches are available on the Aminet under biz/patch/sc\#?."
+ @Echo ""
+ @Echo " Just a simple request..."
+ @Echo " Please give me a mail that you compiled whether you encounter any errors"
+ @Echo " or not. I'd just like to know how many Amiga users actually make use of"
+ @Echo " this makefile."
+ @Echo " If you mail me, I'll put you on my mailing-list and notify you whenever"
+ @Echo " new versions of Info-Zip are released."
+ @Echo " Have a look at the makefile for changes like CPU type, UtilLib, etc."
+ @Echo " Feel free to mail comments, suggestions, etc."
+ @Echo " Enjoy Info-Zip !"
+ @Echo " Haidinger Walter, <walthaid@unix.ict.tuwien.ac.at>"
+ @Echo ""
+
+
+# Echo help in case of an error
+#
+.ONERROR:
+ @Echo ""
+ @Echo "[sigh] An error running this makefile was detected."
+ @Echo "This message may also appear if you interrupted smake by pressing CTRL-C."
+ @Echo "Contact Info-Zip authors at Zip-Bugs@lists.wku.edu or me for help."
+ @Echo "Haidinger Walter, <walthaid@unix.ict.tuwien.ac.at>"
+
diff --git a/amiga/stat.c b/amiga/stat.c
new file mode 100644
index 0000000..6075c21
--- /dev/null
+++ b/amiga/stat.c
@@ -0,0 +1,293 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Here we have a handmade stat() function because Aztec's c.lib stat() */
+/* does not support an st_mode field, which we need... also a chmod(). */
+
+/* This stat() is by Paul Wells, modified by Paul Kienitz. */
+/* Originally for use with Aztec C >= 5.0 and Lattice C <= 4.01 */
+/* Adapted for SAS/C 6.5x by Haidinger Walter */
+
+/* POLICY DECISION: We will not attempt to remove global variables from */
+/* this source file for Aztec C. These routines are essentially just */
+/* augmentations of Aztec's c.lib, which is itself not reentrant. If */
+/* we want to produce a fully reentrant UnZip, we will have to use a */
+/* suitable startup module, such as purify.a for Aztec by Paul Kienitz. */
+
+#ifndef __amiga_stat_c
+#define __amiga_stat_c
+
+#include <exec/types.h>
+#include <exec/memory.h>
+#include "amiga/z-stat.h" /* fake version of stat.h */
+#include <string.h>
+
+#ifdef AZTEC_C
+# include <libraries/dos.h>
+# include <libraries/dosextens.h>
+# include <clib/exec_protos.h>
+# include <clib/dos_protos.h>
+# include <pragmas/exec_lib.h>
+# include <pragmas/dos_lib.h>
+#endif
+#ifdef __SASC
+# include <sys/dir.h> /* SAS/C dir function prototypes */
+# include <sys/types.h>
+# include <proto/exec.h>
+# include <proto/dos.h>
+#endif
+
+#ifndef SUCCESS
+# define SUCCESS (-1)
+# define FAILURE (0)
+#endif
+
+
+void close_leftover_open_dirs(void); /* prototype */
+
+static DIR *dir_cleanup_list = NULL; /* for resource tracking */
+
+/* CALL THIS WHEN HANDLING CTRL-C OR OTHER UNEXPECTED EXIT! */
+void close_leftover_open_dirs(void)
+{
+ while (dir_cleanup_list)
+ closedir(dir_cleanup_list);
+}
+
+
+unsigned short disk_not_mounted;
+
+extern int stat(const char *file, struct stat *buf);
+
+stat(file,buf)
+const char *file;
+struct stat *buf;
+{
+
+ struct FileInfoBlock *inf;
+ BPTR lock;
+ time_t ftime;
+ struct tm local_tm;
+
+ if( (lock = Lock((char *)file,SHARED_LOCK))==0 )
+ /* file not found */
+ return(-1);
+
+ if( !(inf = (struct FileInfoBlock *)AllocMem(
+ (long)sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)) )
+ {
+ UnLock(lock);
+ return(-1);
+ }
+
+ if( Examine(lock,inf)==FAILURE )
+ {
+ FreeMem((char *)inf,(long)sizeof(*inf));
+ UnLock(lock);
+ return(-1);
+ }
+
+ /* fill in buf */
+ buf->st_dev =
+ buf->st_nlink =
+ buf->st_uid =
+ buf->st_gid =
+ buf->st_rdev = 0;
+ buf->st_ino = inf->fib_DiskKey;
+ buf->st_blocks = inf->fib_NumBlocks;
+ buf->st_size = inf->fib_Size;
+
+ /* now the date. AmigaDOS has weird datestamps---
+ * ds_Days is the number of days since 1-1-1978;
+ * however, as Unix wants date since 1-1-1970...
+ */
+
+ ftime =
+ (inf->fib_Date.ds_Days * 86400 ) +
+ (inf->fib_Date.ds_Minute * 60 ) +
+ (inf->fib_Date.ds_Tick / TICKS_PER_SECOND ) +
+ (86400 * 8 * 365 ) +
+ (86400 * 2 ); /* two leap years */
+
+ /* tzset(); */ /* this should be handled by mktime(), instead */
+ /* ftime += timezone; */
+ local_tm = *gmtime(&ftime);
+ local_tm.tm_isdst = -1;
+ ftime = mktime(&local_tm);
+
+ buf->st_ctime =
+ buf->st_atime =
+ buf->st_mtime = ftime;
+
+ buf->st_mode = (inf->fib_DirEntryType < 0 ? S_IFREG : S_IFDIR);
+
+ /* lastly, throw in the protection bits */
+ buf->st_mode |= ((inf->fib_Protection ^ 0xF) & 0xFF);
+
+ FreeMem((char *)inf, (long)sizeof(*inf));
+ UnLock((BPTR)lock);
+
+ return(0);
+
+}
+
+int fstat(int handle, struct stat *buf)
+{
+ /* fake some reasonable values for stdin */
+ buf->st_mode = (S_IREAD|S_IWRITE|S_IFREG);
+ buf->st_size = -1;
+ buf->st_mtime = time(&buf->st_mtime);
+ return 0;
+}
+
+
+/* opendir(), readdir(), closedir(), rmdir(), and chmod() by Paul Kienitz. */
+
+DIR *opendir(const char *path)
+{
+ DIR *dd = AllocMem(sizeof(DIR), MEMF_PUBLIC);
+ if (!dd) return NULL;
+ if (!(dd->d_parentlock = Lock((char *)path, MODE_OLDFILE))) {
+ disk_not_mounted = IoErr() == ERROR_DEVICE_NOT_MOUNTED;
+ FreeMem(dd, sizeof(DIR));
+ return NULL;
+ } else
+ disk_not_mounted = 0;
+ if (!Examine(dd->d_parentlock, &dd->d_fib) || dd->d_fib.fib_EntryType < 0) {
+ UnLock(dd->d_parentlock);
+ FreeMem(dd, sizeof(DIR));
+ return NULL;
+ }
+ dd->d_cleanuplink = dir_cleanup_list; /* track them resources */
+ if (dir_cleanup_list)
+ dir_cleanup_list->d_cleanupparent = &dd->d_cleanuplink;
+ dd->d_cleanupparent = &dir_cleanup_list;
+ dir_cleanup_list = dd;
+ return dd;
+}
+
+void closedir(DIR *dd)
+{
+ if (dd) {
+ if (dd->d_cleanuplink)
+ dd->d_cleanuplink->d_cleanupparent = dd->d_cleanupparent;
+ *(dd->d_cleanupparent) = dd->d_cleanuplink;
+ if (dd->d_parentlock)
+ UnLock(dd->d_parentlock);
+ FreeMem(dd, sizeof(DIR));
+ }
+}
+
+struct dirent *readdir(DIR *dd)
+{
+ return (ExNext(dd->d_parentlock, &dd->d_fib) ? (struct dirent *)dd : NULL);
+}
+
+
+#ifdef AZTEC_C
+
+int rmdir(const char *path)
+{
+ return (DeleteFile((char *)path) ? 0 : IoErr());
+}
+
+int chmod(const char *filename, int bits) /* bits are as for st_mode */
+{
+ long protmask = (bits & 0xFF) ^ 0xF;
+ return !SetProtection((char *)filename, protmask);
+}
+
+
+/* This here removes unnecessary bulk from the executable with Aztec: */
+void _wb_parse(void) { }
+
+/* fake a unix function that does not apply to amigados: */
+int umask(void) { return 0; }
+
+
+# include <signal.h>
+
+/* C library signal() messes up debugging yet adds no actual usefulness */
+typedef void (*__signal_return_type)(int);
+__signal_return_type signal() { return SIG_ERR; }
+
+
+/* The following replaces Aztec's argv-parsing function for compatibility with
+Unix-like syntax used on other platforms. It also fixes the problem the
+standard _cli_parse() has of accepting only lower-ascii characters. */
+
+int _argc, _arg_len;
+char **_argv, *_arg_lin;
+
+void _cli_parse(struct Process *pp, long alen, register UBYTE *aptr)
+{
+ register UBYTE *cp;
+ register struct CommandLineInterface *cli;
+ register short c;
+ register short starred = 0;
+# ifdef PRESTART_HOOK
+ void Prestart_Hook(void);
+# endif
+
+ cli = (struct CommandLineInterface *) (pp->pr_CLI << 2);
+ cp = (UBYTE *) (cli->cli_CommandName << 2);
+ _arg_len = cp[0] + alen + 2;
+ if (!(_arg_lin = AllocMem((long) _arg_len, 0L)))
+ return;
+ c = cp[0];
+ strncpy(_arg_lin, cp + 1, c);
+ _arg_lin[c] = 0;
+ for (cp = _arg_lin + c + 1; alen && (*aptr < '\n' || *aptr > '\r'); alen--)
+ *cp++ = *aptr++;
+ *cp = 0;
+ aptr = cp = _arg_lin + c + 1;
+ for (_argc = 1; ; _argc++) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (!*cp)
+ break;
+ if (*cp == '"') {
+ cp++;
+ while (c = *cp++) {
+ if (c == '"' && !starred) {
+ *aptr++ = 0;
+ starred = 0;
+ break;
+ } else if (c == '\\' && !starred)
+ starred = 1;
+ else {
+ *aptr++ = c;
+ starred = 0;
+ }
+ }
+ } else {
+ while ((c = *cp++) && c != ' ' && c != '\t')
+ *aptr++ = c;
+ *aptr++ = 0;
+ }
+ if (c == 0)
+ --cp;
+ }
+ *aptr = 0;
+ if (!(_argv = AllocMem((_argc + 1) * sizeof(*_argv), 0L))) {
+ _argc = 0;
+ return;
+ }
+ for (c = 0, cp = _arg_lin; c < _argc; c++) {
+ _argv[c] = cp;
+ cp += strlen(cp) + 1;
+ }
+ _argv[c] = NULL;
+# ifdef PRESTART_HOOK
+ Prestart_Hook();
+# endif
+}
+
+#endif /* AZTEC_C */
+
+#endif /* __amiga_stat_c */
diff --git a/amiga/z-stat.h b/amiga/z-stat.h
new file mode 100644
index 0000000..53d6cd1
--- /dev/null
+++ b/amiga/z-stat.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __amiga_z_stat_h
+#define __amiga_z_stat_h
+
+/* Since older versions of the Lattice C compiler for Amiga, and all current */
+/* versions of the Manx Aztec C compiler for Amiga, either provide no stat() */
+/* function or provide one inadequate for unzip (Aztec's has no st_mode */
+/* field), we provide our own stat() function in stat.c by Paul Wells, and */
+/* this fake stat.h file by Paul Kienitz. Paul Wells originally used the */
+/* Lattice stat.h but that does not work for Aztec and is not distributable */
+/* with this package, so I made a separate one. This has to be pulled into */
+/* unzip.h when compiling an Amiga version, as "amiga/z-stat.h". */
+
+/* We also provide here a "struct dirent" for use with opendir() & readdir() */
+/* functions included in amiga/stat.c. If you use amiga/stat.c, this must */
+/* be included wherever you use either readdir() or stat(). */
+
+#ifdef AZTEC_C
+# define __STAT_H
+#else /* __SASC */
+/* do not include the following header, replacement definitions are here */
+# define _STAT_H /* do not include SAS/C <stat.h> */
+# define _DIRENT_H /* do not include SAS/C <dirent.h> */
+# define _SYS_DIR_H /* do not include SAS/C <sys/dir.h> */
+# define _COMMIFMT_H /* do not include SAS/C <sys/commifmt.h> */
+# include <dos.h>
+#endif
+#include <libraries/dos.h>
+#include <time.h>
+
+
+struct stat {
+ unsigned short st_mode;
+ time_t st_ctime, st_atime, st_mtime;
+ long st_size;
+ long st_ino;
+ long st_blocks;
+ short st_attr, st_dev, st_nlink, st_uid, st_gid, st_rdev;
+};
+
+#define S_IFDIR (1<<11)
+#define S_IFREG (1<<10)
+
+#if 0
+ /* these values here are totally random: */
+# define S_IFLNK (1<<14)
+# define S_IFSOCK (1<<13)
+# define S_IFCHR (1<<8)
+# define S_IFIFO (1<<7)
+# define S_IFMT (S_IFDIR|S_IFREG|S_IFCHR|S_IFLNK)
+#else
+# define S_IFMT (S_IFDIR|S_IFREG)
+#endif
+
+#define S_IHIDDEN (1<<7)
+#define S_ISCRIPT (1<<6)
+#define S_IPURE (1<<5)
+#define S_IARCHIVE (1<<4)
+#define S_IREAD (1<<3)
+#define S_IWRITE (1<<2)
+#define S_IEXECUTE (1<<1)
+#define S_IDELETE (1<<0)
+
+int stat(const char *name, struct stat *buf);
+int fstat(int handle, struct stat *buf); /* returns dummy values */
+
+typedef struct dirent {
+ struct dirent *d_cleanuplink,
+ **d_cleanupparent;
+ BPTR d_parentlock;
+ struct FileInfoBlock d_fib;
+} DIR;
+#define d_name d_fib.fib_FileName
+
+extern unsigned short disk_not_mounted; /* flag set by opendir() */
+
+DIR *opendir(const char *);
+void closedir(DIR *);
+void close_leftover_open_dirs(void); /* call this if aborted in mid-run */
+struct dirent *readdir(DIR *);
+int umask(void);
+
+#ifdef AZTEC_C
+int rmdir(const char *);
+int chmod(const char *filename, int bits);
+#endif
+
+#endif /* __amiga_z_stat_h */
diff --git a/amiga/zipup.h b/amiga/zipup.h
new file mode 100644
index 0000000..c9316f4
--- /dev/null
+++ b/amiga/zipup.h
@@ -0,0 +1,25 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef __amiga_zipup_h
+#define __amiga_zipup_h
+
+#ifndef O_RAW
+# define O_RAW 0
+#endif
+#define fhow (O_RDONLY | O_RAW)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
+
+#endif /* __amiga_zipup_h */
+
diff --git a/aosvs/aosvs.c b/aosvs/aosvs.c
new file mode 100644
index 0000000..f944ad1
--- /dev/null
+++ b/aosvs/aosvs.c
@@ -0,0 +1,659 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <dirent.h>
+#include <time.h>
+
+#include "zip.h"
+#include <paru.h> /* parameter definitions */
+#include <sys_calls.h> /* AOS/VS system call interface */
+#include <packets/filestatus.h> /* AOS/VS ?FSTAT packet defs */
+
+#ifndef UTIL /* AOS/VS specific fileio code not needed for UTILs */
+
+#define PAD 0
+#define PATH_END ':'
+
+/*
+ * could probably avoid the union -
+ * all are same size & we're going to assume this
+ */
+typedef union zvsfstat_stru
+{
+ P_FSTAT norm_fstat_packet; /* normal fstat packet */
+ P_FSTAT_DIR dir_fstat_packet; /* DIR/CPD fstat packet */
+ P_FSTAT_UNIT unit_fstat_packet; /* unit (device) fstat packet */
+ P_FSTAT_IPC ipc_fstat_packet; /* IPC file fstat packet */
+} ZVSFSTAT_STRU;
+
+typedef struct zextrafld
+{
+ char extra_header_id[2]; /* set to VS - in theory, an int */
+ char extra_data_size[2]; /* size of rest, in Intel little-endian order */
+ char extra_sentinel[4]; /* set to FCI w/ trailing null */
+ unsigned char extra_rev; /* set to 10 for rev 1.0 */
+ ZVSFSTAT_STRU fstat_packet; /* the fstat packet */
+ char aclbuf[$MXACL]; /* raw ACL, or link-resolution name */
+} ZEXTRAFLD;
+
+#define ZEXTRA_HEADID "VS"
+#define ZEXTRA_SENTINEL "FCI"
+#define ZEXTRA_REV (unsigned char) 10
+
+local ZEXTRAFLD zzextrafld; /* buffer for extra field containing
+ ?FSTAT packet & ACL buffer */
+local char zlinkres[$MXPL]; /* buf for link resolution contents */
+local char znamebuf[$MXPL]; /* buf for AOS/VS filename */
+static char vsnamebuf[$MXPL];
+static char uxnamebuf[FNMAX];
+static P_FSTAT vsfstatbuf;
+
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *strlower(s)
+char *s; /* string to convert */
+/* Convert all uppercase letters to lowercase in string s */
+{
+ char *p; /* scans string */
+
+ for (p = s; *p; p++)
+ if (*p >= 'A' && *p <= 'Z')
+ *p += 'a' - 'A';
+ return s;
+}
+
+char *strupper(s)
+char *s; /* string to convert */
+/* Convert all lowercase letters to uppercase in string s */
+{
+ char *p; /* scans string */
+
+ for (p = s; *p; p++)
+ if (*p >= 'a' && *p <= 'z')
+ *p -= 'a' - 'A';
+ return s;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ for (t = x; *t == '/'; t++)
+ ;
+
+ if (*t == '=') /* AOS/VS for ./ */
+ t++;
+ else if (*t == ':') /* AOS/VS for / */
+ t++;
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ if (*t == '^') /* AOS/VS for ../ */
+ {
+ if ((n = malloc(strlen(t) + 3)) == NULL)
+ return NULL;
+ strcpy(n, "../");
+ strcpy(n + 3, t + 1);
+ }
+ else if (*t == '@') /* AOS/VS for :PER:, kind of like /dev/ */
+ {
+ if ((n = malloc(strlen(t) + 5)) == NULL)
+ return NULL;
+ strcpy(n, "/PER/");
+ strcpy(n + 5, t + 1);
+ }
+ else
+ {
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+ }
+ /* now turn AOS/VS dir separators (colons) into slashes */
+ for (t = n; *t != '\0'; t++)
+ if (*t == ':')
+ *t = '/';
+ /*
+ * Convert filename to uppercase (for correct matching).
+ * (It may make more sense to patch the matching code, since
+ * we may want those filenames in uppercase on the target system,
+ * but this seems better at present. If we're converting, uppercase
+ * also seems to make sense.)
+ */
+ strupper(n);
+
+
+ if (dosify)
+ msname(n);
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+
+ return x;
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ time_t u[2]; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u */
+ u[0] = u[1] = dos2unixtime(d);
+ utime(f, u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0)
+ error("fstat(stdin)");
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFDIR) != 0) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime(&s.st_ctime);
+}
+
+int deletedir(d)
+char *d;
+{
+ return rmdir(d);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+ /* NOTE: this AOS/VS version assumes the pathname in z->name is an
+ * AOS/VS pathname, not a unix-style one. Since you can zip up using
+ * unix-style pathnames, this may create problems occasionally.
+ * We COULD add code to parse back to AOS/VS format ...
+ * (This might also fail for other reasons such as access denied, but
+ * that should already have occurred.)
+ * We set the central-dir extra fld pointer & length here to the same data.
+ */
+{
+ int aclend = 0;
+/*
+ * use this to simplify because different calls depending on
+ * whether links are resolved
+ */
+ unsigned short errc;
+
+ z->ext = 0; /* init to no extra field */
+/* get the ?FSTAT info & the acl - if no errors, get memory & store.
+ * (first, we have to cut off the trailing slash that was added if
+ * it's a dir, since AOS/VS doesn't accept that kind of thing)
+ */
+ strncpy(znamebuf, z->name, $MXPL);
+ znamebuf[$MXPL-1] = '\0';
+ if (znamebuf[strlen(znamebuf)-1] == '/')
+ znamebuf[strlen(znamebuf)-1] = '\0';
+ if (linkput)
+ errc = sys_fstat(znamebuf, BIT1, &(zzextrafld.fstat_packet));
+ else
+ errc = sys_fstat(znamebuf, 0, &(zzextrafld.fstat_packet));
+ if (errc)
+ {
+ fprintf(stderr,
+ "\n Warning: can't get ?FSTAT info & acl of %s - error %d\n ",
+ znamebuf, errc);
+ perror("sys_fstat()");
+ }
+ else
+ {
+ /* store the ACL - or, if a link (no ACL!), store the resolution name */
+ if (zzextrafld.fstat_packet.norm_fstat_packet.styp_type != $FLNK)
+ {
+ if ((errc = sys_gacl(znamebuf, zzextrafld.aclbuf)) != 0)
+ {
+ fprintf(stderr, "\n Warning: can't get acl of %s - error %d\n ",
+ z->name, errc);
+ perror("sys_gacl()");
+ }
+ else
+ {
+ /* find length of ACL - ends with double-null */
+ while (aclend++ < $MXACL &&
+ (zzextrafld.aclbuf[aclend - 1] != '\0' ||
+ zzextrafld.aclbuf[aclend] != '\0'))
+ /* EMPTY LOOP */ ;
+ if ((z->cextra = z->extra =
+ malloc(sizeof(ZEXTRAFLD) - $MXACL + aclend + 4)) != NULL)
+ {
+ strncpy(zzextrafld.extra_header_id, ZEXTRA_HEADID,
+ sizeof(zzextrafld.extra_header_id));
+ strncpy(zzextrafld.extra_sentinel, ZEXTRA_SENTINEL,
+ sizeof(zzextrafld.extra_sentinel));
+ zzextrafld.extra_rev = ZEXTRA_REV; /* this is a char, no need
+ to worry about byte order */
+ /* set size (Intel (little-endian)) 2-byte int, which we've set
+ as array to make it easier */
+ errc = (unsigned short) (sizeof(ZEXTRAFLD) - $MXACL + aclend + 4 -
+ sizeof(zzextrafld.extra_header_id) -
+ sizeof(zzextrafld.extra_data_size));
+ zzextrafld.extra_data_size[0] = errc & 0xFF; /* low-order byte */
+ zzextrafld.extra_data_size[1] = errc >> 8; /* high-order byte */
+ memcpy((char *) z->extra, (char *) &zzextrafld,
+ sizeof(ZEXTRAFLD) - $MXACL + aclend + 4);
+ z->cext = z->ext = sizeof(ZEXTRAFLD) - $MXACL + aclend + 4;
+ }
+ }
+ }
+ else /* a link */
+ {
+ if ((errc = sys_glink(z->name, zzextrafld.aclbuf)) != 0)
+ {
+ fprintf(stderr,
+ "\n Warning: can't get link-resolution of %s - error %d\n ",
+ z->name, errc);
+ perror("sys_glink()");
+ }
+ else
+ {
+ aclend = strlen(zzextrafld.aclbuf) + 1;
+ if ((z->extra = malloc(sizeof(ZEXTRAFLD) - $MXACL + aclend + 4))
+ != NULL)
+ {
+ strncpy(zzextrafld.extra_header_id, ZEXTRA_HEADID,
+ sizeof(zzextrafld.extra_header_id));
+ strncpy(zzextrafld.extra_sentinel, ZEXTRA_SENTINEL,
+ sizeof(zzextrafld.extra_sentinel));
+ zzextrafld.extra_rev = ZEXTRA_REV; /* this is a char, no need
+ to worry about byte order */
+ /* set size (Intel (little-endian)) 2-byte int, which we've set
+ as array to make it easier */
+ errc = (unsigned short) (sizeof(ZEXTRAFLD) - $MXACL + aclend + 4 -
+ sizeof(zzextrafld.extra_header_id) -
+ sizeof(zzextrafld.extra_data_size));
+ zzextrafld.extra_data_size[0] = errc & 0xFF; /* low-order byte */
+ zzextrafld.extra_data_size[1] = errc >> 8; /* high-order byte */
+ memcpy((char *) z->extra, (char *) &zzextrafld,
+ sizeof(ZEXTRAFLD) - $MXACL + aclend + 4);
+ z->ext = sizeof(ZEXTRAFLD) - $MXACL + aclend + 4;
+ }
+ }
+ }
+ }
+ return ZE_OK;
+}
+
+#endif /* !UTIL */
+
+void version_local()
+{
+ printf("Compiled with %s under %s.\n",
+ "a C compiler",
+ "AOS/VS"
+ );
+}
+
+
+/*
+ * This file defines for AOS/VS two Unix functions relating to links;
+ * the calling code should have the following defines:
+ *
+ * #define lstat(path,buf) zvs_lstat(path,buf)
+ * #define readlink(path,buf,nbytes) zvs_readlink(path,buf,nbytes)
+ *
+ * For these functions, I'm going to define yet 2 MORE filename buffers
+ * and also insert code to change pathnames to Unix & back. This is
+ * easier than changing all the other places this kind of thing happens to
+ * be efficient. This is a kludge. I'm also going to put the functions
+ * here for my immediate convenience rather than somewhere else for
+ * someone else's.
+ *
+ * WARNING: the use of static buffers means that you'd better get your
+ * data out of these buffers before the next call to any of these functions!
+ *
+ */
+
+/* =========================================================================
+ * ZVS_LSTAT() - get (or simulate) stat information WITHOUT following symlinks
+ * This is intended to look to the outside like the unix lstat()
+ * function. We do a quick-&-dirty filename conversion.
+ *
+ * If the file is NOT a symbolic link, we can just do a stat() on it and
+ * that should be fine. But if it IS a link, we have to set the elements
+ * of the stat struct ourselves, since AOS/VS doesn't have a built-in
+ * lstat() function.
+ *
+ * RETURNS: 0 on success, or -1 otherwise
+ *
+ */
+
+int zvs_lstat(char *path, struct stat *buf)
+{
+ char *cp_vs = vsnamebuf;
+ char *cp_ux = path;
+ int mm, dd, yy;
+
+ /*
+ * Convert the Unix pathname to an AOS/VS pathname.
+ * This is quick & dirty; it won't handle (for instance) pathnames with
+ * ../ in the middle of them, and may choke on other Unixisms. We hope
+ * they're unlikely.
+ */
+ if (!strncmp(cp_ux, "../", 3))
+ {
+ *cp_vs++ = '^'; /* AOS/VS for ../ */
+ cp_ux += 3;
+ }
+ else if (!strncmp(cp_ux, "./", 2))
+ {
+ *cp_vs++ = '='; /* AOS/VS for ./ */
+ cp_ux += 2;
+ }
+
+ do
+ {
+ if (*cp_ux == '/')
+ {
+ *cp_vs++ = ':';
+ }
+ else
+ {
+ *cp_vs++ = (char) toupper(*cp_ux);
+ }
+
+ } while (*cp_ux++ != '\0' && cp_vs - vsnamebuf < sizeof(vsnamebuf));
+
+ /* If Unix name was too long for our buffer, return an error return */
+ if (cp_vs - vsnamebuf >= sizeof(vsnamebuf) && *(cp_vs - 1) != '\0')
+ return (-1); /* error */
+
+ /* Make AOS/VS ?FSTAT call that won't follow links & see if we find
+ * anything. If not, we return error.
+ */
+ if (sys_fstat(vsnamebuf,
+ BIT1, /* BIT1 says to not resolve links */
+ &vsfstatbuf))
+ return (-1); /* error */
+
+ /* If we DID find the file but it's not a link,
+ * call stat() and return its value.
+ */
+ if (vsfstatbuf.styp_type != $FLNK)
+ return (stat(path, buf)); /* call with Unix pathname ... */
+
+ /* Otherwise, we have to kludge up values for the stat structure */
+ memset((char *) buf, 0, sizeof(*buf)); /* init to nulls (0 values) */
+ buf->st_mode = S_IFLNK | 0777; /* link and rwxrwxrwx */
+ buf->st_uid = -1; /* this is what we get on AOS/VS
+ anyway (maybe unless we set up
+ a dummy password file?) */
+ buf->st_nlink = 1;
+ /* The DG date we've got is days since 12/31/67 and seconds/2. So we
+ * need to subtract 732 days (if that's not negative), convert to seconds,
+ * and add adjusted seconds.
+ */
+ if (vsfstatbuf.stch.short_time[0] < 732)
+ buf->st_ctime = buf->st_mtime = buf->st_atime = 0L;
+ else
+ {
+ buf->st_ctime = buf->st_mtime = buf->st_atime =
+ ((long) vsfstatbuf.stch.short_time[0] - 732L) * 24L * 3600L +
+ 2L * (long) vsfstatbuf.stch.short_time[1];
+ }
+
+ /* And we need to get the filename linked to and use its length as
+ * the file size. We'll use the Unix pathname buffer for this - hope
+ * it's big enough. (We won't overwrite anything, but we could get a
+ * truncated path.) If there's an error, here's our last chance to
+ * say anything.
+ */
+ if ((buf->st_size = zvs_readlink(vsnamebuf, uxnamebuf, FNMAX)) < 0)
+ return (-1);
+ else
+ return (0);
+
+} /* end zvs_lstat() */
+
+/* =========================================================================
+ * ZVS_READLINK() - get pathname pointed to by an AOS/VS link file
+ * This is intended to look to the outside like the unix readlink()
+ * function. We do a quick-&-dirty filename conversion.
+ *
+ * RETURNS: the length of the output path (in bytes), or -1 if an error
+ *
+ */
+
+int zvs_readlink(char *path, char *buf, int nbytes)
+{
+ char *cp_vs = vsnamebuf;
+ char *cp_ux = buf;
+
+ /* This is called with z->name, the filename the user gave, so we'll get
+ * the link-resolution name on the assumption that it's a valid AOS/VS
+ * name. We're also assuming a reasonable value (> 5) for nbytes.
+ */
+ if (sys_glink(path, vsnamebuf))
+ return (-1); /* readlink() is supposed to return -1 on error */
+
+ /* Now, convert the AOS/VS pathname to a Unix pathname.
+ * Note that sys_glink(), unlike readlink(), does add a null.
+ */
+ if (*cp_vs == '^') /* AOS/VS for ../ */
+ {
+ strncpy(cp_ux, "../", 3);
+ cp_ux += 3;
+ cp_vs++;
+ }
+ else if (*cp_vs == '@') /* AOS/VS for :PER:, kind of like /dev/ */
+ {
+ strncpy(cp_ux, "/PER/", 5);
+ cp_ux += 5;
+ cp_vs++;
+ }
+ else if (*cp_vs == '=') /* AOS/VS for ./ */
+ {
+ strncpy(cp_ux, "./", 2);
+ cp_ux += 2;
+ cp_vs++;
+ }
+ while (*cp_vs != '\0' && cp_ux - buf < nbytes)
+ {
+ if (*cp_vs == ':')
+ {
+ *cp_ux++ = '/';
+ }
+ else
+ {
+ *cp_ux++ = (char) toupper(*cp_vs);
+ }
+ cp_vs++;
+ }
+
+ return (cp_ux - buf); /* # characters in Unix path (no trailing null) */
+
+} /* end zvs_readlink() */
diff --git a/aosvs/make.cli b/aosvs/make.cli
new file mode 100644
index 0000000..32b2624
--- /dev/null
+++ b/aosvs/make.cli
@@ -0,0 +1,5 @@
+push
+prompt pop
+sea :c_4.10 :c_4.10:lang_rt [!sea]
+cc%0/%/link/NOUNX AOS_VS/DEFINE NODIR/DEFINE <ZIP CRC32 CRYPT DEFLATE FILEIO GLOBALS MKTIME TREES TTYIO UTIL ZIPFILE ZIPUP AOSVS>.C
+pop
diff --git a/api.c b/api.c
new file mode 100644
index 0000000..b6f57e7
--- /dev/null
+++ b/api.c
@@ -0,0 +1,718 @@
+/*
+ api.c - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ api.c
+
+ This module supplies a Zip dll engine for use directly from C/C++
+ programs.
+
+ The entry points are:
+
+ ZpVer *ZpVersion(void);
+ int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc);
+ int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts);
+
+ This module is currently only used by the Windows dll, and is not used at
+ all by any of the other platforms, although it should be easy enough to
+ implement this on most platforms.
+
+ ---------------------------------------------------------------------------*/
+#define __API_C
+
+#include <malloc.h>
+#ifdef WINDLL
+# include <windows.h>
+# include "windll/windll.h"
+#endif
+
+#ifdef OS2
+# define INCL_DOSMEMMGR
+# include <os2.h>
+#endif
+
+#ifdef __BORLANDC__
+#include <dir.h>
+#endif
+#include <direct.h>
+#include <ctype.h>
+#include "api.h" /* this includes zip.h */
+#include "crypt.h"
+#include "revision.h"
+#ifdef USE_ZLIB
+# include "zlib.h"
+#endif
+
+
+DLLPRNT *lpZipPrint;
+DLLPASSWORD *lpZipPassword;
+extern DLLCOMMENT *lpComment;
+ZIPUSERFUNCTIONS ZipUserFunctions, far * lpZipUserFunctions;
+
+int ZipRet;
+char szOrigDir[PATH_MAX];
+BOOL fNo_int64 = FALSE; /* flag for DLLSERVICE_NO_INT64 */
+
+/* Local forward declarations */
+extern int zipmain OF((int, char **));
+int AllocMemory(unsigned int, char *, char *, BOOL);
+int ParseString(LPSTR, unsigned int);
+void FreeArgVee(void);
+
+ZPOPT Options;
+char **argVee;
+unsigned int argCee;
+
+/*---------------------------------------------------------------------------
+ Local functions
+ ---------------------------------------------------------------------------*/
+
+char szRootDir[PATH_MAX], szExcludeList[PATH_MAX], szIncludeList[PATH_MAX], szTempDir[PATH_MAX];
+
+int ParseString(LPSTR s, unsigned int ArgC)
+{
+unsigned int i;
+int root_flag, m, j;
+char *str1, *str2, *str3;
+size_t size;
+
+i = ArgC;
+str1 = (char *) malloc(lstrlen(s)+4);
+lstrcpy(str1, s);
+lstrcat(str1, " @");
+
+if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
+ {
+ root_flag = TRUE;
+ if (szRootDir[lstrlen(szRootDir)-1] != '\\')
+ lstrcat(szRootDir, "\\");
+ }
+else
+ root_flag = FALSE;
+
+str2 = strchr(str1, '\"'); /* get first occurance of double quote */
+
+while ((str3 = strchr(str1, '\t')) != NULL)
+ {
+ str3[0] = ' '; /* Change tabs into a single space */
+ }
+
+/* Note that if a quoted string contains multiple adjacent spaces, they
+ will not be removed, because they could well point to a valid
+ folder/file name.
+*/
+while ((str2 = strchr(str1, '\"')) != NULL)
+ /* Found a double quote if not NULL */
+ {
+ str3 = strchr(str2+1, '\"'); /* Get the second quote */
+ if (str3 == NULL)
+ {
+ free(str1);
+ return ZE_PARMS; /* Something is screwy with the
+ string, bail out */
+ }
+ str3[0] = '\0'; /* terminate str2 with a NULL */
+
+ /* strip unwanted fully qualified path from entry */
+ if (root_flag)
+ if ((_strnicmp(szRootDir, str2+1, lstrlen(szRootDir))) == 0)
+ {
+ m = 0;
+ str2++;
+ for (j = lstrlen(szRootDir); j < lstrlen(str2); j++)
+ str2[m++] = str2[j];
+ str2[m] = '\0';
+ str2--;
+ }
+ size = _msize(argVee);
+ if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+ {
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+ /* argCee is incremented in AllocMemory */
+ if (AllocMemory(i, str2+1, "Creating file list from string", TRUE) != ZE_OK)
+ {
+ free(str1);
+ return ZE_MEM;
+ }
+ i++;
+ str3+=2; /* Point past the whitespace character */
+ str2[0] = '\0'; /* Terminate str1 */
+ lstrcat(str1, str3);
+ } /* end while */
+
+/* points to first occurance of a space */
+str2 = strchr(str1, ' ');
+
+/* Go through the string character by character, looking for instances
+ of two spaces together. Terminate when you find the trailing @
+*/
+while ((str2[0] != '\0') && (str2[0] != '@'))
+ {
+ while ((str2[0] == ' ') && (str2[1] == ' '))
+ {
+ str3 = &str2[1];
+ str2[0] = '\0';
+ lstrcat(str1, str3);
+ }
+ str2++;
+ }
+
+/* Do we still have a leading space? */
+if (str1[0] == ' ')
+ {
+ str3 = &str1[1];
+ lstrcpy(str1, str3); /* Dump the leading space */
+ }
+
+
+/* Okay, now we have gotten rid of any tabs and replaced them with
+ spaces, and have replaced multiple spaces with a single space. We
+ couldn't do this before because the folder names could have actually
+ contained these characters.
+*/
+
+str2 = str3 = str1;
+
+while ((str2[0] != '\0') && (str3[0] != '@'))
+ {
+ str3 = strchr(str2+1, ' ');
+ str3[0] = '\0';
+ /* strip unwanted fully qualified path from entry */
+ if (root_flag)
+ if ((_strnicmp(szRootDir, str2, lstrlen(szRootDir))) == 0)
+ {
+ m = 0;
+ for (j = lstrlen(Options.szRootDir); j < lstrlen(str2); j++)
+ str2[m++] = str2[j];
+ str2[m] = '\0';
+ }
+ size = _msize(argVee);
+ if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+ {
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+ if (AllocMemory(i, str2, "Creating file list from string", TRUE) != ZE_OK)
+ {
+ free(str1);
+ return ZE_MEM;
+ }
+ i++;
+ str3++;
+ str2 = str3;
+ }
+free(str1);
+return ZE_OK;
+}
+
+int AllocMemory(unsigned int i, char *cmd, char *str, BOOL IncrementArgCee)
+{
+if ((argVee[i] = (char *) malloc( sizeof(char) * strlen(cmd)+1 )) == NULL)
+ {
+ if (IncrementArgCee)
+ argCee++;
+ FreeArgVee();
+ fprintf(stdout, "Unable to allocate memory in zip library at %s\n", str);
+ return ZE_MEM;
+ }
+strcpy( argVee[i], cmd );
+argCee++;
+return ZE_OK;
+}
+
+void FreeArgVee(void)
+{
+unsigned i;
+
+/* Free the arguments in the array */
+for (i = 0; i < argCee; i++)
+ {
+ free (argVee[i]);
+ argVee[i] = NULL;
+ }
+/* Then free the array itself */
+free(argVee);
+
+/* Restore the original working directory */
+chdir(szOrigDir);
+#ifdef __BORLANDC__
+setdisk(toupper(szOrigDir[0]) - 'A');
+#endif
+
+}
+
+
+/*---------------------------------------------------------------------------
+ Documented API entry points
+ ---------------------------------------------------------------------------*/
+
+int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc)
+{
+ZipUserFunctions = *lpZipUserFunc;
+lpZipUserFunctions = &ZipUserFunctions;
+
+if (!lpZipUserFunctions->print ||
+ !lpZipUserFunctions->comment)
+ return FALSE;
+
+return TRUE;
+}
+
+int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts)
+/* Add, update, freshen, or delete zip entries in a zip file. See the
+ command help in help() zip.c */
+{
+int k, j, m;
+size_t size;
+
+Options = *Opts; /* Save off options, and make them available locally */
+szRootDir[0] = '\0';
+szExcludeList[0] = '\0';
+szIncludeList[0] = '\0';
+szTempDir[0] = '\0';
+if (Options.szRootDir) lstrcpy(szRootDir, Options.szRootDir);
+if (Options.szExcludeList) lstrcpy(szExcludeList, Options.szExcludeList);
+if (Options.szIncludeList) lstrcpy(szIncludeList, Options.szIncludeList);
+if (Options.szTempDir) lstrcpy(szTempDir, Options.szTempDir);
+
+getcwd(szOrigDir, PATH_MAX); /* Save current drive and directory */
+
+if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
+ {
+ /* Make sure there isn't a trailing slash */
+ if (szRootDir[lstrlen(szRootDir)-1] == '\\')
+ szRootDir[lstrlen(szRootDir)-1] = '\0';
+
+ chdir(szRootDir);
+#ifdef __BORLANDC__
+ setdisk(toupper(szRootDir[0]) - 'A');
+#endif
+ }
+
+argCee = 0;
+
+/* malloc additional 40 to allow for additional command line arguments. Note
+ that we are also adding in the count for the include lists as well as the
+ exclude list. */
+if ((argVee = (char **)malloc((C.argc+40)*sizeof(char *))) == NULL)
+ {
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+if ((argVee[argCee] = (char *) malloc( sizeof(char) * strlen("wiz.exe")+1 )) == NULL)
+ {
+ free(argVee);
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+strcpy( argVee[argCee], "wiz.exe" );
+argCee++;
+
+
+/* Set compression level efficacy -0...-9 */
+if (AllocMemory(argCee, "-0", "Compression", FALSE) != ZE_OK)
+ return ZE_MEM;
+
+/* Check to see if the compression level is set to a valid value. If
+ not, then set it to the default.
+*/
+if ((Options.fLevel < '0') || (Options.fLevel > '9'))
+ {
+ Options.fLevel = '6';
+ if (!Options.fDeleteEntries)
+ fprintf(stdout, "Compression level set to invalid value. Setting to default\n");
+ }
+
+argVee[argCee-1][1] = Options.fLevel;
+
+if (Options.fOffsets) /* Update offsets for SFX prefix */
+ {
+ if (AllocMemory(argCee, "-A", "Offsets", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fDeleteEntries) /* Delete files from zip file -d */
+ {
+ if (AllocMemory(argCee, "-d", "Delete", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fNoDirEntries) /* Do not add directory entries -D */
+ {
+ if (AllocMemory(argCee, "-D", "No Dir Entries", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fFreshen) /* Freshen zip file--overwrite only -f */
+ {
+ if (AllocMemory(argCee, "-f", "Freshen", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fRepair) /* Fix archive -F or -FF */
+ {
+ if (Options.fRepair == 1)
+ {
+ if (AllocMemory(argCee, "-F", "Repair", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+ else
+ {
+ if (AllocMemory(argCee, "-FF", "Repair", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+ }
+if (Options.fGrow) /* Allow appending to a zip file -g */
+ {
+ if (AllocMemory(argCee, "-g", "Appending", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fJunkDir) /* Junk directory names -j */
+ {
+ if (AllocMemory(argCee, "-j", "Junk Dir Names", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fEncrypt) /* encrypt -e */
+ {
+ if (AllocMemory(argCee, "-e", "Encrypt", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fJunkSFX) /* Junk sfx prefix */
+ {
+ if (AllocMemory(argCee, "-J", "Junk SFX", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (Options.fForce) /* Make entries using DOS names (k for Katz) -k */
+ {
+ if (AllocMemory(argCee, "-k", "Force DOS", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (Options.fLF_CRLF) /* Translate LF_CRLF -l */
+ {
+ if (AllocMemory(argCee, "-l", "LF-CRLF", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fCRLF_LF) /* Translate CR/LF to LF -ll */
+ {
+ if (AllocMemory(argCee, "-ll", "CRLF-LF", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fMove) /* Delete files added to or updated in zip file -m */
+ {
+ if (AllocMemory(argCee, "-m", "Move", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (Options.fLatestTime) /* Set zip file time to time of latest file in it -o */
+ {
+ if (AllocMemory(argCee, "-o", "Time", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (Options.fComment) /* Add archive comment "-z" */
+ {
+ if (AllocMemory(argCee, "-z", "Comment", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (Options.fQuiet) /* quiet operation -q */
+ {
+ if (AllocMemory(argCee, "-q", "Quiet", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fRecurse == 1) /* recurse into subdirectories -r */
+ {
+ if (AllocMemory(argCee, "-r", "Recurse -r", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+else if (Options.fRecurse == 2) /* recurse into subdirectories -R */
+ {
+ if (AllocMemory(argCee, "-R", "Recurse -R", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fSystem) /* include system and hidden files -S */
+ {
+ if (AllocMemory(argCee, "-S", "System", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fExcludeDate) /* Exclude files newer than specified date -tt */
+ {
+ if ((Options.Date != NULL) && (Options.Date[0] != '\0'))
+ {
+ if (AllocMemory(argCee, "-tt", "Date", FALSE) != ZE_OK)
+ return ZE_MEM;
+ if (AllocMemory(argCee, Options.Date, "Date", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+ }
+
+if (Options.fIncludeDate) /* include files newer than specified date -t */
+ {
+ if ((Options.Date != NULL) && (Options.Date[0] != '\0'))
+ {
+ if (AllocMemory(argCee, "-t", "Date", FALSE) != ZE_OK)
+ return ZE_MEM;
+ if (AllocMemory(argCee, Options.Date, "Date", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+ }
+
+if (Options.fUpdate) /* Update zip file--overwrite only if newer -u */
+ {
+ if (AllocMemory(argCee, "-u", "Update", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fVerbose) /* Mention oddities in zip file structure -v */
+ {
+ if (AllocMemory(argCee, "-v", "Verbose", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.fVolume) /* Include volume label -$ */
+ {
+ if (AllocMemory(argCee, "-$", "Volume", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.szSplitSize != NULL) /* Turn on archive splitting */
+ {
+ if (AllocMemory(argCee, "-s", "Splitting", FALSE) != ZE_OK)
+ return ZE_MEM;
+ if (AllocMemory(argCee, Options.szSplitSize, "Split size", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (lpZipUserFunctions->split != NULL) /* Turn on archive split destinations select */
+ {
+ if (AllocMemory(argCee, "-sp", "Split Pause Select Destination", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+#ifdef WIN32
+if (Options.fPrivilege) /* Use privileges -! */
+ {
+ if (AllocMemory(argCee, "-!", "Privileges", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+#endif
+if (Options.fExtra) /* Exclude extra attributes -X */
+ {
+ if (AllocMemory(argCee, "-X", "Extra", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.IncludeList != NULL) /* Include file list -i */
+ {
+ if (AllocMemory(argCee, "-i", "Include file list", FALSE) != ZE_OK)
+ return ZE_MEM;
+ k = 0;
+ if (Options.IncludeListCount > 0)
+ while ((Options.IncludeList[k] != NULL) && (Options.IncludeListCount != k+1))
+ {
+ size = _msize(argVee);
+ if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+ {
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+ if (AllocMemory(argCee, Options.IncludeList[k], "Include file list array", TRUE) != ZE_OK)
+ {
+ return ZE_MEM;
+ }
+ k++;
+ }
+ else
+ while (Options.IncludeList[k] != NULL)
+ {
+ size = _msize(argVee);
+ if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+ {
+ FreeArgVee();
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+ if (AllocMemory(argCee, Options.IncludeList[k], "Include file list array", TRUE) != ZE_OK)
+ return ZE_MEM;
+ k++;
+ }
+
+ if (AllocMemory(argCee, "@", "End of Include List", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (Options.ExcludeList != NULL) /* Exclude file list -x */
+ {
+ if (AllocMemory(argCee, "-x", "Exclude file list", FALSE) != ZE_OK)
+ return ZE_MEM;
+ k = 0;
+ if (Options.ExcludeListCount > 0)
+ while ((Options.ExcludeList[k] != NULL) && (Options.ExcludeListCount != k+1))
+ {
+ size = _msize(argVee);
+ if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+ {
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+ if (AllocMemory(argCee, Options.ExcludeList[k], "Exclude file list array", TRUE) != ZE_OK)
+ return ZE_MEM;
+ k++;
+ }
+ else
+ while (Options.ExcludeList[k] != NULL)
+ {
+ size = _msize(argVee);
+ if ((argVee = (char **)realloc(argVee, size + sizeof(char *))) == NULL)
+ {
+ FreeArgVee();
+ fprintf(stdout, "Unable to allocate memory in zip dll\n");
+ return ZE_MEM;
+ }
+ if (AllocMemory(argCee, Options.ExcludeList[k], "Exclude file list array", TRUE) != ZE_OK)
+ return ZE_MEM;
+ k++;
+ }
+ if (AllocMemory(argCee, "@", "End of Exclude List", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (szIncludeList != NULL && szIncludeList[0] != '\0') /* Include file list -i */
+ {
+ if (AllocMemory(argCee, "-i", "Include file list", FALSE) != ZE_OK)
+ return ZE_MEM;
+ if ((k = ParseString(szIncludeList, argCee)) != ZE_OK)
+ return k; /* Something was screwy with the parsed string
+ bail out */
+ if (AllocMemory(argCee, "@", "End of Include List", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+if (szExcludeList != NULL && szExcludeList[0] != '\0') /* Exclude file list -x */
+ {
+ if (AllocMemory(argCee, "-x", "Exclude file list", FALSE) != ZE_OK)
+ return ZE_MEM;
+
+ if ((k = ParseString(szExcludeList, argCee)) != ZE_OK)
+ return k; /* Something was screwy with the parsed string
+ bail out */
+
+ if (AllocMemory(argCee, "@", "End of Exclude List", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if ((szTempDir != NULL) && (szTempDir[0] != '\0')
+ && Options.fTemp) /* Use temporary directory -b */
+ {
+ if (AllocMemory(argCee, "-b", "Temp dir switch command", FALSE) != ZE_OK)
+ return ZE_MEM;
+ if (AllocMemory(argCee, szTempDir, "Temporary directory", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (AllocMemory(argCee, C.lpszZipFN, "Zip file name", FALSE) != ZE_OK)
+ return ZE_MEM;
+
+if ((szRootDir != NULL) && (szRootDir[0] != '\0'))
+ {
+ if (szRootDir[lstrlen(szRootDir)-1] != '\\')
+ lstrcat(szRootDir, "\\"); /* append trailing \\ */
+ if (C.FNV != NULL)
+ {
+ for (k = 0; k < C.argc; k++)
+ {
+ if (AllocMemory(argCee, C.FNV[k], "Making argv", FALSE) != ZE_OK)
+ return ZE_MEM;
+ if ((_strnicmp(szRootDir, C.FNV[k], lstrlen(szRootDir))) == 0)
+ {
+ m = 0;
+ for (j = lstrlen(szRootDir); j < lstrlen(C.FNV[k]); j++)
+ argVee[argCee-1][m++] = C.FNV[k][j];
+ argVee[argCee-1][m] = '\0';
+ }
+ }
+ }
+
+ }
+else
+ if (C.FNV != NULL)
+ for (k = 0; k < C.argc; k++)
+ {
+ if (AllocMemory(argCee, C.FNV[k], "Making argv", FALSE) != ZE_OK)
+ return ZE_MEM;
+ }
+
+if (C.lpszAltFNL != NULL)
+ {
+ if ((k = ParseString(C.lpszAltFNL, argCee)) != ZE_OK)
+ return k; /* Something was screwy with the parsed string
+ bail out
+ */
+ }
+
+
+
+argVee[argCee] = NULL;
+
+ZipRet = zipmain(argCee, argVee);
+
+/* Free the arguments in the array. Note this also restores the
+ current directory
+ */
+FreeArgVee();
+
+return ZipRet;
+}
+
+#if CRYPT
+int encr_passwd(int modeflag, char *pwbuf, int size, const char *zfn)
+ {
+ return (*lpZipUserFunctions->password)(pwbuf, size, ((modeflag == ZP_PW_VERIFY) ?
+ "Verify password: " : "Enter password: "),
+ (char *)zfn);
+ }
+#endif /* CRYPT */
+
+void EXPENTRY ZpVersion(ZpVer far * p) /* should be pointer to const struct */
+ {
+ p->structlen = ZPVER_LEN;
+
+#ifdef BETA
+ p->flag = 1;
+#else
+ p->flag = 0;
+#endif
+#ifdef CRYPT
+ p->fEncryption = TRUE;
+#else
+ p->fEncryption = FALSE;
+#endif
+ lstrcpy(p->betalevel, Z_BETALEVEL);
+ lstrcpy(p->date, REVDATE);
+
+#ifdef ZLIB_VERSION
+ lstrcpy(p->zlib_version, ZLIB_VERSION);
+ p->flag |= 2;
+#else
+ p->zlib_version[0] = '\0';
+#endif
+
+#ifdef ZIP64_SUPPORT
+ p->flag |= 4; /* Flag that ZIP64 was compiled in. */
+#endif
+
+ p->zip.major = Z_MAJORVER;
+ p->zip.minor = Z_MINORVER;
+ p->zip.patchlevel = Z_PATCHLEVEL;
+
+#ifdef OS2
+ p->os2dll.major = D2_MAJORVER;
+ p->os2dll.minor = D2_MINORVER;
+ p->os2dll.patchlevel = D2_PATCHLEVEL;
+#endif
+#ifdef WINDLL
+ p->windll.major = DW_MAJORVER;
+ p->windll.minor = DW_MINORVER;
+ p->windll.patchlevel = DW_PATCHLEVEL;
+#endif
+ }
diff --git a/api.h b/api.h
new file mode 100644
index 0000000..f609633
--- /dev/null
+++ b/api.h
@@ -0,0 +1,184 @@
+/*
+ api.h - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Only the Windows DLL is currently supported */
+#ifndef _ZIPAPI_H
+#define _ZIPAPI_H
+
+#include "zip.h"
+
+#ifdef WIN32
+# ifndef PATH_MAX
+# define PATH_MAX 260
+# endif
+#else
+# ifndef PATH_MAX
+# define PATH_MAX 128
+# endif
+#endif
+
+#if defined(WINDLL) || defined(API)
+#include <windows.h>
+/* Porting definations between Win 3.1x and Win32 */
+#ifdef WIN32
+# define far
+# define _far
+# define __far
+# define near
+# define _near
+# define __near
+#endif
+
+/*---------------------------------------------------------------------------
+ Prototypes for public Zip API (DLL) functions.
+ ---------------------------------------------------------------------------*/
+
+#define ZPVER_LEN sizeof(ZpVer)
+/* These defines are set to zero for now, until OS/2 comes out
+ with a dll.
+ */
+#define D2_MAJORVER 0
+#define D2_MINORVER 0
+#define D2_PATCHLEVEL 0
+
+/* intended to be a private struct: */
+typedef struct _zip_ver {
+ uch major; /* e.g., integer 5 */
+ uch minor; /* e.g., 2 */
+ uch patchlevel; /* e.g., 0 */
+ uch not_used;
+} _zip_version_type;
+
+typedef struct _ZpVer {
+ ulg structlen; /* length of the struct being passed */
+ ulg flag; /* bit 0: is_beta bit 1: uses_zlib */
+ char betalevel[10]; /* e.g., "g BETA" or "" */
+ char date[20]; /* e.g., "4 Sep 95" (beta) or "4 September 1995" */
+ char zlib_version[10]; /* e.g., "0.95" or NULL */
+ BOOL fEncryption; /* TRUE if encryption enabled, FALSE otherwise */
+ _zip_version_type zip;
+ _zip_version_type os2dll;
+ _zip_version_type windll;
+} ZpVer;
+
+# ifndef EXPENTRY
+# define EXPENTRY WINAPI
+# endif
+
+#ifndef DEFINED_ONCE
+#define DEFINED_ONCE
+typedef int (WINAPI DLLPRNT) (LPSTR, unsigned long);
+typedef int (WINAPI DLLPASSWORD) (LPSTR, int, LPCSTR, LPCSTR);
+#endif
+#ifdef ZIP64_SUPPORT
+typedef int (WINAPI DLLSERVICE) (LPCSTR, unsigned __int64);
+typedef int (WINAPI DLLSERVICE_NO_INT64) (LPCSTR, unsigned long, unsigned long);
+#else
+typedef int (WINAPI DLLSERVICE) (LPCSTR, unsigned long);
+#endif
+typedef int (WINAPI DLLSPLIT) (LPSTR);
+typedef int (WINAPI DLLCOMMENT)(LPSTR);
+
+/* Structures */
+
+typedef struct { /* zip options */
+LPSTR Date; /* Date to include after */
+LPSTR szRootDir; /* Directory to use as base for zipping */
+LPSTR szTempDir; /* Temporary directory used during zipping */
+BOOL fTemp; /* Use temporary directory '-b' during zipping */
+BOOL fSuffix; /* include suffixes (not implemented) */
+BOOL fEncrypt; /* encrypt files */
+BOOL fSystem; /* include system and hidden files */
+BOOL fVolume; /* Include volume label */
+BOOL fExtra; /* Exclude extra attributes */
+BOOL fNoDirEntries; /* Do not add directory entries */
+BOOL fExcludeDate; /* Exclude files newer than specified date */
+BOOL fIncludeDate; /* Include only files newer than specified date */
+BOOL fVerbose; /* Mention oddities in zip file structure */
+BOOL fQuiet; /* Quiet operation */
+BOOL fCRLF_LF; /* Translate CR/LF to LF */
+BOOL fLF_CRLF; /* Translate LF to CR/LF */
+BOOL fJunkDir; /* Junk directory names */
+BOOL fGrow; /* Allow appending to a zip file */
+BOOL fForce; /* Make entries using DOS names (k for Katz) */
+BOOL fMove; /* Delete files added or updated in zip file */
+BOOL fDeleteEntries; /* Delete files from zip file */
+BOOL fUpdate; /* Update zip file--overwrite only if newer */
+BOOL fFreshen; /* Freshen zip file--overwrite only */
+BOOL fJunkSFX; /* Junk SFX prefix */
+BOOL fLatestTime; /* Set zip file time to time of latest file in it */
+BOOL fComment; /* Put comment in zip file */
+BOOL fOffsets; /* Update archive offsets for SFX files */
+BOOL fPrivilege; /* Use privileges (WIN32 only) */
+BOOL fEncryption; /* TRUE if encryption supported, else FALSE.
+ this is a read only flag */
+LPSTR szSplitSize; /* This string contains the size that you want to
+ split the archive into. i.e. 100 for 100 bytes,
+ 2K for 2 k bytes, where K is 1024, m for meg
+ and g for gig. If this string is not NULL it
+ will automatically be assumed that you wish to
+ split an archive. */
+LPSTR szIncludeList; /* Pointer to include file list string (for VB) */
+long IncludeListCount; /* Count of file names in the include list array */
+char **IncludeList; /* Pointer to include file list array. Note that the last
+ entry in the array must be NULL */
+LPSTR szExcludeList; /* Pointer to exclude file list (for VB) */
+long ExcludeListCount; /* Count of file names in the include list array */
+char **ExcludeList; /* Pointer to exclude file list array. Note that the last
+ entry in the array must be NULL */
+int fRecurse; /* Recurse into subdirectories. 1 => -r, 2 => -R */
+int fRepair; /* Repair archive. 1 => -F, 2 => -FF */
+char fLevel; /* Compression level (0 - 9) */
+} ZPOPT, _far *LPZPOPT;
+
+typedef struct {
+ int argc; /* Count of files to zip */
+ LPSTR lpszZipFN; /* name of archive to create/update */
+ char **FNV; /* array of file names to zip up */
+ LPSTR lpszAltFNL; /* pointer to a string containing a list of file
+ names to zip up, separated by whitespace. Intended
+ for use only by VB users, all others should set this
+ to NULL. */
+} ZCL, _far *LPZCL;
+
+typedef struct {
+ DLLPRNT *print;
+ DLLCOMMENT *comment;
+ DLLPASSWORD *password;
+ DLLSPLIT *split; /* This MUST be set to NULL unless you want to be queried
+ for a destination for each split archive. */
+#ifdef ZIP64_SUPPORT
+ DLLSERVICE *ServiceApplication64;
+ DLLSERVICE_NO_INT64 *ServiceApplication64_No_Int64;
+#else
+ DLLSERVICE *ServiceApplication;
+#endif
+} ZIPUSERFUNCTIONS, far * LPZIPUSERFUNCTIONS;
+
+extern LPZIPUSERFUNCTIONS lpZipUserFunctions;
+
+void EXPENTRY ZpVersion(ZpVer far *);
+int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc);
+int EXPENTRY ZpArchive(ZCL C, LPZPOPT Opts);
+
+#if defined(ZIPLIB) || defined(COM_OBJECT)
+# define ydays zp_ydays
+#endif
+
+
+
+/* Functions not yet supported */
+#if 0
+int EXPENTRY ZpMain (int argc, char **argv);
+int EXPENTRY ZpAltMain (int argc, char **argv, ZpInit *init);
+#endif
+#endif /* WINDLL? || API? */
+
+#endif /* _ZIPAPI_H */
diff --git a/atari/Makefile b/atari/Makefile
new file mode 100644
index 0000000..2c86196
--- /dev/null
+++ b/atari/Makefile
@@ -0,0 +1,111 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+MAKE = make
+SHELL = /bin/sh
+
+# (to use the Gnu compiler, change cc to gcc in CC and BIND)
+CC = cc
+BIND = $(CC)
+AS = $(CC) -c
+E =
+CPP = /lib/cpp
+
+# probably can change this to 'install' if you have it
+INSTALL = cp
+
+# target directories - where to install executables and man pages to
+BINDIR = /usr/local/bin
+manext=1
+MANDIR = /usr/local/man/man$(manext)
+
+# flags
+# CFLAGS flags for C compile
+# LFLAGS1 flags after output file spec, before obj file list
+# LFLAGS2 flags after obj file list (libraries, etc)
+CFLAGS = -O
+LFLAGS1 =
+LFLAGS2 = -s
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o crc32.o globals.o \
+ crypt.o ttyio.o atari.o
+
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o atari_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h atari/osdep.h
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+ rm -f $*_.c; ln $< $*_.c
+ $(CC) $(CFLAGS) -DUTIL -c $*_.c
+ rm -f $*_.c
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+.1.doc:
+ nroff -man $< | col -b | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: atari/zipup.h
+
+match.o: match.s
+ $(CPP) match.s > _match.s
+ $(AS) _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+ZIPS = zip$E zipnote$E zipsplit$E zipcloak$E
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA)
+ $(BIND) -o zip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+ $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC)
+ $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+ $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+ nroff -man man/zip.1 | col -b | uniq > $(ZIPMANUAL)
+
+# install
+install: $(ZIPS)
+ $(INSTALL) $(ZIPS) $(BINDIR)
+ $(INSTALL) man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+ -cd $(BINDIR); rm -f $(ZIPS)
+ -cd $(MANDIR); rm -f zip.$(manext)
+
+dist: $(ZIPMANUAL)
+ zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+ -e s/[.]//g -e q revision.h` \
+ `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+# ATARI version (gcc 2.5.8 and Mintlibs PL46)
+atari:
+ $(MAKE) zips CFLAGS="-O -DATARI" OBJA=atari/atari.o CC=gcc E=.ttp
+
+# clean up after making stuff and installing it
+clean:
+ rm -f *.o $(ZIPS) flags
diff --git a/atari/README b/atari/README
new file mode 100644
index 0000000..cce4206
--- /dev/null
+++ b/atari/README
@@ -0,0 +1,5 @@
+From: harry@hal.westfalen.de (Harald Denker)
+
+The old zip ATARI port is based on TurboC which is no more
+supported (for more than 3 years). I used the GNU gcc 2.5.8 and
+MiNTlibs PL46.
diff --git a/atari/atari.c b/atari/atari.c
new file mode 100644
index 0000000..ce5196c
--- /dev/null
+++ b/atari/atari.c
@@ -0,0 +1,681 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <errno.h>
+#include <dirent.h>
+#include <mintbind.h>
+#include <osbind.h>
+#include <ostruct.h>
+
+
+#define PAD 0
+#define PATH_END '/'
+
+extern char *label; /* defined in fileio.c */
+
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+local char *getVolumeLabel(drive, vtime, vmode, utim)
+ int drive; /* drive name: 'A' .. 'Z' or '\0' for current drive */
+ ulg *vtime; /* volume label creation time (DOS format) */
+ ulg *vmode; /* volume label file mode */
+ time_t utim;/* volume label creation time (UNIX format) */
+
+/* If a volume label exists for the given drive, return its name and
+ set its time and mode. The returned name must be static data. */
+{
+ static char vol[14];
+ _DTA *dtaptr;
+
+ if (drive) {
+ vol[0] = (char)drive;
+ strcpy(vol+1, ":/");
+ } else {
+ strcpy(vol, "/");
+ }
+ strcat(vol, "*.*");
+ if (Fsfirst(vol, FA_LABEL) == 0) {
+ dtaptr = Fgetdta();
+ strncpy(vol, dtaptr->dta_name, sizeof(vol)-1);
+ *vtime = ((ulg)dtaptr->dta_date << 16) |
+ ((ulg)dtaptr->dta_time & 0xffff);
+ *vmode = (ulg)dtaptr->dta_attribute;
+ return vol;
+ }
+ return NULL;
+}
+
+char GetFileMode(char *name)
+{
+ struct stat sb;
+
+ sb.st_attr = 0;
+ Fxattr(linkput ? 1 : 0, name, &sb);
+ if (errno == EINVAL) {
+ _DTA *dtaptr, *old;
+ old = Fgetdta();
+ Fsfirst(name, FA_RDONLY+FA_HIDDEN+FA_SYSTEM+FA_DIR);
+ dtaptr = Fgetdta();
+ sb.st_attr = dtaptr->dta_attribute;
+ Fsetdta(old);
+ }
+ return sb.st_attr & 0x3f;
+}
+
+
+int wild2(w)
+char *w; /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+ file system. Return an error code in the ZE_ class. */
+{
+ DIR *d; /* stream for reading directory */
+ char *e; /* name found in directory */
+ int r; /* temporary variable */
+ char *n; /* constructed name from directory */
+ int f; /* true if there was a match */
+ char *a; /* alloc'ed space for name */
+ char *p; /* path */
+ char *q; /* name */
+ char v[5]; /* space for device current directory */
+
+ if (volume_label == 1) {
+ volume_label = 2;
+ label = getVolumeLabel(w[1] == ':' ? to_up(w[0]) : '\0',
+ &label_time, &label_mode, &label_utim);
+ if (label != NULL) {
+ newname(label, 0, 0);
+ }
+ if (w[1] == ':' && w[2] == '\0') return ZE_OK;
+ /* "zip -$ foo a:" can be used to force drive name */
+ }
+
+ /* special handling of stdin request */
+ if (strcmp(w, "-") == 0) /* if compressing stdin */
+ return newname(w, 0, 0);
+
+ /* Allocate and copy pattern */
+ if ((p = a = malloc(strlen(w) + 1)) == NULL)
+ return ZE_MEM;
+ strcpy(p, w);
+
+ /* Normalize path delimiter as '/'. */
+ for (q = p; *q; q++) /* use / consistently */
+ if (*q == '\\')
+ *q = '/';
+
+ /* Only name can have special matching characters */
+ if ((q = isshexp(p)) != NULL &&
+ (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
+ {
+ free((zvoid *)a);
+ return ZE_PARMS;
+ }
+
+ /* Separate path and name into p and q */
+ if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
+ {
+ *q++ = '\0'; /* path/name -> path, name */
+ if (*p == '\0') /* path is just / */
+ p = strcpy(v, "/.");
+ }
+ else if ((q = strrchr(p, ':')) != NULL)
+ { /* has device and no or root path */
+ *q++ = '\0';
+ p = strcat(strcpy(v, p), ":"); /* copy device as path */
+ if (*q == '/') /* -> device:/., name */
+ {
+ strcat(p, "/");
+ q++;
+ }
+ strcat(p, ".");
+ }
+ else if (recurse && (strcmp(p, ".") == 0 || strcmp(p, "..") == 0))
+ { /* current or parent directory */
+ /* I can't understand Mark's code so I am adding a hack here to get
+ * "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
+ * reject "zip -rm foo ..".
+ */
+ if (dispose && strcmp(p, "..") == 0)
+ ziperr(ZE_PARMS, "cannot remove parent directory");
+ q = "*.*";
+ }
+ else /* no path or device */
+ {
+ q = p;
+ p = strcpy(v, ".");
+ }
+ if (recurse && *q == '\0') {
+ q = "*.*";
+ }
+ /* Search that level for matching names */
+ if ((d = opendir(p)) == NULL)
+ {
+ free((zvoid *)a);
+ return ZE_MISS;
+ }
+ if ((r = strlen(p)) > 1 &&
+ (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
+ *(p + r - 1) = '\0';
+ f = 0;
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e, 0))
+ {
+ f = 1;
+ if (strcmp(p, ".") == 0) { /* path is . */
+ r = procname(e, 0); /* name is name */
+ if (r) {
+ f = 0;
+ break;
+ }
+ } else
+ {
+ if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
+ {
+ free((zvoid *)a);
+ closedir(d);
+ return ZE_MEM;
+ }
+ n = strcpy(n, p);
+ if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
+ strcat(n, "/");
+ r = procname(strcat(n, e), 0); /* name is path/name */
+ free((zvoid *)n);
+ if (r) {
+ f = 0;
+ break;
+ }
+ }
+ }
+ }
+ closedir(d);
+
+ /* Done */
+ free((zvoid *)a);
+ return f ? ZE_OK : ZE_MISS;
+}
+
+
+#include <regexp.h>
+#include <osbind.h>
+
+void regerror( char ZCONST *msg ) {
+ perror( msg );
+}
+
+static int ret;
+static regexp *regptr;
+static short is_w, ind_w;
+static char fullpath[FILENAME_MAX], file_arg[FILENAME_MAX];
+
+#define FTW_F 0
+#define FTW_D 1
+#define FTW_DNR 2
+#define FTW_NS 3
+
+static int ftwfunc( struct stat *stats, int ftw_status )
+{
+ char *path = &fullpath[0];
+
+ if (strncmp(path, "./", 2) == 0) path += 2;
+ switch (ftw_status) {
+ case FTW_NS:
+ zipwarn("can't stat file: ", path);
+ ret = ZE_MISS;
+ return 0;
+ case FTW_F:
+ if (!is_w || regexec(regptr, path, 1)) {
+#if 0
+ char fn[FILENAME_MAX];
+ int k;
+ if (S_ISLNK(stats->st_mode) &&
+ (k = readlink(path, fn, FILENAME_MAX)) > 0) {
+ int l = strlen(path);
+ fn[k] = '\0';
+ strcat(strcat(path, " -> "), fn);
+ ret = newname(path, 0, 0); /* procname(path, 0); */
+ path[l] = '\0';
+ } else
+#endif
+ ret = newname(path, 0, 0); /* procname(path, 0); */
+ }
+ return 0;
+ case FTW_DNR:
+ zipwarn("can't open directory: ", path);
+ ret = ZE_MISS;
+ return 0;
+ case FTW_D:
+ if (strcmp(path, ".") == 0) return 0;
+ if (is_w && ind_w > 0 && strncmp(path, file_arg, ind_w) != 0)
+ return 4;
+ }
+ return 0;
+}
+
+static int myftw( int depth )
+{
+ register DIR *dirp;
+ struct dirent *entp;
+ struct stat stats;
+ register char *p,*q;
+ register long i;
+
+ if (LSSTAT(fullpath, &stats) < 0)
+ return ftwfunc(&stats, FTW_NS);
+
+ if (!S_ISDIR(stats.st_mode))
+ return ftwfunc(&stats, FTW_F);
+
+ if ((dirp = opendir(fullpath)) == NULL)
+ return ftwfunc(&stats, FTW_DNR);
+
+ if (i = ftwfunc(&stats, FTW_D)) {
+ closedir(dirp);
+ return (i == 4 ? 0 : (int)i);
+ }
+ i = strlen(fullpath);
+ p = &fullpath[i];
+ *p++ = '/'; *p = '\0';
+ if (dirnames && i > 1) {
+ q = (strncmp(fullpath, "./", 2) == 0 ? &fullpath[2] : &fullpath[0]);
+ ret = newname(q, 1, 0);
+ }
+ i = 0;
+ while (depth > 0 && (entp = readdir(dirp)) != 0)
+ if (strcmp(entp->d_name,".") != 0 && strcmp(entp->d_name,"..") != 0) {
+ strcpy(p, entp->d_name);
+ if (i = myftw(depth-1))
+ depth = 0; /* force User's finish */
+ }
+ closedir(dirp);
+ return (int)i;
+}
+
+int wild( char *p )
+{
+ char *d;
+
+ ret = ZE_OK;
+ if (p == NULL) p = "*";
+
+ if (strcmp(p, "-") == 0) /* if compressing stdin */
+ ret = newname(p, 0, 0);
+
+ strcpy(fullpath, p);
+ /* now turning UNIX-Wildcards into basic regular expressions */
+ for (is_w = ind_w = 0, d = &file_arg[0]; *p; d++, p++)
+ switch (*p) {
+ case '*': *d++ = '.'; *d = *p; is_w = 1; break;
+ case '?': *d = '.'; is_w = 1; break;
+ case '[': *d = *p;
+ if (*(p+1) == '!') {
+ *++d = '^'; p++;
+ } is_w = 1; break;
+ case '.': *d++ = '\\'; *d = *p; break;
+ default : *d = *p;
+ if (!is_w) ind_w++;
+ }
+ *++d = '\0';
+ if (is_w) {
+ strcat( file_arg, "$" ); /* to get things like *.[ch] work */
+ if ((regptr = regcomp( file_arg )) == NULL)
+ return ZE_MEM;
+ strcpy( fullpath, "." );
+ myftw( recurse ? 99 : 1 );
+ free(regptr);
+ } else if (recurse) {
+ myftw( 99 );
+ } else
+ myftw( 1 ); /* ret = procname( fullpath, 0 ); */
+ return ret;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ for (p = n; *p; p++) /* use / consistently */
+ if (*p == '\\')
+ *p = '/';
+ if (!S_ISDIR(s.st_mode))
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t, *p; /* shortened name */
+ int dosflag;
+
+ dosflag = 0;
+
+ /* Find starting point in name before doing malloc */
+ t = *x && *(x + 1) == ':' ? x + 2 : x;
+ while (*t == '/' || *t == '\\')
+ t++;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ for (n = t; *n; n++)
+ if (*n == '\\')
+ *n = '/';
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+#if 0
+ if (p = strstr(t, " -> ")) /* shorten "link -> data" to "link" */
+ *p = '\0';
+#endif
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+ return x;
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ struct utimbuf u; /* argument for utime() const ?? */
+
+ /* Convert DOS time to time_t format in u[0] and u[1] */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ /* Set updated and accessed times of f */
+ utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+
+ if (a != NULL) {
+/* *a = ((ulg)s.st_mode << 16) | (ulg)GetFileMode(name); */
+ *a = ((ulg)s.st_mode << 16) | (ulg)s.st_attr;
+ }
+ free(name);
+ if (n != NULL)
+ *n = S_ISREG(s.st_mode) ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid) return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(2))) == NULL)
+ return ZE_MEM;
+ if ((z->cextra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = EB_UT_LEN(2); /* length of data part of e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME;
+ z->extra[5] = (char)(z_utim->mtime);
+ z->extra[6] = (char)(z_utim->mtime >> 8);
+ z->extra[7] = (char)(z_utim->mtime >> 16);
+ z->extra[8] = (char)(z_utim->mtime >> 24);
+ z->extra[9] = (char)(z_utim->atime);
+ z->extra[10] = (char)(z_utim->atime >> 8);
+ z->extra[11] = (char)(z_utim->atime >> 16);
+ z->extra[12] = (char)(z_utim->atime >> 24);
+
+ z->ext = (EB_HEADSIZE+EB_UX_LEN(2));
+
+ memcpy(z->cextra, z->extra, (EB_HEADSIZE+EB_UT_LEN(1)));
+ z->cextra[EB_LEN] = EB_UT_LEN(1);
+ z->cext = (EB_HEADSIZE+EB_UX_LEN(1));
+
+ return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+ return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ return rmdir(d);
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#ifdef __TURBOC__
+ char buf[40];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+# if 0
+ "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
+# else
+# ifdef __TURBOC__
+ "Turbo C", (sprintf(buf, " (0x%04x = %d)", __TURBOC__, __TURBOC__), buf),
+# else
+ "unknown compiler", "",
+# endif
+# endif
+#endif
+
+#ifdef __MINT__
+ "Atari TOS/MiNT",
+#else
+ "Atari TOS",
+#endif
+
+ " (Atari ST/TT/Falcon030)",
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
diff --git a/atari/make_all.mup b/atari/make_all.mup
new file mode 100644
index 0000000..5f8c4dc
--- /dev/null
+++ b/atari/make_all.mup
@@ -0,0 +1,7 @@
+rm -f *.o *.sym *.ttp
+make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o zips
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.ttp OBJA=atari.o zip.ttp
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.sym OBJA=atari.o zip.sym LFLAGS2="-B/bin/sym-"
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o -n zips > make_all.mup
+#fixstk 32K pgp.ttp
+prgflags 017 007 *.ttp
diff --git a/atari/make_zip.mup b/atari/make_zip.mup
new file mode 100644
index 0000000..4ea4c31
--- /dev/null
+++ b/atari/make_zip.mup
@@ -0,0 +1,7 @@
+#rm -f *.o *.sym *.ttp
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o zips
+make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.ttp OBJA=atari.o zip.ttp
+make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-g -D__NO_INLINE__ -DATARI" E=.sym OBJA=atari.o zip.sym LFLAGS2="-B/bin/sym-"
+#make370 SHELL=/bin/mupfel.ttp CC=gcc CFLAGS="-O -DATARI" E=.ttp OBJA=atari.o -n zips > make_all.mup
+#fixstk 32K pgp.ttp
+prgflags 017 007 *.ttp
diff --git a/atari/osdep.h b/atari/osdep.h
new file mode 100644
index 0000000..46387b6
--- /dev/null
+++ b/atari/osdep.h
@@ -0,0 +1,20 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#define DIRENT
+#define NO_TERMIO
+#define USE_CASE_MAP
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#include <sys/types.h>
+#include <sys/stat.h>
diff --git a/atari/zipup.h b/atari/zipup.h
new file mode 100644
index 0000000..1de3f61
--- /dev/null
+++ b/atari/zipup.h
@@ -0,0 +1,19 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/atheos/Makefile b/atheos/Makefile
new file mode 100644
index 0000000..91df1c8
--- /dev/null
+++ b/atheos/Makefile
@@ -0,0 +1,146 @@
+######################################################################
+#
+# Makefile for Info-ZIP's zip, zipcloak, zipnote, and zipsplit on AtheOS
+#
+# Copyright (C) 1999-2007 Info-ZIP
+# Chris Herborth (chrish@pobox.com)
+# Ruslan Nickolaev (nruslan@hotbox.ru)
+#
+######################################################################
+# Things that don't change:
+
+# Punish people who don't have SMP hardware.
+MAKE = make -j 4 -f atheos/Makefile
+SHELL = /bin/sh
+
+LN = ln -s
+RM = rm -f
+
+BIND = $(CC)
+AS = as
+
+INSTALL = install
+
+# Target directories
+prefix = /usr
+BINDIR = $(prefix)/bin
+manext = 1
+MANDIR = $(prefix)/man/man$(manext)
+ZIPMANUAL = MANUAL
+
+VERSION = Version 2.3 of __DATE__
+
+######################################################################
+
+CC:=gcc
+CFLAGS:=-O3 -march=i586 -Wall -I. -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN -DASMV -DASM_CRC
+LFLAGS1:=
+LFLAGS2:=
+TARGET=$(ZIPS)
+
+######################################################################
+# Helpful targets
+all:
+ $(MAKE) CC=$(CC) CFLAGS="$(CFLAGS)" \
+ LFLAGS1="$(LFLAGS1)" LFLAGS2="$(LFLAGS2)" \
+ $(TARGET)
+
+######################################################################
+# Object file lists and other build goodies
+
+# Object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crc32.o crypt.o \
+ ttyio.o atheos.o
+OBJI = deflate.o trees.o
+OBJA = match.o crc_i386.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o atheos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+# Headers
+ZIP_H = zip.h ziperr.h tailor.h atheos/osdep.h
+
+# What to build?
+ZIPS = zip zipnote zipsplit zipcloak
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+ $(RM) $*_.c; $(LN) $< $*_.c
+ $(CC) -c $(CFLAGS) -DUTIL $*_.c
+ $(RM) $*_.c
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+ groff -man -Tascii $< > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: atheos/zipup.h
+
+match.o: match.S
+ $(CC) -E match.S > matchs.s
+ $(AS) -o $@ matchs.s
+ $(RM) matchs.s
+
+crc_i386.o: crc_i386.S
+ $(CC) -E crc_i386.S > crc_i386s.s
+ $(AS) -o $@ crc_i386s.s
+ $(RM) crc_i386s.s
+
+atheos.o: atheos/atheos.c
+ $(CC) -c $(CFLAGS) atheos/atheos.c
+
+atheos_.o: atheos/atheos.c
+ $(RM) $*_.c; $(LN) atheos/atheos.c $*_.c
+ $(CC) -c $(CFLAGS) -DUTIL $*_.c
+ $(RM) $*_.c
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip: $(OBJZ) $(OBJI) $(OBJA)
+ $(BIND) -o zip $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote: $(OBJN)
+ $(BIND) -o zipnote $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+ $(BIND) -o zipcloak $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+ $(BIND) -o zipsplit $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+ groff -man -Tascii man/zip.1 > $(ZIPMANUAL)
+
+# install
+install: $(ZIPS)
+ $(INSTALL) -m755 $(ZIPS) $(BINDIR)
+ mkdir -p $(MANDIR)
+ $(INSTALL) -m644 man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+ -cd $(BINDIR); $(RM) $(ZIPS)
+ -cd $(MANDIR); $(RM) zip.$(manext)
+
+dist: $(ZIPMANUAL)
+ zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+ -e s/[.]//g -e q revision.h` \
+ `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+# clean up after making stuff and installing it
+clean:
+ $(RM) *.o $(ZIPS) flags
+
+# end of Makefile
diff --git a/atheos/README b/atheos/README
new file mode 100644
index 0000000..a96fffc
--- /dev/null
+++ b/atheos/README
@@ -0,0 +1,21 @@
+Info-ZIP's zip for AtheOS/Syllable
+
+FEATURES
+ stores AtheOS/Syllable file attributes, compressing them if possible
+
+TODO
+----
+There is only one thing to be fixed:
+ write_attr() should return count of writed bytes. However that's bug related with AFS only.
+
+Please report any bugs to Info-ZIP at www.info-zip.org.
+If this bug related with AtheOS/Syllable only, you can mail me directly: nruslan@hotbox.ru.
+
+Visit the Info-ZIP web site (http://www.info-zip.org) for all the
+latest zip and unzip information, FAQs, source code and ready-to-run
+executables.
+
+- Ruslan Nickolaev (nruslan@hotbox.ru)
+ Sep 06/2004
+
+(updated 12 November 2004)
diff --git a/atheos/atheos.c b/atheos/atheos.c
new file mode 100644
index 0000000..6f1c915
--- /dev/null
+++ b/atheos/atheos.c
@@ -0,0 +1,885 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+
+ This AtheOS - specific file is based on unix.c and beos.c;
+ changes by Ruslan Nickolaev (nruslan@hotbox.ru)
+*/
+
+#include "zip.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atheos/fs_attribs.h>
+
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef _POSIX_VERSION
+# include <utime.h>
+#else
+ int utime OF((char *, time_t *));
+#endif
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+local int get_attr_dir( const char *, char **, off_t * );
+local int add_UT_ef( struct zlist far * );
+local int add_Ux_ef( struct zlist far * );
+local int add_At_ef( struct zlist far * );
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFREG) == S_IFREG ||
+ (s.st_mode & S_IFLNK) == S_IFLNK)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ }
+ else if ((s.st_mode & S_IFDIR) == S_IFDIR)
+ {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) */
+ else
+ zipwarn("ignoring special file: ", n);
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t = NULL; /* shortened name */
+ int dosflag;
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ /* Strip "//host/share/" part of a UNC name */
+ if (!strncmp(x,"//",2) && (x[2] != '\0' && x[2] != '/')) {
+ n = x + 2;
+ while (*n != '\0' && *n != '/')
+ n++; /* strip host name */
+ if (*n != '\0') {
+ n++;
+ while (*n != '\0' && *n != '/')
+ n++; /* strip `share' name */
+ }
+ if (*n != '\0')
+ t = n + 1;
+ } else
+ t = x;
+ while (*t == '/')
+ t++; /* strip leading '/' chars to get a relative path */
+ while (*t == '.' && t[1] == '/')
+ t += 2; /* strip redundant leading "./" sections */
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (isdir == 42) return n; /* avoid warning on unused variable */
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+ return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#ifdef _POSIX_VERSION
+ struct utimbuf u; /* argument for utime() const ?? */
+#else
+ time_t u[2]; /* argument for utime() */
+#endif
+
+ /* Convert DOS time to time_t format in u */
+#ifdef _POSIX_VERSION
+ u.actime = u.modtime = dos2unixtime(d);
+ utime(f, &u);
+#else
+ u[0] = u[1] = dos2unixtime(d);
+ utime(f, u);
+#endif
+
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ }
+ else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+#ifndef OS390
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+#else
+/*
+** The following defines are copied from the unizip source and represent the
+** legacy Unix mode flags. These fixed bit masks are no longer required
+** by XOPEN standards - the S_IS### macros being the new recommended method.
+** The approach here of setting the legacy flags by testing the macros should
+** work under any _XOPEN_SOURCE environment (and will just rebuild the same bit
+** mask), but is required if the legacy bit flags differ from legacy Unix.
+*/
+#define UNX_IFDIR 0040000 /* Unix directory */
+#define UNX_IFREG 0100000 /* Unix regular file */
+#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */
+#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */
+#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */
+#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */
+#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */
+ {
+ mode_t legacy_modes;
+
+ /* Initialize with permission bits - which are not implementation optional */
+ legacy_modes = s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
+ if (S_ISDIR(s.st_mode))
+ legacy_modes |= UNX_IFDIR;
+ if (S_ISREG(s.st_mode))
+ legacy_modes |= UNX_IFREG;
+ if (S_ISLNK(s.st_mode))
+ legacy_modes |= UNX_IFLNK;
+ if (S_ISBLK(s.st_mode))
+ legacy_modes |= UNX_IFBLK;
+ if (S_ISCHR(s.st_mode))
+ legacy_modes |= UNX_IFCHR;
+ if (S_ISFIFO(s.st_mode))
+ legacy_modes |= UNX_IFIFO;
+ if (S_ISSOCK(s.st_mode))
+ legacy_modes |= UNX_IFSOCK;
+ *a = ((ulg)legacy_modes << 16) | !(s.st_mode & S_IWRITE);
+ }
+#endif
+ if ((s.st_mode & S_IFMT) == S_IFDIR) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = t->mtime; /* best guess, (s.st_ctime: last status change!!) */
+ }
+ return unix2dostime(&s.st_mtime);
+}
+
+/* ----------------------------------------------------------------------
+
+Return a malloc()'d buffer containing all of the attributes and their names
+for the file specified in name. You have to free() this yourself. The length
+of the buffer is also returned.
+
+If get_attr_dir() fails, the buffer will be NULL, total_size will be 0,
+and an error will be returned:
+
+ EOK - no errors occurred
+ EINVAL - attr_buff was pointing at a buffer
+ ENOMEM - insufficient memory for attribute buffer
+
+Other errors are possible (whatever is returned by the fs_attrib.h functions).
+
+PROBLEMS:
+
+- pointers are 32-bits; attributes are limited to ssize_t in size so it's
+ possible to overflow... in practice, this isn't too likely... your
+ machine will thrash like hell before that happens
+
+*/
+
+#define INITIAL_BUFF_SIZE 65536
+
+int get_attr_dir( const char *name, char **attr_buff, off_t *total_size )
+{
+ int retval = EOK;
+ int fd;
+ DIR *fa_dir;
+ struct dirent *fa_ent;
+ off_t attrs_size = 0;
+ size_t entname_size;
+ char *ptr;
+ struct attr_info fa_info;
+
+ *total_size = 0;
+
+ /* ----------------------------------------------------------------- */
+ /* Sanity-check. */
+ if( *attr_buff != NULL ) {
+ return EINVAL;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Can we open the file/directory? */
+ /* */
+ /* linkput is a zip global; it's set to 1 if we're storing symbolic */
+ /* links as symbolic links (instead of storing the thing the link */
+ /* points to)... if we're storing the symbolic link as a link, we'll */
+ /* want the link's file attributes, otherwise we want the target's. */
+
+ fd = open( name, linkput ? O_RDONLY | O_NOTRAVERSE : O_RDONLY );
+ if( fd < 0 ) {
+ return errno;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Allocate an initial buffer; 64k should usually be enough. */
+ *attr_buff = (char *)malloc( INITIAL_BUFF_SIZE );
+ ptr = *attr_buff;
+ if( ptr == NULL ) {
+ close( fd );
+
+ return ENOMEM;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Open the attributes directory for this file. */
+ fa_dir = open_attrdir( fd );
+ if( fa_dir == NULL ) {
+ close( fd );
+
+ free( ptr );
+ *attr_buff = NULL;
+
+ return retval;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Read all the attributes; the buffer could grow > 64K if there are */
+ /* many and/or they are large. */
+ while( ( fa_ent = read_attrdir( fa_dir ) ) != NULL ) {
+ retval = stat_attr( fd, fa_ent->d_name, &fa_info );
+ /* TODO: check retval != EOK */
+
+ entname_size = strlen( fa_ent->d_name ) + 1;
+ attrs_size += entname_size + sizeof( struct attr_info ) + fa_info.ai_size;
+
+ if( attrs_size > INITIAL_BUFF_SIZE ) {
+ unsigned long offset = ptr - *attr_buff;
+
+ *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+ if( *attr_buff == NULL ) {
+ retval = close_attrdir( fa_dir );
+ /* TODO: check retval != EOK */
+ close( fd );
+ return ENOMEM;
+ }
+
+ ptr = *attr_buff + offset;
+ }
+
+ /* Now copy the data for this attribute into the buffer. */
+ strcpy( ptr, fa_ent->d_name );
+ ptr += entname_size;
+
+ memcpy( ptr, &fa_info, sizeof( struct attr_info ) );
+ ptr += sizeof( struct attr_info );
+
+ if( fa_info.ai_size > 0 ) {
+ ssize_t read_bytes = read_attr( fd, fa_ent->d_name, fa_info.ai_type, ptr, 0, fa_info.ai_size );
+ if( read_bytes != fa_info.ai_size ) {
+ /* print a warning about mismatched sizes */
+ char buff[80];
+ sprintf( buff, "read %d, expected %d", read_bytes, (ssize_t)fa_info.ai_size );
+ zipwarn( "attribute size mismatch: ", buff );
+ }
+
+ ptr += fa_info.ai_size;
+ }
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Close the attribute directory. */
+ retval = close_attrdir( fa_dir );
+ /* TODO: check retval != EOK */
+
+ /* ----------------------------------------------------------------- */
+ /* If the buffer is too big, shrink it. */
+ if( attrs_size < INITIAL_BUFF_SIZE ) {
+ *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+ if( *attr_buff == NULL ) {
+ close( fd );
+ return ENOMEM;
+ }
+ }
+
+ *total_size = attrs_size;
+
+ close( fd );
+
+ return EOK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'UT' extra field to the zlist data pointed to by z. */
+
+#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+
+local int add_UT_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ struct stat s;
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ /* We can't work if there's no entry to work on. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_UT_SIZE > USHRT_MAX ||
+ z->cext + EB_C_UT_SIZE > USHRT_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* stat() the file (or the symlink) to get the data; if we can't get */
+ /* the data, there's no point in trying to fill out the fields. */
+ if(LSSTAT( z->name, &s ) ) {
+ return ZE_OPEN;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_UT_SIZE );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_UT_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'U';
+ *l_ef++ = 'T';
+ *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */
+ *l_ef++ = (char)0;
+ *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_ATIME);
+ *l_ef++ = (char)(s.st_mtime);
+ *l_ef++ = (char)(s.st_mtime >> 8);
+ *l_ef++ = (char)(s.st_mtime >> 16);
+ *l_ef++ = (char)(s.st_mtime >> 24);
+ *l_ef++ = (char)(s.st_atime);
+ *l_ef++ = (char)(s.st_atime >> 8);
+ *l_ef++ = (char)(s.st_atime >> 16);
+ *l_ef++ = (char)(s.st_atime >> 24);
+
+ z->ext += EB_L_UT_SIZE;
+
+ /* Now add the central version. */
+ memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE);
+ c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */
+
+ z->cext += EB_C_UT_SIZE;
+
+ return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'Ux' extra field to the zlist data pointed to by z. */
+
+#define EB_L_UX2_SIZE (EB_HEADSIZE + EB_UX2_MINLEN)
+#define EB_C_UX2_SIZE (EB_HEADSIZE)
+
+local int add_Ux_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ struct stat s;
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_UX2_SIZE > USHRT_MAX ||
+ z->cext + EB_C_UX2_SIZE > USHRT_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* stat() the file (or the symlink) to get the data; if we can't get */
+ /* the data, there's no point in trying to fill out the fields. */
+ if(LSSTAT( z->name, &s ) ) {
+ return ZE_OPEN;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_UX2_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_UX2_SIZE );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UX2_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_UX2_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'U';
+ *l_ef++ = 'x';
+ *l_ef++ = (char)(EB_UX2_MINLEN);
+ *l_ef++ = (char)(EB_UX2_MINLEN >> 8);
+ *l_ef++ = (char)(s.st_uid);
+ *l_ef++ = (char)(s.st_uid >> 8);
+ *l_ef++ = (char)(s.st_gid);
+ *l_ef++ = (char)(s.st_gid >> 8);
+
+ z->ext += EB_L_UX2_SIZE;
+
+ /* Now add the central version of the field. */
+ *c_ef++ = 'U';
+ *c_ef++ = 'x';
+ *c_ef++ = 0;
+ *c_ef++ = 0;
+
+ z->cext += EB_C_UX2_SIZE;
+
+ return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'At' extra field to the zlist data pointed to by z. */
+
+#define EB_L_AT_SIZE (EB_HEADSIZE + EB_L_AT_LEN) /* + attr size */
+#define EB_C_AT_SIZE (EB_HEADSIZE + EB_C_AT_LEN)
+
+#define MEMCOMPRESS_HEADER 6 /* ush compression type, ulg CRC */
+#define DEFLAT_WORSTCASE_ADD 5 /* byte blocktype, 2 * ush blocklength */
+#define MEMCOMPRESS_OVERHEAD (MEMCOMPRESS_HEADER + DEFLAT_WORSTCASE_ADD)
+
+local int add_At_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ char *attrbuff = NULL;
+ off_t attrsize = 0;
+ char *compbuff = NULL;
+ ush compsize = 0;
+ uch flags = 0;
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_AT_SIZE > USHRT_MAX ||
+ z->cext + EB_C_AT_SIZE > USHRT_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* Attempt to load up a buffer full of the file's attributes. */
+ {
+ if (get_attr_dir( z->name, &attrbuff, &attrsize) != EOK ) {
+ return ZE_OPEN;
+ }
+ if (attrsize == 0) {
+ return ZE_OK;
+ }
+ if (attrbuff == NULL) {
+ return ZE_LOGIC;
+ }
+
+ /* Check for way too much data. */
+ if (attrsize > (off_t)ULONG_MAX) {
+ zipwarn( "uncompressed attributes truncated", "" );
+ attrsize = (off_t)(ULONG_MAX - MEMCOMPRESS_OVERHEAD);
+ }
+ }
+
+ if (verbose) {
+ printf( "\t[in=%lu]", (unsigned long)attrsize );
+ }
+
+ /* Try compressing the data */
+ compbuff = (char *)malloc( (size_t)attrsize + MEMCOMPRESS_OVERHEAD );
+ if( compbuff == NULL ) {
+ return ZE_MEM;
+ }
+ compsize = memcompress( compbuff,
+ (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+ attrbuff,
+ (size_t)attrsize );
+ if (verbose) {
+ printf( " [out=%u]", compsize );
+ }
+
+ /* Attempt to optimise very small attributes. */
+ if (compsize > attrsize) {
+ free( compbuff );
+ compsize = (ush)attrsize;
+ compbuff = attrbuff;
+
+ flags = EB_AT_FL_NATURAL;
+ }
+
+ /* Check to see if we really have enough room in the EF for the data. */
+ if( ( z->ext + compsize + EB_L_AT_LEN ) > USHRT_MAX ) {
+ compsize = USHRT_MAX - EB_L_AT_LEN - z->ext;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_AT_SIZE + compsize );
+ } else {
+ l_ef = (char *)malloc( EB_L_AT_SIZE + compsize );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_AT_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_AT_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'A';
+ *l_ef++ = 't';
+ *l_ef++ = (char)(compsize + EB_L_AT_LEN);
+ *l_ef++ = (char)((compsize + EB_L_AT_LEN) >> 8);
+ *l_ef++ = (char)((unsigned long)attrsize);
+ *l_ef++ = (char)((unsigned long)attrsize >> 8);
+ *l_ef++ = (char)((unsigned long)attrsize >> 16);
+ *l_ef++ = (char)((unsigned long)attrsize >> 24);
+ *l_ef++ = flags;
+ memcpy( l_ef, compbuff, (size_t)compsize );
+
+ z->ext += EB_L_AT_SIZE + compsize;
+
+ /* And the central version. */
+ *c_ef++ = 'A';
+ *c_ef++ = 't';
+ *c_ef++ = (char)(EB_C_AT_LEN);
+ *c_ef++ = (char)(EB_C_AT_LEN >> 8);
+ *c_ef++ = (char)compsize;
+ *c_ef++ = (char)(compsize >> 8);
+ *c_ef++ = (char)(compsize >> 16);
+ *c_ef++ = (char)(compsize >> 24);
+ *c_ef++ = flags;
+
+ z->cext += EB_C_AT_SIZE;
+
+ return ZE_OK;
+}
+
+/* Extra field info:
+ - 'UT' - UNIX time extra field
+ - 'Ux' - UNIX uid/gid extra field
+ - 'At' - AtheOS file attributes extra field
+
+ This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields
+ (full data in local header, only modification time in central header),
+ with the 'At' field added to the end and the size of the 'At' field
+ in the central header.
+
+ See the end of atheos/osdep.h for a simple explanation of the 'At' EF
+ layout.
+ */
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* store full data in local header but just modification time stamp info
+ in central header */
+{
+ int retval;
+
+ /* Check to make sure z is valid. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ retval = add_UT_ef(z);
+ if( retval != ZE_OK ) {
+ return retval;
+ }
+
+ retval = add_Ux_ef(z);
+ if( retval != ZE_OK ) {
+ return retval;
+ }
+
+ return add_At_ef(z); /* last function; we can use return value directly */
+}
+
+/* ---------------------------------------------------------------------- */
+/* Set a file's MIME type. */
+void setfiletype(const char *file, const char *type)
+{
+ int fd;
+ off_t nLen;
+ ssize_t nError;
+
+ fd = open( file, O_RDWR );
+
+ if (fd < 0) {
+ zipwarn( "can't open zipfile to write file type", "" );
+ }
+
+ else
+ {
+ nLen = strlen( type );
+ /* FIXME: write_attr() should return count of writed bytes */
+ nError = write_attr( fd, "os::MimeType", O_TRUNC, ATTR_TYPE_STRING, type, 0, nLen );
+ if (nError < 0) {
+ zipwarn( "couldn't write complete file type", "" );
+ }
+ close( fd );
+ }
+}
+
+#endif /* !UTIL */
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+ "(unknown compiler)", "",
+#endif
+
+ "Syllable",
+
+#if defined(i486) || defined(__i486) || defined(__i486__) || defined(i386) || defined(__i386) || defined(__i386__)
+ " (x86)",
+#else
+ " (unknown platform)",
+#endif
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
diff --git a/atheos/osdep.h b/atheos/osdep.h
new file mode 100644
index 0000000..0869f94
--- /dev/null
+++ b/atheos/osdep.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+
+#ifndef _OSDEP_H_
+#define _OSDEP_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/unistd.h>
+
+#define USE_EF_UT_TIME /* Enable use of "UT" extra field time info */
+
+#define EB_L_AT_LEN 5 /* min size is an unsigned long and flag */
+#define EB_C_AT_LEN 5 /* Length of data in local EF and flag. */
+
+#define EB_AT_FL_NATURAL 0x01 /* data is 'natural' (not compressed) */
+#define EB_AT_FL_BADBITS 0xfe /* bits currently undefined */
+
+#ifndef ZP_NEED_MEMCOMPR
+ define ZP_NEED_MEMCOMPR
+#endif
+
+#define deletedir(d) rmdir(d);
+
+/* Set a file's MIME type. */
+void setfiletype( const char *file, const char *type );
+
+/*
+'At' extra-field layout:
+
+'At' - signature
+ef_size - size of data in this EF (little-endian unsigned short)
+full_size - uncompressed data size (little-endian unsigned long)
+flag - flags (byte)
+ flags & EB_AT_FL_NATURAL = the data is not compressed
+ flags & EB_AT_FL_BADBITS = the data is corrupted or we
+ can't handle it properly
+data - compressed or uncompressed file attribute data
+
+If flag & EB_AT_FL_NATURAL, the data is not compressed; this optimisation is
+necessary to prevent wasted space for files with small attributes. In this
+case, there should be ( ef_size - EB_L_AT_LEN ) bytes of data, and full_size
+should equal ( ef_size - EB_L_AT_LEN ).
+
+If the data is compressed, there will be ( ef_size - EB_L_AT_LEN ) bytes of
+compressed data, and full_size bytes of uncompressed data.
+
+If a file has absolutely no attributes, there will not be a 'At' extra field.
+
+The uncompressed data is arranged like this:
+
+attr_name\0 - C string
+struct attr_info (little-endian)
+attr_data (length in attr_info.ai_size)
+*/
+
+#endif
+
diff --git a/atheos/zipup.h b/atheos/zipup.h
new file mode 100644
index 0000000..d3d39a3
--- /dev/null
+++ b/atheos/zipup.h
@@ -0,0 +1,24 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef _ZIPUP_H_
+#define _ZIPUP_H_
+
+#ifndef O_RDONLY
+# include <sys/fcntl.h>
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
+
+#endif /* _ZIPUP_H_ */
diff --git a/beos/Contents b/beos/Contents
new file mode 100644
index 0000000..939a535
--- /dev/null
+++ b/beos/Contents
@@ -0,0 +1,14 @@
+Contents of the "beos" sub-directory for Zip 2.2 and later:
+
+ Contents this file
+ README Notes from the author of the BeOS port
+ Makefile makefile for building (sorry, no project files)
+ beos.c BeOS-specific routines (similar to the UNIX ones)
+ osdep.h BeOS-specific includes and whatnot
+ zipup.h Definitions for zip routines
+
+This port supports both Metrowerks CodeWarrior and GNU C as the compiler,
+and PowerPC and x86 architectures.
+
+- Chris Herborth (chrish@pobox.com)
+ June 24, 1998
diff --git a/beos/Makefile b/beos/Makefile
new file mode 100644
index 0000000..1b9e613
--- /dev/null
+++ b/beos/Makefile
@@ -0,0 +1,182 @@
+######################################################################
+#
+# Makefile for Info-ZIP's zip, zipcloak, zipnote, and zipsplit on BeOS
+#
+# Copyright © 1999 Info-ZIP
+# Chris Herborth (chrish@pobox.com)
+#
+# This is the new New and Improved Makefile for BeOS; it automatically
+# detects your platform and uses the appropriate compiler and compiler
+# flags.
+
+######################################################################
+# Things that don't change:
+
+# Punish people who don't have SMP hardware.
+MAKE = make -j 4 -f beos/Makefile
+SHELL = /bin/sh
+
+LN = ln -s
+
+BIND = $(CC)
+AS = $(CC) -c
+CPP = $(CC) -E
+
+INSTALL = install
+
+# Target directories
+prefix = /boot/home/config
+BINDIR = $(prefix)/bin
+manext = 1
+MANDIR = $(prefix)/man/man$(manext)
+ZIPMANUAL = MANUAL
+
+VERSION = Version 2.3 of __DATE__
+
+######################################################################
+# Things that change:
+
+# PowerPC system
+ifeq "$(BE_HOST_CPU)" "ppc"
+
+CC:=mwcc
+
+ifeq "$(shell uname -r)" "4.0"
+
+CFLAGS:=-O7 -opt schedule604 -rostr -w9 \
+ -I. -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN
+LFLAGS1:=-warn
+
+else
+
+CFLAGS:=-O7 -proc 604e -w9 -I. -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN
+LFLAGS1:=-nodup
+
+endif
+
+LFLAGS2:=-L/boot/develop/lib/ppc -lbe -lroot
+OBJA =
+TARGET=$(ZIPS)
+
+# x86 system
+else
+
+CC:=gcc
+
+# Removed -Wconversion and -Wshadow because of the unnecessary warnings
+# they generate. - Sept. 28, 1999
+CFLAGS:=-O3 -mpentiumpro \
+ -Wall -Wno-multichar -Wno-ctor-dtor-privacy \
+ -Wbad-function-cast -Woverloaded-virtual \
+ -I. -I/boot/develop/headers/be/support \
+ -I/boot/develop/headers/be/storage \
+ -DHAVE_DIRENT_H -DPASSWD_FROM_STDIN # -DASMV
+LFLAGS1:=
+LFLAGS2:=-L/boot/develop/lib/x86 -lbe -lroot
+OBJA = #match.o
+TARGET=$(ZIPS)
+
+endif
+
+######################################################################
+# Helpful targets
+all:
+ $(MAKE) CC=$(CC) CFLAGS="$(CFLAGS)" \
+ LFLAGS1="$(LFLAGS1)" LFLAGS2="$(LFLAGS2)" \
+ $(TARGET)
+
+######################################################################
+# Object file lists and other build goodies
+
+# Object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+ beos.o crc32.o
+OBJI = deflate.o trees.o
+# OBJA moved into ifeq block above; we'll use assembly for x86
+OBJU = zipfile_.o fileio_.o util_.o globals.o beos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+# Headers
+ZIP_H = zip.h ziperr.h tailor.h beos/osdep.h
+
+# What to build?
+ZIPS = zip zipnote zipsplit zipcloak
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+ rm -f $*_.c; $(LN) $< $*_.c
+ $(CC) -c $(CFLAGS) -DUTIL $*_.c
+ rm -f $*_.c
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+ groff -man -Tascii $< > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: beos/zipup.h
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(AS) _match.s
+ mv -f _match.o match.o
+ rm -f _match.s
+
+beos.o: beos/beos.c
+ $(CC) -c $(CFLAGS) beos/beos.c
+
+beos_.o: beos/beos.c
+ rm -f $*_.c; $(LN) beos/beos.c $*_.c
+ $(CC) -c $(CFLAGS) -DUTIL $*_.c
+ rm -f $*_.c
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip: $(OBJZ) $(OBJI) $(OBJA)
+ $(BIND) -o zip $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote: $(OBJN)
+ $(BIND) -o zipnote $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak: $(OBJC)
+ $(BIND) -o zipcloak $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit: $(OBJS)
+ $(BIND) -o zipsplit $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+ groff -man -Tascii man/zip.1 > $(ZIPMANUAL)
+
+# install
+install: $(ZIPS)
+ $(INSTALL) -m755 $(ZIPS) $(BINDIR)
+ mkdir -p $(MANDIR)
+ $(INSTALL) -m644 man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+ -cd $(BINDIR); rm -f $(ZIPS)
+ -cd $(MANDIR); rm -f zip.$(manext)
+
+dist: $(ZIPMANUAL)
+ zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+ -e s/[.]//g -e q revision.h` \
+ `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+# clean up after making stuff and installing it
+clean:
+ rm -f *.o $(ZIPS) flags
+
+# end of Makefile
diff --git a/beos/README b/beos/README
new file mode 100644
index 0000000..b985ea0
--- /dev/null
+++ b/beos/README
@@ -0,0 +1,31 @@
+Info-ZIP's zip for BeOS
+
+KNOWN BUGS
+
+- None! (as of zip 2.21)
+
+- building on x86 BeOS generates a hell of a lot of bugs; I'm not going to
+ worry about them until Be fixes their headers though...
+
+FEATURES
+
+- stores BeOS file attributes, compressing them if possible (as of 2.21,
+ this works properly for symbolic links, too; as of 2.3, this works
+ properly for symbolic links whether you're storing them as links or not)
+
+- zip files are created with the correct file type (application/zip)
+
+- supports both Metrowerks CodeWarrior (PowerPC platform) and GNU C
+ (x86 platform), automatically picking the default compiler for each
+ architecture
+
+Please report any bugs to the Zip-Bugs mailing list; our email address is
+zip-bugs@lists.wku.edu. If it's something BeOS-specific, you could email
+me directly.
+
+Visit the Info-ZIP web site (http://www.cdrom.com/pub/infozip/) for all the
+latest zip and unzip information, FAQs, source code and ready-to-run
+executables.
+
+- Chris Herborth (chrish@pobox.com)
+ April 2/1999
diff --git a/beos/beos.c b/beos/beos.c
new file mode 100644
index 0000000..d8d16df
--- /dev/null
+++ b/beos/beos.c
@@ -0,0 +1,945 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+
+ This BeOS-specific file is based on unix.c in the unix directory; changes
+ by Chris Herborth (chrish@pobox.com).
+
+*/
+
+#include "zip.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <dirent.h>
+
+#include <kernel/fs_attr.h>
+#include <storage/Mime.h>
+#include <support/byteorder.h>
+
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef _POSIX_VERSION
+# include <utime.h>
+#else
+ int utime OF((char *, time_t *));
+#endif
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+local int get_attr_dir( const char *, char **, off_t * );
+local int add_UT_ef( struct zlist far * );
+local int add_Ux_ef( struct zlist far * );
+local int add_Be_ef( struct zlist far * );
+
+
+#ifdef NO_DIR /* for AT&T 3B1 */
+#include <sys/dir.h>
+#ifndef dirent
+# define dirent direct
+#endif
+typedef FILE DIR;
+/*
+** Apparently originally by Rich Salz.
+** Cleaned up and modified by James W. Birdsall.
+*/
+
+#define opendir(path) fopen(path, "r")
+
+struct dirent *readdir(dirp)
+DIR *dirp;
+{
+ static struct dirent entry;
+
+ if (dirp == NULL)
+ return NULL;
+ for (;;)
+ if (fread (&entry, sizeof (struct dirent), 1, dirp) == 0)
+ return NULL;
+ else if (entry.d_ino)
+ return (&entry);
+} /* end of readdir() */
+
+#define closedir(dirp) fclose(dirp)
+#endif /* NO_DIR */
+
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ for (t = x; *t == '/'; t++)
+ ; /* strip leading '/' chars to get a relative path */
+ while (*t == '.' && t[1] == '/')
+ t += 2; /* strip redundant leading "./" sections */
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (isdir == 42) return n; /* avoid warning on unused variable */
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+ return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#ifdef _POSIX_VERSION
+ struct utimbuf u; /* argument for utime() const ?? */
+#else
+ time_t u[2]; /* argument for utime() */
+#endif
+
+ /* Convert DOS time to time_t format in u */
+#ifdef _POSIX_VERSION
+ u.actime = u.modtime = dos2unixtime(d);
+ utime(f, &u);
+#else
+ u[0] = u[1] = dos2unixtime(d);
+ utime(f, u);
+#endif
+
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNAMX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFMT) == S_IFDIR) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_mtime; /* best guess (s.st_ctime: last status change!) */
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+/* ----------------------------------------------------------------------
+
+Return a malloc()'d buffer containing all of the attributes and their names
+for the file specified in name. You have to free() this yourself. The length
+of the buffer is also returned.
+
+If get_attr_dir() fails, the buffer will be NULL, total_size will be 0,
+and an error will be returned:
+
+ EOK - no errors occurred
+ EINVAL - attr_buff was pointing at a buffer
+ ENOMEM - insufficient memory for attribute buffer
+
+Other errors are possible (whatever is returned by the fs_attr.h functions).
+
+PROBLEMS:
+
+- pointers are 32-bits; attributes are limited to off_t in size so it's
+ possible to overflow... in practice, this isn't too likely... your
+ machine will thrash like hell before that happens
+
+*/
+
+#define INITIAL_BUFF_SIZE 65536
+
+int get_attr_dir( const char *name, char **attr_buff, off_t *total_size )
+{
+ int retval = EOK;
+ int fd;
+ DIR *fa_dir;
+ struct dirent *fa_ent;
+ off_t attrs_size;
+ off_t this_size;
+ char *ptr;
+ struct attr_info fa_info;
+ struct attr_info big_fa_info;
+
+ retval = EOK;
+ attrs_size = 0; /* gcc still says this is used uninitialized... */
+ *total_size = 0;
+
+ /* ----------------------------------------------------------------- */
+ /* Sanity-check. */
+ if( *attr_buff != NULL ) {
+ return EINVAL;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Can we open the file/directory? */
+ /* */
+ /* linkput is a zip global; it's set to 1 if we're storing symbolic */
+ /* links as symbolic links (instead of storing the thing the link */
+ /* points to)... if we're storing the symbolic link as a link, we'll */
+ /* want the link's file attributes, otherwise we want the target's. */
+ if( linkput ) {
+ fd = open( name, O_RDONLY | O_NOTRAVERSE );
+ } else {
+ fd = open( name, O_RDONLY );
+ }
+ if( fd < 0 ) {
+ return errno;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Allocate an initial buffer; 64k should usually be enough. */
+ *attr_buff = (char *)malloc( INITIAL_BUFF_SIZE );
+ ptr = *attr_buff;
+ if( ptr == NULL ) {
+ close( fd );
+
+ return ENOMEM;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Open the attributes directory for this file. */
+ fa_dir = fs_fopen_attr_dir( fd );
+ if( fa_dir == NULL ) {
+ close( fd );
+
+ free( ptr );
+ *attr_buff = NULL;
+
+ return retval;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Read all the attributes; the buffer could grow > 64K if there are */
+ /* many and/or they are large. */
+ fa_ent = fs_read_attr_dir( fa_dir );
+ while( fa_ent != NULL ) {
+ retval = fs_stat_attr( fd, fa_ent->d_name, &fa_info );
+ /* TODO: check retval != EOK */
+
+ this_size = strlen( fa_ent->d_name ) + 1;
+ this_size += sizeof( struct attr_info );
+ this_size += fa_info.size;
+
+ attrs_size += this_size;
+
+ if( attrs_size > INITIAL_BUFF_SIZE ) {
+ unsigned long offset = ptr - *attr_buff;
+
+ *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+ if( *attr_buff == NULL ) {
+ retval = fs_close_attr_dir( fa_dir );
+ /* TODO: check retval != EOK */
+ close( fd );
+
+ return ENOMEM;
+ }
+
+ ptr = *attr_buff + offset;
+ }
+
+ /* Now copy the data for this attribute into the buffer. */
+ strcpy( ptr, fa_ent->d_name );
+ ptr += strlen( fa_ent->d_name );
+ *ptr++ = '\0';
+
+ /* We need to put a big-endian version of the fa_info data into */
+ /* the archive. */
+ big_fa_info.type = B_HOST_TO_BENDIAN_INT32( fa_info.type );
+ big_fa_info.size = B_HOST_TO_BENDIAN_INT64( fa_info.size );
+ memcpy( ptr, &big_fa_info, sizeof( struct attr_info ) );
+ ptr += sizeof( struct attr_info );
+
+ if( fa_info.size > 0 ) {
+ ssize_t read_bytes;
+
+ read_bytes = fs_read_attr( fd, fa_ent->d_name, fa_info.type, 0,
+ ptr, fa_info.size );
+ if( read_bytes != fa_info.size ) {
+ /* print a warning about mismatched sizes */
+ char buff[80];
+
+ sprintf( buff, "read %ld, expected %ld",
+ (ssize_t)read_bytes, (ssize_t)fa_info.size );
+ zipwarn( "attribute size mismatch: ", buff );
+ }
+
+ /* Wave my magic wand... this swaps all the Be types to big- */
+ /* endian automagically. */
+ (void)swap_data( fa_info.type, ptr, fa_info.size,
+ B_SWAP_HOST_TO_BENDIAN );
+
+ ptr += fa_info.size;
+ }
+
+ fa_ent = fs_read_attr_dir( fa_dir );
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* Close the attribute directory. */
+ retval = fs_close_attr_dir( fa_dir );
+ /* TODO: check retval != EOK */
+
+ /* ----------------------------------------------------------------- */
+ /* If the buffer is too big, shrink it. */
+ if( attrs_size < INITIAL_BUFF_SIZE ) {
+ *attr_buff = (char *)realloc( *attr_buff, attrs_size );
+ if( *attr_buff == NULL ) {
+ /* This really shouldn't happen... */
+ close( fd );
+
+ return ENOMEM;
+ }
+ }
+
+ *total_size = attrs_size;
+
+ close( fd );
+
+ return EOK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'UT' extra field to the zlist data pointed to by z. */
+
+#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+
+local int add_UT_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ struct stat s;
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ /* We can't work if there's no entry to work on. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_UT_SIZE > USHRT_MAX ||
+ z->cext + EB_C_UT_SIZE > USHRT_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* stat() the file (or the symlink) to get the data; if we can't get */
+ /* the data, there's no point in trying to fill out the fields. */
+ if(LSSTAT( z->name, &s ) ) {
+ return ZE_OPEN;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_UT_SIZE );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_UT_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'U';
+ *l_ef++ = 'T';
+ *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */
+ *l_ef++ = (char)0;
+ *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_ATIME);
+ *l_ef++ = (char)(s.st_mtime);
+ *l_ef++ = (char)(s.st_mtime >> 8);
+ *l_ef++ = (char)(s.st_mtime >> 16);
+ *l_ef++ = (char)(s.st_mtime >> 24);
+ *l_ef++ = (char)(s.st_atime);
+ *l_ef++ = (char)(s.st_atime >> 8);
+ *l_ef++ = (char)(s.st_atime >> 16);
+ *l_ef++ = (char)(s.st_atime >> 24);
+
+ z->ext += EB_L_UT_SIZE;
+
+ /* Now add the central version. */
+ memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE);
+ c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */
+
+ z->cext += EB_C_UT_SIZE;
+
+ return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'Ux' extra field to the zlist data pointed to by z. */
+
+#define EB_L_UX2_SIZE (EB_HEADSIZE + EB_UX2_MINLEN)
+#define EB_C_UX2_SIZE (EB_HEADSIZE)
+
+local int add_Ux_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ struct stat s;
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_UX2_SIZE > USHRT_MAX ||
+ z->cext + EB_C_UX2_SIZE > USHRT_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* stat() the file (or the symlink) to get the data; if we can't get */
+ /* the data, there's no point in trying to fill out the fields. */
+ if(LSSTAT( z->name, &s ) ) {
+ return ZE_OPEN;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_UX2_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_UX2_SIZE );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UX2_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_UX2_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'U';
+ *l_ef++ = 'x';
+ *l_ef++ = (char)(EB_UX2_MINLEN);
+ *l_ef++ = (char)(EB_UX2_MINLEN >> 8);
+ *l_ef++ = (char)(s.st_uid);
+ *l_ef++ = (char)(s.st_uid >> 8);
+ *l_ef++ = (char)(s.st_gid);
+ *l_ef++ = (char)(s.st_gid >> 8);
+
+ z->ext += EB_L_UX2_SIZE;
+
+ /* Now add the central version of the field. */
+ *c_ef++ = 'U';
+ *c_ef++ = 'x';
+ *c_ef++ = 0;
+ *c_ef++ = 0;
+
+ z->cext += EB_C_UX2_SIZE;
+
+ return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'Be' extra field to the zlist data pointed to by z. */
+
+#define EB_L_BE_SIZE (EB_HEADSIZE + EB_L_BE_LEN) /* + attr size */
+#define EB_C_BE_SIZE (EB_HEADSIZE + EB_C_BE_LEN)
+
+/* maximum memcompress overhead is the sum of the compression header length */
+/* (6 = ush compression type, ulg CRC) and the worstcase deflate overhead */
+/* when uncompressible data are kept in 2 "stored" blocks (5 per block = */
+/* byte blocktype + 2 * ush blocklength) */
+#define MEMCOMPRESS_OVERHEAD (EB_MEMCMPR_HSIZ + EB_DEFLAT_EXTRA)
+
+local int add_Be_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ char *attrbuff = NULL;
+ off_t attrsize = 0;
+ char *compbuff = NULL;
+ ush compsize = 0;
+ uch flags = 0;
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_BE_SIZE > USHRT_MAX ||
+ z->cext + EB_C_BE_SIZE > USHRT_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* Attempt to load up a buffer full of the file's attributes. */
+ {
+ int retval;
+
+ retval = get_attr_dir( z->name, &attrbuff, &attrsize );
+ if( retval != EOK ) {
+ return ZE_OPEN;
+ }
+ if( attrsize == 0 ) {
+ return ZE_OK;
+ }
+ if( attrbuff == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* Check for way too much data. */
+ if( attrsize > (off_t)ULONG_MAX ) {
+ zipwarn( "uncompressed attributes truncated", "" );
+ attrsize = (off_t)(ULONG_MAX - MEMCOMPRESS_OVERHEAD);
+ }
+ }
+
+ if( verbose ) {
+ printf( "\t[in=%lu]", (unsigned long)attrsize );
+ }
+
+ /* Try compressing the data */
+ compbuff = (char *)malloc( (size_t)attrsize + MEMCOMPRESS_OVERHEAD );
+ if( compbuff == NULL ) {
+ return ZE_MEM;
+ }
+ compsize = memcompress( compbuff,
+ (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+ attrbuff,
+ (size_t)attrsize );
+ if( verbose ) {
+ printf( " [out=%u]", compsize );
+ }
+
+ /* Attempt to optimise very small attributes. */
+ if( compsize > attrsize ) {
+ free( compbuff );
+ compsize = (ush)attrsize;
+ compbuff = attrbuff;
+
+ flags = EB_BE_FL_NATURAL;
+ }
+
+ /* Check to see if we really have enough room in the EF for the data. */
+ if( ( z->ext + compsize + EB_L_BE_LEN ) > USHRT_MAX ) {
+ compsize = USHRT_MAX - EB_L_BE_LEN - z->ext;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_BE_SIZE + compsize );
+ } else {
+ l_ef = (char *)malloc( EB_L_BE_SIZE + compsize );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_BE_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_BE_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'B';
+ *l_ef++ = 'e';
+ *l_ef++ = (char)(compsize + EB_L_BE_LEN);
+ *l_ef++ = (char)((compsize + EB_L_BE_LEN) >> 8);
+ *l_ef++ = (char)((unsigned long)attrsize);
+ *l_ef++ = (char)((unsigned long)attrsize >> 8);
+ *l_ef++ = (char)((unsigned long)attrsize >> 16);
+ *l_ef++ = (char)((unsigned long)attrsize >> 24);
+ *l_ef++ = flags;
+ memcpy( l_ef, compbuff, (size_t)compsize );
+
+ z->ext += EB_L_BE_SIZE + compsize;
+
+ /* And the central version. */
+ *c_ef++ = 'B';
+ *c_ef++ = 'e';
+ *c_ef++ = (char)(EB_C_BE_LEN);
+ *c_ef++ = (char)(EB_C_BE_LEN >> 8);
+ *c_ef++ = (char)compsize;
+ *c_ef++ = (char)(compsize >> 8);
+ *c_ef++ = (char)(compsize >> 16);
+ *c_ef++ = (char)(compsize >> 24);
+ *c_ef++ = flags;
+
+ z->cext += EB_C_BE_SIZE;
+
+ return ZE_OK;
+}
+
+/* Extra field info:
+ - 'UT' - UNIX time extra field
+ - 'Ux' - UNIX uid/gid extra field
+ - 'Be' - BeOS file attributes extra field
+
+ This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields
+ (full data in local header, only modification time in central header),
+ with the 'Be' field added to the end and the size of the 'Be' field
+ in the central header.
+
+ See the end of beos/osdep.h for a simple explanation of the 'Be' EF
+ layout.
+ */
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* store full data in local header but just modification time stamp info
+ in central header */
+{
+ int retval;
+
+ /* Tell picky compilers to shut up about unused variables. */
+ z_utim = z_utim;
+
+ /* Check to make sure z is valid. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* This function is much simpler now that I've moved the extra fields */
+ /* out... it simplified the 'Be' code, too. */
+ retval = add_UT_ef( z );
+ if( retval != ZE_OK ) {
+ return retval;
+ }
+
+ retval = add_Ux_ef( z );
+ if( retval != ZE_OK ) {
+ return retval;
+ }
+
+ retval = add_Be_ef( z );
+ if( retval != ZE_OK ) {
+ return retval;
+ }
+
+ return ZE_OK;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Set a file's MIME type. */
+void setfiletype( const char *file, const char *type )
+{
+ int fd;
+ attr_info fa;
+ ssize_t wrote_bytes;
+
+ fd = open( file, O_RDWR );
+ if( fd < 0 ) {
+ zipwarn( "can't open zipfile to write file type", "" );
+ return;
+ }
+
+ fa.type = B_MIME_STRING_TYPE;
+ fa.size = (off_t)(strlen( type ) + 1);
+
+ wrote_bytes = fs_write_attr( fd, BE_FILE_TYPE_NAME, fa.type, 0,
+ type, fa.size );
+ if( wrote_bytes != (ssize_t)fa.size ) {
+ zipwarn( "couldn't write complete file type", "" );
+ }
+
+ close( fd );
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+# ifdef NO_RMDIR
+ /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
+ int r, len;
+ char *s; /* malloc'd string for system command */
+
+ len = strlen(d);
+ if ((s = malloc(len + 34)) == NULL)
+ return 127;
+
+ sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
+ r = system(s);
+ free(s);
+ return r;
+# else /* !NO_RMDIR */
+ return rmdir(d);
+# endif /* ?NO_RMDIR */
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+
+ printf(CompiledWith,
+
+#ifdef __MWERKS__
+ "Metrowerks CodeWarrior", "",
+#else
+# ifdef __GNUC__
+ "gcc ", __VERSION__,
+# endif
+#endif
+
+ "BeOS",
+
+#ifdef __POWERPC__
+ " (PowerPC)",
+#else
+# ifdef __INTEL__
+ " (x86)",
+# else
+ " (UNKNOWN!)",
+# endif
+#endif
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
diff --git a/beos/osdep.h b/beos/osdep.h
new file mode 100644
index 0000000..0197903
--- /dev/null
+++ b/beos/osdep.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <support/Errors.h> /* for B_NO_ERROR */
+
+#define USE_EF_UT_TIME /* Enable use of "UT" extra field time info */
+
+#define EB_L_BE_LEN 5 /* min size is an unsigned long and flag */
+#define EB_C_BE_LEN 5 /* Length of data in local EF and flag. */
+
+#define EB_BE_FL_NATURAL 0x01 /* data is 'natural' (not compressed) */
+#define EB_BE_FL_BADBITS 0xfe /* bits currently undefined */
+
+#ifndef ZP_NEED_MEMCOMPR
+# define ZP_NEED_MEMCOMPR
+#endif
+
+/* Set a file's MIME type. */
+#define BE_FILE_TYPE_NAME "BEOS:TYPE"
+void setfiletype( const char *file, const char *type );
+
+/*
+DR9 'Be' extra-field layout:
+
+'Be' - signature
+ef_size - size of data in this EF (little-endian unsigned short)
+full_size - uncompressed data size (little-endian unsigned long)
+flag - flags (byte)
+ flags & EB_BE_FL_NATURAL = the data is not compressed
+ flags & EB_BE_FL_BADBITS = the data is corrupted or we
+ can't handle it properly
+data - compressed or uncompressed file attribute data
+
+If flag & EB_BE_FL_NATURAL, the data is not compressed; this optimisation is
+necessary to prevent wasted space for files with small attributes (which
+appears to be quite common on the Advanced Access DR9 release). In this
+case, there should be ( ef_size - EB_L_BE_LEN ) bytes of data, and full_size
+should equal ( ef_size - EB_L_BE_LEN ).
+
+If the data is compressed, there will be ( ef_size - EB_L_BE_LEN ) bytes of
+compressed data, and full_size bytes of uncompressed data.
+
+If a file has absolutely no attributes, there will not be a 'Be' extra field.
+
+The uncompressed data is arranged like this:
+
+attr_name\0 - C string
+struct attr_info (big-endian)
+attr_data (length in attr_info.size)
+*/
diff --git a/beos/zipup.h b/beos/zipup.h
new file mode 100644
index 0000000..40c79eb
--- /dev/null
+++ b/beos/zipup.h
@@ -0,0 +1,19 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# include <fcntl.h>
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/bzip2/install.txt b/bzip2/install.txt
new file mode 100644
index 0000000..87d45ad
--- /dev/null
+++ b/bzip2/install.txt
@@ -0,0 +1,258 @@
+HOW TO ADD BZIP2 SUPPORT TO ZIP
+
+This document describes how to add bzip2 support to Zip.
+
+Compiling or linking in the bzip2 library adds an additional bzip2
+compression method to Zip. This new method can be selected instead
+of the Zip traditional compression method deflation to compress files
+and often gives a better compression ratio (perhaps at the cost of
+greater CPU time). The compression method is specified using the
+"-Z method" command-line option, where "method" may be either "deflate"
+(the default), or "bzip2" (if Zip is built with bzip2 support). Zip
+has been tested with bzip2 library 1.0.5 and earlier.
+
+Notes
+
+Compression method bzip2 requires a modern unzip. Before using bzip2
+compression in Zip, verify that a modern UnZip program with bzip2 support
+will be used to read the resulting zip archive so that entries compressed
+with bzip2 (compression method 12) can be read. Older unzips probably
+won't recognize the compression method and will skip those entries.
+
+The Zip source kit does not include the bzip2 library or source files, but
+these can be found at "http://www.bzip.org/" for example. See below for
+how to add bzip2 to Zip for various operating systems.
+
+Zip using bzip2 compression is not compatible with the bzip2 application,
+but instead provides an additional way to compress files before adding
+them to a Zip archive. It does not replace the bzip2 program itself,
+which creates bzip2 archives in a different format that are not
+compatible with zip or unzip.
+
+The bzip2 code and algorithms are provided under the bzip2 license
+(provided in the bzip2 source kit) and what is not covered by that license
+is covered under the Info-ZIP license. Info-ZIP will look at issues
+involving the use of bzip2 compression in Zip, but any questions about
+the bzip2 code and algorithms or bzip2 licensing, for example, should be
+directed to the bzip2 maintainer.
+
+
+Installation
+
+To build Zip with bzip2 support, Zip generally needs one bzip2 header
+file, "bzlib.h", and the object library, typically "libbz2.a", except
+in cases where the source files are compiled in directly. If you
+are either compiling the bzip2 library or compiling in the bzip2
+source files, we recommend defining the C macro BZ_NO_STDIO, which
+excludes a lot of standalone error code (not used when bzip2 is
+used as a library and makes the library smaller) and provides hooks
+that Zip can use to provide better error handling. However, a
+standard bzip2 object library will work, though any errors that bzip2
+generates may be more cryptic.
+
+Building the bzip2 library from the bzip2 source files (recommended):
+
+ Download the latest bzip2 package (from "http://www.bzip.org/", for
+ example).
+
+ Unpack the bzip2 source kit (bzip2-1.0.5.tar.gz was current as of
+ this writing, but the latest should work).
+
+ Read the README file in the bzip2 source kit.
+
+ Compile the bzip2 library for your OS, preferably defining
+ BZ_NO_STDIO. Note: On UNIX systems, this may be done automatically
+ when building Zip, as explained below.
+
+
+Installation on UNIX (see below for installation on other systems):
+
+ Note: Zip on UNIX uses the "bzlib.h" include file and the compiled
+ "libbz2.a" library to static link to bzip2. Currently we do not
+ support using the shared library (patches welcome).
+
+ The easiest approach may be to drop the two above files in the
+ bzip2 directory of the Zip source tree and build Zip using the
+ "generic" target, that is, using a command like
+ make -f unix/Makefile generic
+ If all goes well, make should confirm that it found the files and
+ will be compiling in bzip2 by setting the BZIP2_SUPPORT flag and
+ then including the libraries while compiling and linking Zip.
+
+ To use bzlib.h and libbz2.a from somewhere else on your system,
+ define the "make" macro IZ_BZIP2 to point to that directory. For
+ example:
+ make -f unix/Makefile generic IZ_BZIP2=/mybz2
+ where /mybz2 might be "/usr/local/src/bzip2/bzip2-1.0.5" on some
+ systems. Only a compiled bzip2 library can be pointed to using
+ IZ_BZIP2 and Zip will not compile bzip2 source in other than the
+ bzip2 directory.
+
+ If IZ_BZIP2 is not defined, Zip will look for the bzip2 files in
+ the "bzip2" directory in the Zip source directory. The bzip2
+ directory is empty in the Zip source distribution (except for
+ this install.txt file) and is provided as a place to put the
+ bzip2 files. To use this directory, either drop bzlib.h and
+ libbz2.a in it to use the compiled library as noted above or drop
+ the contents of the bzip2 source kit in this directory so that
+ bzlib.h is directly in the bzip2 directory and Zip will try to
+ compile it if no compiled library is already there.
+
+
+ Unpacking bzip2 so Zip compiles it:
+
+ To make this work, the bzip2 source kit must be unpacked directly
+ into the Zip "bzip2" directory. For example:
+
+ # Unpack the Zip source kit.
+ gzip -cd zip30.tar-gz | tar xfo -
+ # Move down to the Zip kit's "bzip2" directory, ...
+ cd zip30/bzip2
+ # ... and unpack the bzip2 source kit there.
+ gzip -cd ../../bzip2-1.0.5.tar.gz | tar xfo -
+ # Move the bzip2 source files up to the Zip kit's bzip2 directory.
+ cd bzip2-1.0.5
+ mv * ..
+ # Return to the Zip source kit directory, ready to build.
+ cd ../..
+ # Build Zip.
+ make -f unix/Makefile generic
+
+
+ Using a system bzip2 library:
+
+ If IZ_BZIP2 is not defined and both a compiled library and the bzip2
+ source files are missing from the Zip bzip2 directory, Zip will test
+ to see if bzip2 is globally defined on the system in the default
+ include and library paths and, if found, link in the system bzip2
+ library. This is automatic.
+
+
+ Preventing inclusion of bzip2:
+
+ To build Zip with _no_ bzip2 support on a system where the automatic
+ bzip2 detection scheme will find bzip2, you can specify a bad
+ IZ_BZIP2 directory. For example:
+
+ make -f unix/Makefile generic IZ_BZIP2=no_such_directory
+
+ You can also define NO_BZIP2_SUPPORT to exclude bzip2.
+
+
+ Verifying bzip2 support in Zip:
+
+ When the Zip build is complete, verify that bzip2 support has been
+ enabled by checking the feature list:
+
+ ./zip -v
+
+ If all went well, bzip2 (and its library version) should be listed.
+
+
+Installation on other systems
+
+ MSDOS:
+
+ Thanks to Robert Riebisch, the DJGPP 2.x Zip port now supports bzip2.
+ To include bzip2, first install bzip2. The new msdos/makebz2.dj2
+ makefile then looks in the standard bzip2 installation directories
+ for the needed files. As he says:
+ It doesn't try to be clever about finding libbz2.a. It just
+ expects bzip2 stuff installed to the default include and library
+ folders, e.g., "C:\DJGPP\include" and "C:\DJGPP\lib" on DOS.
+
+ Given a standard DJGPP 2.x installation, this should create a
+ version of Zip 3.0 with bzip2 support.
+
+ The bzip2 library for DJGPP can be found on any DJGPP mirror in
+ "current/v2apps" (or "beta/v2apps/" for the latest beta). This
+ library has been ported to MSDOS/DJGPP by Juan Manuel Guerrero.
+
+
+ WIN32 (Windows NT/2K/XP/2K3/... and Windows 95/98/ME):
+
+ For Windows there seems to be two approaches, either use bzip2
+ as a dynamic link library or compile the bzip2 source in directly.
+ I have not gotten the static library libbz2.lib to work, but that
+ may be me.
+
+ Using bzip2 as a dynamic link library:
+
+ Building bzip2:
+
+ If you have the needed bzlib.h, libbz2.lib, and libbz2.dll files
+ you can skip building bzip2. If not, open the libbz2.dsp project
+ and build libbz2.dll
+
+ This creates
+ debug/libbz2.lib
+ and
+ libbz2.dll
+
+
+ Building Zip:
+
+ Copy libbz2.lib to the bzip2 directory in the Zip source tree. This
+ is needed to compile Zip with bzip2 support. Also copy the matching
+ bzlib.h from the bzip2 source to the same directory.
+
+ Add libbz2.lib to the link list for whatever you are building. Also
+ define the compiler define BZIP2_SUPPORT.
+
+ Build Zip.
+
+
+ Using Zip with bzip2 as dll:
+
+ Put libbz2.dll in your command path. This is needed to run Zip with
+ bzip2 support.
+
+ Verify that bzip2 is enabled with the command
+
+ zip -v
+
+ You should see bzip2 listed.
+
+ Compiling in bzip2 from the bzip2 source:
+
+ This approach compiles in the bzip2 code directly. No external
+ library is needed.
+
+ Get a copy of the bzip2 source and copy the contents to the bzip2
+ directory in the Zip source tree so that bzlib.h is directly in
+ the bzip2 directory.
+
+ Use the vc6bz2 project to build Zip. This project knows of the
+ added bzip2 files.
+
+ Verify that bzip2 is enabled with the command
+
+ zip -v
+
+
+ Windows DLL (WIN32):
+
+ Nothing yet.
+
+
+ Mac OS X:
+
+ Follow the standard UNIX build procedure. Mac OS X includes bzip2
+ and the UNIX builders should find the bzip2 files in the standard
+ places. Note that the version of bzip2 on your OS may not be
+ current and you can instead specify a different library or compile
+ your own bzip2 library as noted in the Unix procedures above.
+
+
+ OS/2:
+
+ Nothing yet.
+
+
+ VMS (OpenVMS):
+
+ See [.vms]install_vms.txt for how to enable bzip2 support on VMS.
+
+
+Last updated 26 March 2007, 15 July 2007, 9 April 2008, 27 June 2008
+S. Schweda, E. Gordon
diff --git a/cmsmvs/README.CMS b/cmsmvs/README.CMS
new file mode 100644
index 0000000..a4425da
--- /dev/null
+++ b/cmsmvs/README.CMS
@@ -0,0 +1,434 @@
+Using ZIP and UNZIP on VM/CMS
+=============================
+
+
+Installing executables
+----------------------
+
+The following CMS MODULEs are available:
+ ZIP
+ ZIPNOTE
+ ZIPCLOAK
+ ZIPSPLIT
+ UNZIP
+
+In addition to these, each MODULE file also has an EXEC with the same
+name. These EXECs are front-ends to the MODULES that will attempt to
+set up the required runtime libraries before running the MODULE.
+All the EXECs are identical. Only their names are different.
+They are stored as plain text files.
+
+The CMS MODULE files have been packed using the COPYFILE command to
+allow their file format to be properly restored, since variable length
+binary files will not currently unzip properly (see below for details).
+The MODULEs are shipped with a filetype or extension of CMO (for CMS
+MODULE). Their names may vary on the distribution disk to indicate
+their level, etc.
+
+To restore them to executable MODULEs on CMS, do the following:
+ 1. Upload them to CMS with a Fixed record length with LRECL 1024.
+ Example, from a DOS or OS/2 window, type this:
+ SEND unzip.cmo A:unzip module a (RECFM F LRECL 1024
+
+ Example, using FTP from CMS, type this:
+ BINARY FIXED 1024
+ GET unzip.cmo unzip.module.a
+
+ Note: Replace "unzip.cmo" with the actual name.
+
+ 2. Use COPYFILE to unpack the file.
+ Example, in CMS type this:
+ COPYFILE UNZIP MODULE A (UNPACK REPLACE OLDDATE
+
+ 3. Repeat steps 1-2 for each of the programs.
+
+ 4. Build the ZIPINFO module by typing this:
+ COPYFILE UNZIP MODULE A ZIPINFO MODULE A (OLDDATE
+
+ 5. Upload the EXECs to CMS as text files (with ASCII-to-EBCDIC
+ translation).
+ Example, from a DOS or OS/2 window, type this:
+ SEND unzip.exc A:unzip exec a (CRLF
+
+ Example, using FTP from CMS, type this:
+ GET unzip.exc unzip.exec.a
+
+ 6. Repeat steps 4 for each of the EXECs.
+
+
+Preparing the environment
+-------------------------
+
+The executables provided were compiled with IBM C 3.1.0 and
+require the the Language Environment (LE) runtime libraries.
+
+To provide access to the runtime libraries:
+ 1. Link to the disk containing the Language Environment files,
+ if necessary.
+
+ 2. Use the command "GLOBAL LOADLIB SCEERUN"
+
+ These commands can be placed in your PROFILE EXEC.
+
+ Note: EXECs have been provided called ZIP, UNZIP, etc. that
+ issue the GLOBAL LOADLIB statement. This was done to alleviate
+ frustration of users that don't have the GLOBAL LOADLIB statement
+ in their PROFILE EXEC. These EXECs may require changing for
+ your system.
+
+ Unfortunately, there is no way, using IBM C, to produce a MODULE
+ that doesn't require a runtime library.
+
+
+Testing
+-------
+
+To test the MODULEs, just type ZIP or UNZIP. They should
+show help information on using the commands.
+
+If you see something like this:
+ DMSLIO201W The following names are undefined:
+ CEEEV003
+ DMSABE155T User abend 4093 called from 00DCD298 reason code 000003EB
+
+Then you don't have access to the proper runtime libraries, as
+described above.
+
+Here is additional information on the ZIP and UNZIP programs that
+may assist support personnel:
+ - Compiled with IBM C V3R1M0 on VM/ESA 2.2.0 with
+ CMS level 13 Service Level 702.
+
+ - Require the SCEERUN LOADLIB runtime library. This is
+ part of the Language Environment (LE).
+
+ - Linked with options RMODE ANY AMODE ANY RLDSAVE.
+
+If you continue to have trouble, report the problem to Zip-Bugs
+(see the bottom of this document).
+
+
+
+Compiling the source on VM/CMS
+------------------------------
+
+The source has been successfully compiled previously using
+C/370 2.1 and 2.2. The source has been recently compiled using
+IBM C 3.1.0 on VM/ESA 2.2.0 with CMS level 13. I don't have
+access to an MVS system so the code hasn't been tested there
+in a while.
+
+ 1. Unzip the source files required for CMS. The root-level files
+ inside the ZIP file and the files in the CMSMVS subdirectory are
+ needed. Example (use both commands):
+ unzip -aj zip23.zip -x */* -dc
+ unzip -aj zip23.zip cmsmvs/* -dc
+
+ This example unzips the files to the C-disk, while translating
+ character data and ignoring paths.
+
+ If you don't already have a working UNZIP MODULE on CMS you will
+ have to unzip the files on another system and transport them
+ to CMS. All the required files are plain text so they can
+ be transferred with ASCII-to-EBCDIC translations.
+
+ 2. Repeat step 1 with the zip file containing the UNZIP code.
+ Unzip the files to a different disk than the disk used for the ZIP
+ code.
+
+ 3. To compile the ZIP code, run the supplied CCZIP EXEC.
+ To compile the UNZIP code, run the supplied CCUNZIP EXEC.
+
+NOTE:
+Some of the ZIP and UNZIP source files have the same name. It is
+recommended that you keep the source from each on separate disks and
+move the disk you are building from ahead of the other in the search
+order.
+
+For example, you may have a 192 disk with the ZIP source code and
+a 193 disk with the UNZIP source code. To compile ZIP, access
+the 192 disk as B, then run CCZIP. This will create the following
+modules: ZIP, ZIPNOTE, ZIPSPLIT, ZIPCLOAK.
+
+To compile UNZIP, access 193 as B, then run CCUNZIP. This will create
+the following modules: UNZIP, ZIPINFO (a copy of UNZIP).
+
+
+=========================================================================
+
+
+Using ZIP/UNZIP
+---------------
+
+Documentation for the commands is in MANUAL NONAME (for ZIP) and in
+UNZIP DOC UNZIP. INFOZIP DOC describes the use of the -Z option of
+UNZIP.
+
+The rest of this section explains special notes concerning the VM/CMS
+version of ZIP and UNZIP.
+
+
+Filenames and directories
+-------------------------
+
+ 1. Specifying filenames
+
+ a. When specifying CMS files, use filename.filetype.filemode format
+ (separate the three parts of the name with a period and use no
+ spaces). Example: profile.exec.a
+
+ Unfortunately, this prevents you from using ZIP from
+ FILELIST. To unzip a zip file, however, you can type something
+ like this next to it in FILELIST:
+ unzip /n -d c
+
+ This will unzip the contents of the current file to a C-disk.
+
+ b. It is possible to use DD names with ZIP and UNZIP on CMS, though
+ it can be cumbersome. Example:
+ filedef out disk myzip zip a
+ zip dd:out file1.txt file2.txt
+
+ While you can also use a DD name for the input files, ZIP
+ currently does not correctly resolve the filename and will
+ store something like "dd:in" inside the ZIP file. A file stored
+ in this manor cannot easily be unzipped, as "dd:in" is an invalid
+ filename.
+
+ c. In places where a directory name would be used on a PC, such as
+ for the ZIP -b (work path) option or the UNZIP -d (destination
+ path) options, use a filemode letter for CMS. For example,
+ to unzip files onto a C-disk, you might type something like this:
+ unzip myzip.zip -d c
+
+ Currently, ZIP uses the A-disk for work files. When zipping
+ large files, you may want to specify a larger disk for work files.
+ This example will use a C-disk for work files.
+ zip -b C myzip.zip.c test.dat.a
+
+
+ 2. Filename conversions
+
+ a. Filemode letters are never stored into the zip file or take from
+ a zip file. Only the filename and filetype are used.
+ ZIP removes the filemode when storing the filename into the
+ zip file. UNZIP assumes "A" for the filemode unless the -d
+ option is used.
+
+ b. When unzipping, any path names are removed from the fileid
+ and the last two period-separated words are used as the
+ filename and filetype. These are truncated to a maximum of
+ eight characters, if necessary. If the filetype (extension)
+ is missing, then UNZIP uses "NONAME" for the filetype.
+ Any '(' or ')' characters are removed from the fileid.
+
+ c. All files are created in upper-case. Files in mixed-case
+ cannot currently be stored into a ZIP file.
+
+ d. Shared File System (SFS) directories are not supported.
+ Files are always accessed by fn.ft.fm. To use an SFS disk,
+ Assign it a filemode, then it can be used.
+
+
+ 3. Wildcards in file names
+
+ a. Wildcards are not supported in the zip filename. The full
+ filename of the zip file must be given (but the .zip is not
+ necessary). So, you can't do this:
+ unzip -t *.zip
+
+ b. Wildcards CAN be used with UNZIP to select (or exclude) files
+ inside a zip file. Examples:
+ unzip myzip *.c - Unzip all .c files.
+ unzip myzip *.c -x z*.c - Unzip all .c files but those
+ starting with Z.
+
+ c. Wildcards cannot currently be used to select files with ZIP.
+ So, you can't do this:
+ zip -a myzip *.exec
+
+ I expect to fix this for CMS in the future.
+
+
+ 4. File timestamps
+
+ a. The dates and times of files being zipped or unzipped are not
+ currently read or set. When a file is zipped, the timestamp
+ inside the zip file will always be the current system date and
+ time. Likewise, when unzipping, the date and time of files
+ being unzipped will always be the current system date/time.
+
+ b. Existing files are assumed to be newer than files inside a zip
+ file when using the -f freshen option of UNZIP. This will prevent
+ overwriting files that may be newer than the files inside the
+ zip file, but also effectively prevents the -f option from working.
+
+
+ 5. ASCII, EBCDIC, and binary data
+
+ Background
+ ----------
+ Most systems create data files as just a stream of bytes. Record
+ breaks happen when certain characters (new line and/or carriage
+ return characters) are encountered in the data. How to interpret
+ the data in a file is up to the user. The system must be told
+ to either notice new line characters in the data or to assume
+ that the data in the file is binary data and should be read or
+ written as-is.
+
+ CMS and MVS are record-based systems. All files are composed
+ of data records. These can be stored in fixed-length files or
+ in variable length files. With fixed-length files, each record
+ is the same length. The record breaks are implied by the
+ LRECL (logical record length) attribute associated with the file.
+ With variable-length files, each record contains the length of
+ that record. The separation of records are not part of the
+ data, but part of the file structure.
+
+ This means you can store any type of data in either type of file
+ structure without having to worry about the data being interpreted
+ as a record break. Fixed-length files may have padding at the
+ end of the file to make up a full record. Variable-length files
+ have no padding, but require extra record length data be stored
+ with the file data.
+
+ Storing fixed-length files into a zip file is simple, because all
+ the data can just be dumped into the zip file and the record
+ format (RECFM) and logical record length (LRECL) can be stored
+ in the extra data area of the zip file so they can be restored
+ when UNZIP is used.
+
+ Storing variable-length data is harder. There is no place to put
+ the record length data needed for each record of the file. This
+ data could be written to the zip file as the first two bytes of
+ each record and interpreted that way by UNZIP. That would make
+ the data unusable on systems other than CMS and MVS, though.
+
+ Currently, there isn't a solution to this problem. Each record is
+ written to the zip file and the record length information is
+ discarded. Binary data stored in variable-length files can't be put
+ into a zip file then later unzipped back into the proper records.
+ This is fine for binary data that will be read as a stream of bytes
+ but not OK where the records matter, such as with CMS MODULEs.
+
+ If the data is text (character data), there is a solution.
+ This data can be converted into ASCII when it's stored into
+ a zip file. The end of each record is now marked in the file
+ by new line characters. Another advantage of this method is
+ that the data is now accessible to non-EBCDIC systems. When
+ the data is unzipped on CMS or MVS, it is converted back into
+ EBCDIC and the records are recreated into a variable-length file.
+
+
+ So, here's what we have...
+
+ a. To store readable text data into a zip file that can be used
+ on other platforms, use the -a option with ZIP to convert the
+ data to ASCII. These files will unzip into variable-length
+ files on CMS and should not contain binary data or corruption
+ may occur.
+
+ b. Files that were zipped on an ASCII-based system will be
+ automatically translated to EBCDIC when unzipped. To prevent
+ this (to unzip binary data on CMS that was sent from an
+ ASCII-based system), use the -B option with UNZIP to force Binary
+ mode. To zip binary files on CMS, use the -B option with ZIP to
+ force Binary mode. This will prevent any data conversions from
+ taking place.
+
+ c. When using the ZIP program without specifying the "-a" or "-B"
+ option, ZIP defaults to "native" (EBCDIC) mode and tries to
+ preserve the file information (RECFM, LRECL, and BLKSIZE). So
+ when you unzip a file zipped with ZIP under CMS or MVS, UNZIP
+ restores the file info. The output will be fixed-length if the
+ original was fixed and variable-length if the original was
+ variable.
+
+ If UNZIP gives a "write error (disk full?)" message, you may be
+ trying to unzip a binary file that was zipped as a text file
+ (without using the -B option)
+
+
+ Summary
+ -------
+ Here's how to ZIP the different types of files.
+
+ RECFM F text
+ Use the -a option with ZIP to convert to ASCII for use with other
+ platforms or no options for use on EBCDIC systems only.
+
+ RECFM V text
+ Use the -a option with ZIP to convert to ASCII for use with other
+ platforms or no options for use on EBCDIC systems only.
+
+
+ RECFM F binary
+ Use the -B option with ZIP (upper-case "B").
+
+ RECFM V binary
+ Use the -B option with ZIP. Can be zipped OK but the record
+ structure is destroyed when unzipped. This is OK for data files
+ read as binary streams but not OK for files such as CMS MODULEs.
+
+
+ 6. Character Sets
+
+ If you are used to running UNZIP on systems like UNIX, DOS, OS/2 or
+ Windows, you will may have some problems with differences in the
+ character set.
+
+ There are a number of different EBCDIC code pages, like there are a
+ number of different ASCII code pages. For example, there is a US
+ EBCDIC, a German EBCDIC, and a Swedish EBCDIC. As long as you are
+ working with other people who use the same EBCDIC code page, you
+ will have no trouble. If you work with people who use ASCII, or who
+ use a different EBCDIC code page, you may need to do some
+ translation.
+
+ UNZIP translates ASCII text files to and from Open Systems EBCDIC
+ (IBM-1047), which may not be the EBCDIC that you are using. For
+ example, US EBCDIC (IBM-037) uses different character codes for
+ square brackets. In such cases, you can use the ICONV utility
+ (supplied with IBM C) to translate between your EBCDIC character set
+ and IBM-1047.
+
+ If your installation does not use IBM-1047 EBCDIC, messages from
+ UNZIP may look a little odd. For example, in a US EBCDIC
+ installation, an opening square bracket will become an i-acute and a
+ closing square bracket will become a u-grave.
+
+ The supplied ZIP and UNZIP EXECs attempt to correct this by setting
+ CMS INPUT and OUTPUT translations to adjust the display of left and
+ right brackets. You may need to change this if brackets don't
+ display correctly on your system.
+
+
+ 7. You can unzip using VM/CMS PIPELINES so unzip can be used as
+ a pipeline filter. Example:
+ 'PIPE COMMAND UNZIP -p test.zip george.test | Count Lines | Cons'
+
+
+
+
+Please report all bugs and problems to:
+ Zip-Bugs@lists.wku.edu
+
+
+-----------------------------------------------------------------------
+Original CMS/MVS port by George Petrov.
+e-mail: c888090@nlevdpsb.snads.philips.nl
+tel: +31-40-781155
+
+Philips C&P
+Eindhoven
+The Netherlands
+
+-----------------------------------------------------------------------
+Additional fixes and README re-write (4/98) by Greg Hartwig.
+e-mail: ghartwig@ix.netcom.com
+ ghartwig@vnet.ibm.com
+
+-----------------------------------------------------------------------
+Additional notes from Ian E. Gorman.
+e-mail: ian@iosphere.net
+
diff --git a/cmsmvs/README.MVS b/cmsmvs/README.MVS
new file mode 100644
index 0000000..4d451db
--- /dev/null
+++ b/cmsmvs/README.MVS
@@ -0,0 +1,92 @@
+Thank you for trying this first port of ZIP for VM/CMS and MVS!
+
+
+ Using under MVS:
+ ---------------------------
+
+1. To use the Info-ZIP's ZIP under MVS you need:
+
+ - C/370 ver 2.1 compiler or another compatible compiler supporting
+ long names for function/variable names.
+
+2. To compile the program under MVS do :
+
+ - unzip all the files from zip22.zip file. They are stored as
+ ASCII format so you have to unzip them first on PC or other
+ system that already have UNZIP, and then upload them to the
+ mainframe with ASCII to EBCDIC conversion.
+
+ - Copy all the .C files in the PDS called youruserid.ZIP.C
+
+ - Copy all the .H files in the PDS called youruserid.ZIP.H
+
+ - adjust the job ZIPMVSC.JOB to work on your size. Change my
+ userid - C888090 to yours
+
+ - execute the job ZIPMVSC to compile and link all the sources.
+
+ - maybe you have to preallocate PDS datasets named:
+ youruserid.ZIP.OBJ and youruserid.ZIP.LOAD
+
+ - execute ZIPVMC to compile and link all the sources.
+
+ - if everything is ok you will get an ZIP MODULE
+
+ - the warnings about the duplicated ASCII and EBCDIC symbols
+ are OK :-)
+
+3. Using ZIP
+
+ - Just read MANUAL
+
+ - A few exceptions concerning MVS
+
+ 3.1. if you want to make a portable zip file that is to be unzipped
+ on ASCII based systems use the -a option
+
+ 3.2. If you want to zip the input files as binary ebcdic files
+ use the -B (capital letter) option
+
+ 3.3. The date/end the time of the input files is set in the zip's
+ dir to the current system date/time
+
+ 3.4. Without specifying the "-a" or "-B" option, the ZIP program
+ defaults to "native" (EBCDIC) mode and tries to preserve the
+ file information (LRECL,BLKSIZE..)
+ So when you UNZIP a file zipped with ZIP under VM/MVS it
+ restores the file info.
+
+ There currently some problems with file with RECFM=V*
+ I don't save the length of each record yet :-)
+
+ 3.5. No wildcards are supported as input file names:
+
+ So you CAN'T use things like: zip myzip *.c
+
+ 3.6. You can use DD names for zipfilename for example:
+
+ under tso/rexx:
+
+ "alloc fi(input) da('myzip.zip')"
+ "zip dd:input file1.txt file2.txt ..."
+
+ under Batch:
+
+ //MYZIP JOB (account)
+ //STEP1 EXEC PGM=ZIP,PARM='dd:input file1.txt file2.txt'
+ //STEPLIB DD DSN=userid.UNZIP.LOAD,DISP=SHR
+ //INPUT DD DSN=userid.MYZIP.ZIP,DISP=NEW,
+ // SPACE=(15000,(15000,10000),RLSE),
+ // DCB=(LRECL=80,RECFM=F)
+ //SYSPRINT DD SYSOUT=*
+
+
+Please report all bugs and problems to :
+ zip-bugs@lists.wku.edu
+
+That's all for now.
+
+Have fun!
+
+
+George Petrov
diff --git a/cmsmvs/README.MVS.LE b/cmsmvs/README.MVS.LE
new file mode 100644
index 0000000..f7dcb8a
--- /dev/null
+++ b/cmsmvs/README.MVS.LE
@@ -0,0 +1,286 @@
+Notes on Zip under MVS Language Environment (LE).
+
+First see README.MVS. This note describes just one beta test on OS/390
+V2R5 using IBM's C compiler (5647A01), V2R4. The major difference is
+the use of LE on the beta site, together with some MVS native mode
+fixes. Changes have not been tested on CMS.
+
+Some of the notes are to clarify things that were not clear from the
+MANUAL or README.MVS.
+
+1. By default, IBM C generates the same csect name for each input
+ source. The prelink stage does not rename them and the linkage
+ editor throws away all but the first occurrence of each duplicate.
+ Oops, my code just disappeared :(.
+
+ To get around this "feature", compile with the CSECT option to
+ force sensible names on the code and data sections of each csect.
+ The name of the static data csect defaults to the source name in
+ lower case, the code csect defaults to the source name in upper
+ case. These csect names still have to be unique, they cannot be
+ the same as function names. Of course, several csects have a
+ function which is the same name as the source in lower case, not
+ exactly an unusual occurrence. Therefore to make the csect name
+ unique, some of the sources have
+
+ #ifdef MVS
+ # pragma csect(STATIC,xxxx_s)
+ #endif
+
+ Where xxxx is an abbreviation of the source name. There has to be
+ a better way!
+
+2. The prelink step always gets cond code 4. It complains about
+ unresolved references, ignore it unless the linker also complains.
+ Prelink also complains about duplicate @@PPA2 sections and so does
+ the linker, but it seems to do no harm. Compile and link steps
+ should get 0, just prelink gets 4. See JCL at the bottom.
+
+3. Under MVS native mode (not Open Edition), tmpnam() returns a quoted
+ name of 5 qualifiers. The first is a HLQ chosen according to the
+ MVS LE algorithm (see below), the other qualifiers are time stamps.
+ If running on MVS and tmpnam() returns a quoted name with at leat
+ one '.', it is only safe to let the user change the high level
+ qualifier. Therefore -b insists on a single qualifier without '.'
+ in the MVS native environment.
+
+4. In Open Edition (OE) mode, the manual says that tmpnam() returns a
+ fully qualified name in directory TMPDIR or /tmp if TMPDIR is not
+ set. There is no point in zip trying to override that name so -b
+ is ignored in MVS OE mode (untested). The user should specify
+ environment variable TMPDIR instead.
+
+5. The MVS LE algorithm for choosing the high level qualifier for
+ native filenames is interesting, as in "May you live in interesting
+ times". The HLQ varies according to the environment the program is
+ running in, sometimes it is userid, sometimes it is TSO prefix.
+ See OS/390 C/C++ Programming Guide, Using a Data Set Name,
+ somewhere around section 2.9.
+
+ If in doubt, use fully qualified and quoted names. Instead of
+ archive.zip, use 'prefix.archive.zip'. For input files, instead of
+ filename, use 'prefix.filename'. For PARM= in JCL, double up the
+ quotes. You even have to quote filenames in stdin.
+
+6. If your PARM includes any '/', make sure the PARM starts with '/'.
+ LE assumes anything before the first '/' is LE run time parameters.
+ It does no harm to always code a leading '/' for LE parms.
+
+7. JCL limits a PARM= to 100 characters total with approx. 65 on a
+ single line. Alas the syntax for continuing PARM= always embeds an
+ extra ',' somewhere in the parameters that the program finally
+ gets. No workaround, limit your PARM to a single line. With the
+ extra quotes around filenames, that does not leave much room. In
+ most cases, you will have to use '-@' to read the list of filenames
+ from SYSIN (stdin), it will not fit on a single PARM line.
+
+8. Filenames can be dataset names or you can refer to a ddname with
+ 'DD:name', case insensitive for external files, case sensitive for
+ OE files. You can even specify 'dd:name(mem)'. No wildcards, to
+ zip a complete pds you have to specify each member individually.
+ Directory recursion in OE does not appear to work at the moment.
+
+9. Zip attempts to map MVS filenames to Unix style names. It did not
+ work correctly for quoted names, fixed. Although you can pick up
+ an external (non-OE) file with a name using any case, be aware that
+ the mapping to a Unix style name faithfully follows the case you
+ supply.
+
+10. The archive file was being created with recfm=V and lrecl=32760.
+ 32760 is not valid for recfm=V under MVS, I originally changed it
+ to lrecl=32756. Then zip broke trying to fseek() over a record
+ boundary, I do not know whether this was a zip or LE bug. Trial
+ and error showed that recfm=U with byteseek seems to work on MVS.
+ No BDW or RDW, just a byte stream. The blocksize is always 6144.
+
+ NOTE: This is an incompatible change from the previous beta,
+ archive files used to be recfm=V. That should not matter
+ because we just transfer the data, ignoring BDW and RDW
+ anyway.
+
+11. Zip used to complain about preallocated but empty archives, wrong
+ length records, no signature etc. The usual IBM/360 problem of no
+ end of file marker in a new, unopened dataset. Fixed, see routine
+ readzipfile in zipfile.c for the gory details. PARM= works fine.
+
+12. Several source files have records that are more than 80 bytes long.
+ It works if you transfer to mainframe datasets with a larger lrecl,
+ I used recfm=fb,lrecl=120 for the .C and .H files. To compile with
+ anything longer than 72 bytes, you need MVS C options NOMARGINS and
+ NOSEQUENCE (NOMAR,NOSEQ).
+
+13. cmsmvs was still using zname instead of name for open. Fixed.
+
+14. zip has to jump through a lot of hoops to see if an existing
+ zipfile actually contains data. A side effect of this is that
+ creating a zipfile with the RLSE parameter is a waste of time.
+
+Keith Owens <kaos@ocs.com.au>. Not a maintainer, just a beta tester.
+Mon Sep 14 19:31:30 EST 1998
+
+
+Sample JCL to compile Zip under MVS LE. You might need a large region,
+I used REGION=128M on the job card. Also watch the output lines,
+75,000 with OPT(2), 100,000+ with OPT(2) replaced with DEF(DEBUG). You
+need to allocate prefix.ZIP.C.OBJ (recfm=FB, lrecl=80) and
+prefix.ZIP.LOAD (recfm=U, blksize is site defined).
+
+//CBC JCLLIB ORDER=CBC.SCBCPRC
+//ZIP EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(ZIP)',
+// OUTFILE='prefix.ZIP.C.OBJ(ZIP),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CRYPT EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(CRYPT)',
+// OUTFILE='prefix.ZIP.C.OBJ(CRYPT),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//TTYIO EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(TTYIO)',
+// OUTFILE='prefix.ZIP.C.OBJ(TTYIO),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//TREES EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(TREES)',
+// OUTFILE='prefix.ZIP.C.OBJ(TREES),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//DEFLATE EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(DEFLATE)',
+// OUTFILE='prefix.ZIP.C.OBJ(DEFLATE),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//FILEIO EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(FILEIO)',
+// OUTFILE='prefix.ZIP.C.OBJ(FILEIO),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//GLOBALS EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(GLOBALS)',
+// OUTFILE='prefix.ZIP.C.OBJ(GLOBALS),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//UTIL EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(UTIL)',
+// OUTFILE='prefix.ZIP.C.OBJ(UTIL),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CRC32 EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(CRC32)',
+// OUTFILE='prefix.ZIP.C.OBJ(CRC32),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CRCTAB EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(CRCTAB)',
+// OUTFILE='prefix.ZIP.C.OBJ(CRCTAB),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//ZIPFILE EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(ZIPFILE)',
+// OUTFILE='prefix.ZIP.C.OBJ(ZIPFILE),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//ZIPUP EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(ZIPUP)',
+// OUTFILE='prefix.ZIP.C.OBJ(ZIPUP),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//CMSMVS EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(CMSMVS)',
+// OUTFILE='prefix.ZIP.C.OBJ(CMSMVS),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//MVS EXEC EDCC,COND=(0,NE),CREGSIZ='4M',
+// INFILE='prefix.ZIP.C(MVS)',
+// OUTFILE='prefix.ZIP.C.OBJ(MVS),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE',
+// CPARM2='OPT(2),DEF(MVS),NOMAR,NOSEQ,CSECT'
+//COMPILE.USERLIB DD DSN=prefix.ZIP.H,DISP=SHR
+//PLINK EXEC PROC=EDCPL,
+// OUTFILE='prefix.ZIP.LOAD(ZIP),DISP=SHR',
+// PREGSIZ=6M,
+// PPARM='NONCAL,MAP,MEMORY',
+// LPARM='LIST,MAP,XREF'
+//PLKED.SYSIN DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(ZIP)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(CRYPT)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(TREES)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(DEFLATE)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(FILEIO)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(GLOBALS)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(UTIL)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(CRC32)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(CRCTAB)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(ZIPFILE)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(ZIPUP)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(MVS)
+// DD DISP=SHR,DSN=prefix.ZIP.C.OBJ(CMSMVS)
+//LKED.SYSLIB DD DISP=SHR,DSN=CEE.SCEELKED
+//SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(2,2))
+//
+
+Sample JCL to zip the mainframe .C and .H files as ASCII (-a). Delete
+any existing archive first, point the temporary file at a particular
+prefix (-b), use 'prefix.ARCHIVE.ZIP' for the archive file, read the
+list of files to zip from stdin (SYSIN).
+
+//DELETE EXEC PGM=IDCAMS
+//SYSPRINT DD SYSOUT=*
+//SYSIN DD *
+ DELETE prefix.ARCHIVE.ZIP
+ SET MAXCC = 0
+//ZIP EXEC PGM=ZIP,
+// PARM='/-a -v -b temppref ''prefix.ARCHIVE.ZIP'' -@'
+//STEPLIB DD DSN=prefix.ZIP.LOAD,DISP=SHR
+//SYSPRINT DD SYSOUT=*
+//SYSOUT DD SYSOUT=*
+//CEEDUMP DD SYSOUT=*
+//ZIPC DD DISP=SHR,DSN=prefix.ZIP.C
+//ZIPH DD DISP=SHR,DSN=prefix.ZIP.H
+//SYSIN DD *
+dd:zipc(api)
+dd:zipc(cms)
+dd:zipc(cmsmvs)
+dd:zipc(crctab)
+dd:zipc(crc32)
+dd:zipc(crypt)
+dd:zipc(deflate)
+dd:zipc(fileio)
+dd:zipc(globals)
+dd:zipc(mktime)
+dd:zipc(mvs)
+dd:zipc(trees)
+dd:zipc(ttyio)
+dd:zipc(util)
+dd:zipc(zip)
+dd:zipc(zipcloak)
+dd:zipc(zipfile)
+dd:zipc(zipnote)
+dd:zipc(zipsplit)
+dd:zipc(zipup)
+dd:ziph(api)
+dd:ziph(cmsmvs)
+dd:ziph(crypt)
+dd:ziph(cstat)
+dd:ziph(ebcdic)
+dd:ziph(mvs)
+dd:ziph(revision)
+dd:ziph(stat)
+dd:ziph(tailor)
+dd:ziph(ttyio)
+dd:ziph(zip)
+dd:ziph(ziperr)
+dd:ziph(zipup)
diff --git a/cmsmvs/cczip.exec b/cmsmvs/cczip.exec
new file mode 100644
index 0000000..86edb59
--- /dev/null
+++ b/cmsmvs/cczip.exec
@@ -0,0 +1,123 @@
+/* CCZIP EXEC Compile zip for VM/CMS */
+/* Author: George Petrov, 11 Apr 1995 (VMCOMPIL EXEC) */
+/* Modified for IBM C V3R1 by Ian E. Gorman, 2 Nov 1998
+ Facilities for compiling and testing were provided by
+ OmniMark Technologies Corporation, Ottawa, Canada
+*/
+Address Command
+Signal On Error
+
+/* Allow longnames, compile re-entrant code.
+ globals.c and cmsmvs.c require EXTENDED features */
+CCopts = 'LONGNAME RENT LANGLVL(EXTENDED) NOEXECOPS'
+
+/* ZIP options -- VM_CMS, REENTRANT */
+CCopts = CCopts 'DEFINE(VM_CMS,REENTRANT)'
+
+/* Link the load module to run in more or less than 16MB memory */
+LINKopts = 'AMODE ANY RMODE ANY RLDSAVE'
+
+/* resources needed to build */
+'GLOBAL TXTLIB SCEELKED CMSLIB'
+'GLOBAL LOADLIB SCEERUN'
+
+/* produce the TEXT (object) files */
+linklist=''
+modname='ZIP'
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIP'
+Call Compile 'CRC32'
+Call Compile 'CRYPT'
+Call Compile 'DEFLATE'
+Call Compile 'FILEIO'
+Call Compile 'GLOBALS'
+Call Compile 'TREES'
+Call Compile 'TTYIO'
+Call Compile 'UTIL'
+Call Compile 'ZIPUP'
+Call Compile 'ZIPFILE'
+Call Compile 'CMSMVS'
+Call Compile 'CMS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+
+
+/*---------------------------------------------------------------------*/
+/* Build utility programs */
+/*---------------------------------------------------------------------*/
+CCopts = CCopts 'DEFINE(UTIL)'
+
+
+linklist=''
+modname='ZIPNOTE'
+Say
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIPNOTE'
+Call Compile 'ZIPFILE'
+Call Compile 'FILEIO'
+Call Compile 'UTIL'
+Call Compile 'GLOBALS'
+Call Compile 'CMSMVS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+
+
+linklist=''
+modname='ZIPSPLIT'
+Say
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIPSPLIT'
+Call Compile 'ZIPFILE'
+Call Compile 'FILEIO'
+Call Compile 'UTIL'
+Call Compile 'GLOBALS'
+Call Compile 'CMSMVS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+
+
+linklist=''
+modname='ZIPCLOAK'
+Say
+Say 'Building' modname 'MODULE...'
+Call Compile 'ZIPCLOAK'
+Call Compile 'ZIPFILE'
+Call Compile 'FILEIO'
+Call Compile 'UTIL'
+Call Compile 'GLOBALS'
+Call Compile 'CRC32'
+Call Compile 'CRYPT'
+Call Compile 'TTYIO'
+Call Compile 'CMSMVS'
+
+Say 'Linking...'
+'EXEC CMOD' linklist '(MODNAME' modname LINKopts
+Say modname 'built successfully.'
+Say 'Done.'
+
+Exit rc
+
+
+
+error:
+ Say 'Error' rc 'during compilation!'
+ Say 'Error in line' sigl':'
+ Say ' 'Sourceline(sigl)
+ Exit rc
+
+
+
+Compile: Procedure Expose CCopts LINKopts linklist
+ Parse arg filename filetype filemode .
+ If filetype='' Then filetype='C'
+ linklist = linklist filename
+
+ Say 'Compiling' filename filetype filemode '...'
+ 'EXEC CC' filename filetype filemode '('CCopts
+ Return rc
diff --git a/cmsmvs/cms.c b/cmsmvs/cms.c
new file mode 100644
index 0000000..e69f5cb
--- /dev/null
+++ b/cmsmvs/cms.c
@@ -0,0 +1,34 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * VM/CMS specific things.
+ */
+
+#include "zip.h"
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ FILE *stream;
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else {
+ if ((stream = fopen(n, "r")) != (FILE *)NULL)
+ {
+ fclose(stream);
+ return newname(n, 0, caseflag);
+ }
+ else return ZE_MISS;
+ }
+ return ZE_OK;
+}
diff --git a/cmsmvs/cmsmvs.c b/cmsmvs/cmsmvs.c
new file mode 100644
index 0000000..9c56de7
--- /dev/null
+++ b/cmsmvs/cmsmvs.c
@@ -0,0 +1,442 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * routines common to VM/CMS and MVS
+ */
+
+#include "zip.h"
+
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+
+#ifndef MVS /* MVS has perfectly good definitions of the following */
+int stat(const char *path, struct stat *buf)
+{
+ if ((buf->fp = fopen(path, "r")) != NULL) {
+ fldata_t fdata;
+ if (fldata( buf->fp, buf->fname, &fdata ) == 0) {
+ buf->st_dev = fdata.__device;
+ buf->st_mode = *(short *)(&fdata);
+ }
+ strcpy( buf->fname, path );
+ fclose(buf->fp);
+ }
+ return (buf->fp != NULL ? 0 : 1);
+}
+#endif /* MVS */
+
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef USE_ZIPMAIN
+int main OF((void));
+#endif
+
+int utime OF((char *, ztimbuf *));
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+#ifndef MVS /* MVS has perfectly good definitions of the following */
+int fstat(int fd, struct stat *buf)
+{
+ fldata_t fdata;
+
+ if ((fd != -1) && (fldata( (FILE *)fd, buf->fname, &fdata ) == 0)) {
+ buf->st_dev = fdata.__device;
+ buf->st_mode = *(short *)(&fdata);
+ buf->fp = (FILE *)fd;
+ return 0;
+ }
+ return -1;
+}
+#endif /* MVS */
+
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+ char mem[10] = ""; /* member name */
+ char ext[10] = ""; /* extension name */
+
+ dosflag = dosify; /* default for non-DOS non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ for (t = x; *t == '/'; t++)
+ ;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+#ifdef MVS
+ /* strip quotes from name, non-OE format */
+ if (*n == '\'' && (t = strrchr(n, '\'')) != n) {
+ if (!*(t+1)) {
+ /* yes, it is a quoted name */
+ int l = strlen(n) - 2;
+ memmove(n, n+1, l);
+ *(n+l) = '\0';
+ }
+ }
+ /* Change member names to fn.ext */
+ if (t = strrchr(n, '(')) {
+ *t = '\0';
+ strcpy(mem,t+1); /* Save member name */
+ if (t = strchr(mem, ')')) *t = '\0'; /* Set end of mbr */
+ /* Save extension */
+ if (t = strrchr(n, '.')) t++;
+ else t = n;
+ strcpy(ext,t);
+ /* Build name as "member.ext" */
+ strcpy(t,mem);
+ strcat(t,".");
+ strcat(t,ext);
+ }
+
+ /* Change all but the last '.' to '/' */
+ if (t = strrchr(n, '.')) {
+ while (--t > n)
+ if (*t == '.')
+ *t = '/';
+ }
+#else
+ /* On CMS, remove the filemode (all past 2nd '.') */
+ if (t = strchr(n, '.'))
+ if (t = strchr(t+1, '.'))
+ *t = '\0';
+ t = n;
+#endif
+
+ strcpy(n, t);
+
+ if (isdir == 42) return n; /* avoid warning on unused variable */
+
+ if (dosify)
+ msname(n); /* msname() needs string in native charset */
+
+ strtoasc(n, n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strtoebc(x, n);
+ return x;
+}
+
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ ztimbuf u; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u.actime and u.modtime */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ utime(f, &u);
+}
+
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+{
+ FILE *stream;
+ time_t ltime;
+
+ if (strcmp(f, "-") != 0) { /* if not compressing stdin */
+ Trace((mesg, "opening file '%s' with '%s'\n", f, FOPR));
+ if ((stream = fopen(f, FOPR)) == (FILE *)NULL) {
+ return 0;
+ } else {
+ if (n != NULL) {
+ /* With byteseek, this will work */
+ fseek(stream, 0L, SEEK_END);
+ *n = ftell(stream);
+ Trace((mesg, "file size = %lu\n", *((ulg *)n)));
+ }
+ fclose(stream);
+ }
+ }
+ else {
+ /* Reading from stdin */
+ if (n != NULL) {
+ *n = -1L;
+ }
+ }
+
+ /* Return current time for all the times -- for now */
+ time(&ltime);
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = ltime;
+
+ /* Set attributes (always a file) */
+ if (a != NULL)
+ *a = 0;
+
+ return unix2dostime(&ltime);
+}
+
+
+
+int set_extra_field(z, z_utim)
+struct zlist far *z;
+iztimes *z_utim;
+/* create extra field and change z->att if desired */
+{
+ fldata_t fdata;
+ FILE *stream;
+ char *eb_ptr;
+#ifdef USE_EF_UT_TIME
+ extent ef_l_len = (EB_HEADSIZE+EB_UT_LEN(1));
+#else /* !USE_EF_UT_TIME */
+ extent ef_l_len = 0;
+#endif /* ?USE_EF_UT_TIME */
+ int set_cmsmvs_eb = 0;
+
+/*translate_eol = 0;*/
+ if (aflag == ASCII) {
+ z->att = ASCII;
+ } else {
+ if (bflag)
+ z->att = BINARY;
+ else
+ z->att = __EBCDIC;
+ ef_l_len += sizeof(fdata)+EB_HEADSIZE;
+ set_cmsmvs_eb = 1;
+ }
+
+ if (ef_l_len > 0) {
+ z->extra = (char *)malloc(ef_l_len);
+ if (z->extra == NULL) {
+ printf("\nFLDATA : Unable to allocate memory !\n");
+ return ZE_MEM;
+ }
+ z->cext = z->ext = ef_l_len;
+ eb_ptr = z->cextra = z->extra;
+
+ if (set_cmsmvs_eb) {
+ if (bflag)
+/*** stream = fopen(z->zname,"rb,type=record"); $RGH$ ***/
+ stream = fopen(z->name,"rb");
+ else
+ stream = fopen(z->name,"r");
+ if (stream == NULL) {
+ printf("\nFLDATA : Could not open file : %s !\n",z->name);
+ printf("Error %d: '%s'\n", errno, strerror(errno));
+ return ZE_NONE;
+ }
+
+ fldata(stream,z->name,&fdata);
+ /*put the system ID */
+#ifdef VM_CMS
+ *(eb_ptr) = EF_VMCMS & 0xFF;
+ *(eb_ptr+1) = EF_VMCMS >> 8;
+#else
+ *(eb_ptr) = EF_MVS & 0xFF;
+ *(eb_ptr+1) = EF_MVS >> 8;
+#endif
+ *(eb_ptr+2) = sizeof(fdata) & 0xFF;
+ *(eb_ptr+3) = sizeof(fdata) >> 8;
+
+ memcpy(eb_ptr+EB_HEADSIZE,&fdata,sizeof(fdata));
+ fclose(stream);
+#ifdef USE_EF_UT_TIME
+ eb_ptr += (sizeof(fdata)+EB_HEADSIZE);
+#endif /* USE_EF_UT_TIME */
+ }
+#ifdef USE_EF_UT_TIME
+ eb_ptr[0] = 0x55; /* ascii[(unsigned)('U')] */
+ eb_ptr[1] = 0x54; /* ascii[(unsigned)('T')] */
+ eb_ptr[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ eb_ptr[3] = 0;
+ eb_ptr[4] = EB_UT_FL_MTIME;
+ eb_ptr[5] = (char)(z_utim->mtime);
+ eb_ptr[6] = (char)(z_utim->mtime >> 8);
+ eb_ptr[7] = (char)(z_utim->mtime >> 16);
+ eb_ptr[8] = (char)(z_utim->mtime >> 24);
+#endif /* USE_EF_UT_TIME */
+ }
+
+ return ZE_OK;
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ return 0;
+}
+
+#ifdef USE_ZIPMAIN
+/* This function is called as main() to parse arguments */
+/* into argc and argv. This is required for stand-alone */
+/* execution. This calls the "real" main() when done. */
+
+int main(void)
+ {
+ int argc=0;
+ char *argv[50];
+
+ int iArgLen;
+ char argstr[256];
+ char **pEPLIST, *pCmdStart, *pArgStart, *pArgEnd;
+
+ /* Get address of extended parameter list from S/370 Register 0 */
+ pEPLIST = (char **)__xregs(0);
+
+ /* Null-terminate the argument string */
+ pCmdStart = *(pEPLIST+0);
+ pArgStart = *(pEPLIST+1);
+ pArgEnd = *(pEPLIST+2);
+ iArgLen = pArgEnd - pCmdStart + 1;
+
+ /* Make a copy of the command string */
+ memcpy(argstr, pCmdStart, iArgLen);
+ argstr[iArgLen] = '\0'; /* Null-terminate */
+
+ /* Store first token (cmd) */
+ argv[argc++] = strtok(argstr, " ");
+
+ /* Store the rest (args) */
+ while (argv[argc-1])
+ argv[argc++] = strtok(NULL, " ");
+ argc--; /* Back off last NULL entry */
+
+ /* Call "real" main() function */
+ return zipmain(argc, argv);
+
+}
+#endif /* USE_ZIPMAIN */
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ char liblvlmsg [50+1];
+ char *compiler = "?";
+ char *platform = "?";
+ char complevel[64];
+
+ /* Map the runtime library level information */
+ union {
+ unsigned int iVRM;
+ struct {
+ unsigned int pd:4; /* Product designation */
+ unsigned int vv:4; /* Version */
+ unsigned int rr:8; /* Release */
+ unsigned int mm:16; /* Modification level */
+ } xVRM;
+ } VRM;
+
+
+ /* Break down the runtime library level */
+ VRM.iVRM = __librel();
+ sprintf(liblvlmsg, "Using runtime library level %s V%dR%dM%d",
+ (VRM.xVRM.pd==1 ? "LE" : "CE"),
+ VRM.xVRM.vv, VRM.xVRM.rr, VRM.xVRM.mm);
+ /* Note: LE = Language Environment, CE = Common Env. (C/370). */
+ /* This refers ONLY to the current runtimes, not the compiler. */
+
+
+#ifdef VM_CMS
+ platform = "VM/CMS";
+ #ifdef __IBMC__
+ compiler = "IBM C";
+ #else
+ compiler = "C/370";
+ #endif
+#endif
+
+#ifdef MVS
+ platform = "MVS";
+ #ifdef __IBMC__
+ compiler = "IBM C/C++";
+ #else
+ compiler = "C/370";
+ #endif
+#endif
+
+#ifdef __COMPILER_VER__
+ VRM.iVRM = __COMPILER_VER__;
+ sprintf(complevel," V%dR%dM%d",
+ VRM.xVRM.vv, VRM.xVRM.rr, VRM.xVRM.mm);
+#else
+#ifdef __IBMC__
+ sprintf(complevel," V%dR%d", __IBMC__ / 100, (__IBMC__ % 100)/10);
+#else
+ complevel[0] = '\0';
+#endif
+#endif
+
+
+ printf("Compiled with %s%s for %s%s%s.\n\n",
+
+ /* Add compiler name and level */
+ compiler, complevel,
+
+ /* Add platform */
+ platform,
+
+ /* Add timestamp */
+#ifdef __DATE__
+ " on " __DATE__
+#ifdef __TIME__
+ " at " __TIME__
+#endif
+#endif
+ ".\n",
+ liblvlmsg
+ );
+} /* end function version_local() */
diff --git a/cmsmvs/cmsmvs.h b/cmsmvs/cmsmvs.h
new file mode 100644
index 0000000..e2adb31
--- /dev/null
+++ b/cmsmvs/cmsmvs.h
@@ -0,0 +1,123 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* Include file for VM/CMS and MVS */
+
+/* This is normally named osdep.h on most systems. Since CMS */
+/* generally doesn't support directories, it's been given a unique */
+/* name to avoid confusion. */
+
+
+#ifndef __cmsmvs_h /* prevent multiple inclusions */
+#define __cmsmvs_h
+
+#ifdef MVS
+# define _POSIX_SOURCE /* tell MVS we want full definitions */
+# include <features.h>
+#endif /* MVS */
+
+#include <time.h> /* the usual non-BSD time functions */
+/* cstat.h is not required for MVS and actually gets in the way. Is it
+ * needed for CMS?
+ */
+#ifdef MVS
+# include <sys/stat.h>
+# include <sys/modes.h>
+#else /* !MVS */
+# include "cstat.h"
+#endif
+
+
+/* Newer compiler version defines something for us */
+#if defined(__VM__) && !defined(VM_CMS)
+# define VM_CMS
+#endif
+
+#define CMS_MVS
+#define EBCDIC
+
+#ifndef MVS /* MVS has perfectly good definitions for the following */
+# define NO_UNISTD_H
+# define NO_FCNTL_H
+#endif /*MVS */
+
+/* If we're generating a stand-alone CMS module, patch in */
+/* a new main() function before the real main() for arg parsing. */
+#ifdef CMS_STAND_ALONE
+# define USE_ZIPMAIN
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#define PASSWD_FROM_STDIN
+ /* Kludge until we know how to open a non-echo tty channel */
+
+/* definition for ZIP */
+#define getch() getc(stdin)
+#define MAXPATHLEN 128
+#define NO_RMDIR
+#define NO_MKTEMP
+#define USE_CASE_MAP
+#define isatty(t) 1
+
+#ifndef MVS /* MVS has perfectly good definitions for the following */
+# define fileno(x) (char *)(x)
+# define fdopen fopen
+# define unlink remove
+# define link rename
+# define utime(f,t)
+#endif /*MVS */
+#ifdef ZCRYPT_INTERNAL
+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as seed pattern */
+#endif
+
+#ifdef MVS
+# if defined(__CRC32_C)
+# pragma csect(STATIC,"crc32_s")
+# elif defined(__DEFLATE_C)
+# pragma csect(STATIC,"deflat_s")
+# elif defined(__ZIPFILE_C)
+# pragma csect(STATIC,"zipfil_s")
+# elif defined(__ZIPUP_C)
+# pragma csect(STATIC,"zipup_s")
+# endif
+#endif /* MVS */
+
+/* end defines for ZIP */
+
+
+
+#if 0 /*$RGH$*/
+/* RECFM=F, LRECL=1 works for sure */
+#define FOPR "rb,recfm=fb"
+#define FOPM "r+"
+#define FOPW "wb,recfm=fb,lrecl=1"
+#define FOPWT "w"
+#endif
+
+/* Try allowing ZIP files to be RECFM=V with "byteseek" for CMS, recfm=U for MVS */
+#define FOPR "rb,byteseek"
+#define FOPM "r+,byteseek"
+#ifdef MVS
+ #define FOPW "wb,recfm=u,byteseek"
+#else /* !MVS */
+ #define FOPW "wb,recfm=v,lrecl=32760,byteseek"
+#endif /* MVS */
+
+#if 0
+#define FOPW_TMP "w,byteseek"
+#else
+#define FOPW_TMP "w,type=memory(hiperspace)"
+#endif
+
+#define CBSZ 0x40000
+#define ZBSZ 0x40000
+
+#endif /* !__cmsmvs_h */
diff --git a/cmsmvs/cstat.h b/cmsmvs/cstat.h
new file mode 100644
index 0000000..f02a5c3
--- /dev/null
+++ b/cmsmvs/cstat.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* cstat.h
+
+ Definitions used for file status functions
+
+*/
+
+#ifndef __STAT_H
+#define __STAT_H
+
+#include <stdio.h>
+
+#define S_IFMT 0xF000 /* file type mask */
+#define S_IFDIR 0x4000 /* directory */
+#define S_IFIFO 0x1000 /* FIFO special */
+#define S_IFCHR 0x2000 /* character special */
+#define S_IFBLK 0x3000 /* block special */
+#define S_IFREG 0x8000 /* or just 0x0000, regular */
+#define S_IREAD 0x0100 /* owner may read */
+#define S_IWRITE 0x0080 /* owner may write */
+#define S_IEXEC 0x0040 /* owner may execute <directory search> */
+
+struct stat
+{
+ short st_dev; /* Drive number of disk containing the */
+ /* file or file handle if the file is */
+ /* on device */
+ short st_ino; /* Not meaningfull for VM/CMS */
+ short st_mode; /* Bit mask giving information about */
+ /* the file's mode */
+ short st_nlink; /* Set to the integer constant 1 */
+ int st_uid; /* Not meaningfull for VM/CMS */
+ int st_gid; /* Not meaningfull for VM/CMS */
+ short st_rdev; /* Same as st_dev */
+ long st_size; /* Size of the file in bytes */
+ long st_atime; /* Most recent access */
+ long st_mtime; /* Same as st_atime */
+ long st_ctime; /* Same as st_atime */
+ FILE *fp;
+ char fname[FILENAME_MAX];
+};
+
+int stat(const char *path, struct stat *sb);
+int fstat(int fd, struct stat *sb);
+
+#endif /* __STAT_H */
diff --git a/cmsmvs/mc.exec b/cmsmvs/mc.exec
new file mode 100644
index 0000000..ca22a18
--- /dev/null
+++ b/cmsmvs/mc.exec
@@ -0,0 +1,95 @@
+/* MAKECPIP EXEC Make program to build a C/370 module */
+/* Author: George Petrov, 29 Sep 1994 */
+
+arg fn . '(' cparms /* Filter name */
+'pipe (end ?) < 'fn' makefile', /* get all source files from */
+ '| frlab GLOBALS:'||,
+ '| drop',
+ '| strip',
+ '| var globals'
+cparms = cparms globals
+say ''
+say 'Compile options : 'cparms
+say ''
+if pos('REB',cparms) > 0 then do
+parse var cparms cp1 'REB' . ' ' cp2 /* REBuild options specified ? */
+cparms = cp1||cp2
+pipe1=,
+'pipe (end ?) < 'fn' makefile', /* get all source files from */
+ '| nfind *'||, /* the makefile and compile */
+ '| frlab TEXT:'||, /* only the those who are */
+ '| r: tolab MODULE:'||, /* changed or never compiled */
+ '| drop',
+ '| o: fanout',
+ '| chop before str /(/',
+ '| statew',
+ '| c: fanout', /* compiled */
+ '| specs /Compiling / 1 w1-3 n / .../ n',
+ '| cons'
+end
+else do
+pipe1=,
+'pipe (end ?) < 'fn' makefile', /* get all source files from */
+ '| nfind *'||, /* the makefile and compile */
+ '| frlab TEXT:'||, /* only the those who are */
+ '| r: tolab MODULE:'||, /* changed or never compiled */
+ '| drop',
+ '| o: fanout',
+ '| specs w1 1 /C/ nw w3 nw write w1 1 /TEXT A/ nw',
+ '| chop before str /(/',
+ '| statew',
+ '| change (57 66) / /0/',
+ '| sort 1.8 d', /* sort the date and time */
+ '| uniq 1-17 singles', /* if the first is a source */
+ '| sort 1.8 d 64.2 d 57.2 d 60.2 d 66.8 d', /* sort the date */
+ '| uniq 1-8 first', /* if the first is a source */
+ '| locate 9.8 /C /', /* program then it has to be */
+ '| c: fanout', /* compiled */
+ '| specs /Compiling / 1 w1-3 n / .../ n',
+ '| cons'
+end
+pipe2= '?',
+ 'r:',
+ '| drop',
+ '| specs w1 1', /* save the module name in var */
+ '| var module',
+ '?',
+ 'o:',
+ '| specs w1 1',
+ '| join * / /',
+ '| var texts', /* save all the text file names */
+ '?', /* for later include */
+ 'c:',
+ '| specs /CC / 1 w1-3 n /(NOTERM 'cparms'/ nw', /* compile! */
+ '| err: cms | cons',
+ '?',
+ 'err:',
+ '| strip both',
+ '| nfind 0'||,
+ '| var err',
+ '| specs /----> Errors found! RC=/ 1 1-* n',
+ '| cons'
+/* '| g: gate'*/
+pipe1 pipe2
+say ''
+if symbol('err') = 'VAR' & err ^= 0 then do
+ say 'Errors found in source files - link aborted! RC = 'err
+ exit err
+end
+say 'Generating module 'module
+'pipe cms cmod' fn texts' DMSCSL | > 'fn' LINK A'
+'set cmstype ht'
+'state 'fn' LINK A'
+rcc = rc
+'set cmstype rt'
+if rcc = 0 then do
+ say ''
+ say 'ERRORS discovered during linking!'
+ say 'See: 'fn' LINK A for more info'
+end
+exit rc
+error:
+say 'Error in REXX detected!'
+Say 'Syntax error on line' Sigl':' Sourceline(Sigl)
+Say 'Error was:' Errortext(RC)
+return rc
diff --git a/cmsmvs/mvs.c b/cmsmvs/mvs.c
new file mode 100644
index 0000000..d7f7437
--- /dev/null
+++ b/cmsmvs/mvs.c
@@ -0,0 +1,221 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * MVS specific things
+ */
+#include "zip.h"
+#include "mvs.h"
+#include <errno.h>
+
+static int gen_node( DIR *dirp, RECORD *recptr )
+{
+ char *ptr, *name, ttr[TTRLEN];
+ int skip, count = 2;
+ unsigned int info_byte, alias, ttrn;
+ struct dirent *new;
+
+ ptr = recptr->rest;
+ while (count < recptr->count) {
+ if (!memcmp( ptr, endmark, NAMELEN ))
+ return 1;
+ name = ptr; /* member name */
+ ptr += NAMELEN;
+ memcpy( ttr, ptr, TTRLEN ); /* ttr name */
+ ptr += TTRLEN;
+ info_byte = (unsigned int) (*ptr); /* info byte */
+ if ( !(info_byte & ALIAS_MASK) ) { /* no alias */
+ new = malloc( sizeof(struct dirent) );
+ if (dirp->D_list == NULL)
+ dirp->D_list = dirp->D_curpos = new;
+ else
+ dirp->D_curpos = (dirp->D_curpos->d_next = new);
+ new->d_next = NULL;
+ memcpy( new->d_name, name, NAMELEN );
+ new->d_name[NAMELEN] = '\0';
+ if ((name = strchr( new->d_name, ' ' )) != NULL)
+ *name = '\0'; /* skip trailing blanks */
+ }
+ skip = (info_byte & SKIP_MASK) * 2 + 1;
+ ptr += skip;
+ count += (TTRLEN + NAMELEN + skip);
+ }
+ return 0;
+}
+
+DIR *opendir(const char *dirname)
+{
+ int bytes, list_end = 0;
+ DIR *dirp;
+ FILE *fp;
+ RECORD rec;
+
+ fp = fopen( dirname, "rb" );
+ if (fp != NULL) {
+ dirp = malloc( sizeof(DIR) );
+ if (dirp != NULL) {
+ dirp->D_list = dirp->D_curpos = NULL;
+ strcpy( dirp->D_path, dirname );
+ do {
+ bytes = fread( &rec, 1, sizeof(rec), fp );
+ if (bytes == sizeof(rec))
+ list_end = gen_node( dirp, &rec );
+ } while (!feof(fp) && !list_end);
+ fclose( fp );
+ dirp->D_curpos = dirp->D_list;
+ return dirp;
+ }
+ fclose( fp );
+ }
+ return NULL;
+}
+
+struct dirent *readdir(DIR *dirp)
+{
+ struct dirent *cur;
+
+ cur = dirp->D_curpos;
+ dirp->D_curpos = dirp->D_curpos->d_next;
+ return cur;
+}
+
+void rewinddir(DIR *dirp)
+{
+ dirp->D_curpos = dirp->D_list;
+}
+
+int closedir(DIR *dirp)
+{
+ struct dirent *node;
+
+ while (dirp->D_list != NULL) {
+ node = dirp->D_list;
+ dirp->D_list = dirp->D_list->d_next;
+ free( node );
+ }
+ free( dirp );
+ return 0;
+}
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+ int exists; /* 1 if file exists */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (!(exists = (LSSTAT(n, &s) == 0)))
+ {
+#ifdef MVS
+ /* special case for MVS. stat does not work on non-HFS files so if
+ * stat fails with ENOENT, try to open the file for reading anyway.
+ * If the user has no OMVS segment, stat gets an initialization error,
+ * even on external files.
+ */
+ if (errno == ENOENT || errno == EMVSINITIAL) {
+ FILE *f = fopen(n, "r");
+ if (f) {
+ /* stat got ENOENT but fopen worked, external file */
+ fclose(f);
+ exists = 1;
+ memset(&s, '\0', sizeof(s)); /* stat data is unreliable for externals */
+ s.st_mode = S_IFREG; /* fudge it */
+ }
+ }
+#endif /* MVS */
+ }
+ if (! exists) {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if (!S_ISDIR(s.st_mode))
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
diff --git a/cmsmvs/mvs.h b/cmsmvs/mvs.h
new file mode 100644
index 0000000..b2f9760
--- /dev/null
+++ b/cmsmvs/mvs.h
@@ -0,0 +1,40 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* <dirent.h> definitions */
+
+#define NAMELEN 8
+
+struct dirent {
+ struct dirent *d_next;
+ char d_name[NAMELEN+1];
+};
+
+typedef struct _DIR {
+ struct dirent *D_list;
+ struct dirent *D_curpos;
+ char D_path[FILENAME_MAX];
+} DIR;
+
+DIR * opendir(const char *dirname);
+struct dirent *readdir(DIR *dirp);
+void rewinddir(DIR *dirp);
+int closedir(DIR *dirp);
+char * readd(DIR *dirp);
+
+#define ALIAS_MASK (unsigned int) 0x80
+#define SKIP_MASK (unsigned int) 0x1F
+#define TTRLEN 3
+#define RECLEN 254
+
+typedef _Packed struct {
+ unsigned short int count;
+ char rest[RECLEN];
+} RECORD;
+
+char *endmark = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
diff --git a/cmsmvs/mvs.mki b/cmsmvs/mvs.mki
new file mode 100644
index 0000000..316d064
--- /dev/null
+++ b/cmsmvs/mvs.mki
@@ -0,0 +1,125 @@
+# Makefile for the MVS (OS/390 Base) version of ZIP 2.3
+# Produced for C/C++ V3R2 in OS/390 1.2.0 by Ian E. Gorman, 2 Nov 1998
+# Facilities for compiling and testing were made available by
+# OmniMark Technologies Corporation, Ottawa, Canada
+
+# NOTES
+#
+# The only tabs in this file are in the first character of each recipe
+# line, where they are required by make.
+#
+# Run this makefile in OpenMVS (OS/390 POSIX) using source files in the
+# HFS file system. You can write the load module to either HFS file
+# system or to a PDS in the native MVS file system. The PDS must have
+# sufficient free space to hold the load module.
+#
+# To compile to a member of a PDS:
+# make
+# or
+# make zip.mvs
+#
+# To compile a test version into the HFS file system:
+# make hfs
+
+# ZIP options -- MVS, REENTRANT
+ZIPOPTS=-DMVS -DREENTRANT
+
+# directories
+
+# generic source code
+SRC=..
+SRC_P=$(SRC)/
+
+# source code for MVS
+CMSMVS=../cmsmvs
+CMSMVS_P=$(CMSMVS)/
+
+# include files
+INCLS=-I$(SRC) -I$(CMSMVS)
+
+# object files and load modules
+BLD_P=../mvs/
+
+# Other options
+
+# Suffixes (E and O must be different)
+E=
+O=.o
+
+# Need EXTENDED features for global.c and vmvms.c, so not using c89
+CC=cc
+CFLAGS=-D_OPEN_SYS $(ZIPOPTS) $(INCLS)
+
+LD=cc
+LDFLAGS=
+
+# Files
+
+# object (TEXT) files
+OBJECTS= $(BLD_P)zip$(O) $(BLD_P)trees$(O) \
+ $(BLD_P)crypt$(O) $(BLD_P)ttyio$(O) $(BLD_P)deflate$(O) \
+ $(BLD_P)fileio$(O) $(BLD_P)globals$(O) $(BLD_P)util$(O) \
+ $(BLD_P)crc32$(O) $(BLD_P)zipfile$(O) \
+ $(BLD_P)zipup$(O) $(BLD_P)cmsmvs$(O) $(BLD_P)mvs$(O)
+
+# Header files
+HFILES= $(SRC_P)api.h $(SRC_P)crc32.h $(SRC_P)crypt.h $(SRC_P)ebcdic.h \
+ $(SRC_P)revision.h $(SRC_P)tailor.h $(SRC_P)ttyio.h \
+ $(SRC_P)zip.h $(SRC_P)ziperr.h $(CMSMVS_P)cmsmvs.h \
+ $(CMSMVS_P)cstat.h $(CMSMVS_P)mvs.h $(CMSMVS_P)zipup.h
+
+# Rules
+
+all: $(BLD_P)zip.mvs$(E)
+hfs: $(BLD_P)zip$(E)
+
+# link
+
+$(BLD_P)zip.mvs$(E): $(OBJECTS)
+ $(LD) -o "//INFOZIP.LOAD(ZIP)" $(LDFLAGS) $^
+ echo "tso call \"infozip(zip)\" \"'\"\"""$$""@""\"\"'\"" > $%
+ chmod a+x $%
+
+$(BLD_P)zip$(E): $(OBJECTS)
+ $(LD) -o $% $(LDFLAGS) $^
+
+# compile
+
+$(BLD_P)trees$(O): $(SRC_P)trees.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)trees.c
+
+$(BLD_P)crypt$(O): $(SRC_P)crypt.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)crypt.c
+
+$(BLD_P)ttyio$(O): $(SRC_P)ttyio.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)ttyio.c
+
+$(BLD_P)deflate$(O): $(SRC_P)deflate.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)deflate.c
+
+$(BLD_P)fileio$(O): $(SRC_P)fileio.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)fileio.c
+
+$(BLD_P)globals$(O): $(SRC_P)globals.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)globals.c
+
+$(BLD_P)zip$(O): $(SRC_P)zip.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)zip.c
+
+$(BLD_P)util$(O): $(SRC_P)util.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)util.c
+
+$(BLD_P)crc32$(O): $(SRC_P)crc32.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)crc32.c
+
+$(BLD_P)zipfile$(O): $(SRC_P)zipfile.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)zipfile.c
+
+$(BLD_P)zipup$(O): $(SRC_P)zipup.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(SRC_P)zipup.c
+
+$(BLD_P)cmsmvs$(O): $(CMSMVS_P)cmsmvs.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(CMSMVS_P)cmsmvs.c
+
+$(BLD_P)mvs$(O): $(CMSMVS_P)mvs.c $(HFILES)
+ $(CC) -c -o $% $(CFLAGS) $(CMSMVS_P)mvs.c
diff --git a/cmsmvs/pipzip.rexx b/cmsmvs/pipzip.rexx
new file mode 100644
index 0000000..4249ded
--- /dev/null
+++ b/cmsmvs/pipzip.rexx
@@ -0,0 +1,27 @@
+/* PIPZIP REXX Rexx filter to use ZIP */
+/* Author : George Petrov, 8 May 1995 */
+
+parse arg opts
+'callpipe *:',
+ '| specs w1 1 /./ n w2 n',
+ '| join * / /',
+ '| specs /zip 'opts'/ 1 1-* nw',
+ '| cms',
+ '| *:'
+
+exit rc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmsmvs/zip.exec b/cmsmvs/zip.exec
new file mode 100644
index 0000000..0b9de97
--- /dev/null
+++ b/cmsmvs/zip.exec
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/* */
+/* Front-end EXEC to set up linkage to the C runtime libraries */
+/* before executing a MODULE generated from C code. */
+/* */
+/* Copy this file as an EXEC with a filename matching the C MODULE. */
+/* */
+/* Greg Hartwig (ghartwig@vnet.ibm.com) 7/31/97, 4/24/98. */
+/* */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT BA AD'
+'SET INPUT BB BD'
+
+Call CLIB
+If rc<>0 Then Do
+ Say 'The required C runtime libraries don''t appear to be available.'
+ Say myname 'can not run.'
+ Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking. */
+/* Removed TXTLIB setting. Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/* SET UP LIBRARIES FOR LE for MVS & VM */
+/***************************************************/
+Address COMMAND
+
+loadlib ='EDCLINK' /* C/370 runtime */
+loadlib ='SCEERUN' /* LE runtime */
+
+
+theirs=queued() /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO' /* old setting M068*/
+ LoadlibList='' /* init list M068*/
+rc=0
+ Do while queued()^=theirs /* all lines from cmdM068*/
+ Parse upper pull 'LOADLIB' '=' Ltemp /* get one line M068*/
+ LoadlibList= Ltemp Loadliblist /* was stacked LIFO M068*/
+ End /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+ 'GLOBAL LOADLIB' Loadlib /* enforce what we need */
+ End
+ Else Do
+ Do xx=1 to Words(loadlib)
+ If Find(loadliblist,word(loadlib,xx)) = 0 ,
+ then loadliblist = loadliblist word(loadlib,xx)
+ End
+ 'GLOBAL LOADLIB' loadliblist /* enforce what we need */
+ End
+Return
diff --git a/cmsmvs/zip.makefile b/cmsmvs/zip.makefile
new file mode 100644
index 0000000..85bef22
--- /dev/null
+++ b/cmsmvs/zip.makefile
@@ -0,0 +1,21 @@
+* This is a comment
+* this makefile compiles filter ZIPME
+
+GLOBALS:
+ long def(VM_CMS)
+TEXT:
+ trees c
+ crypt c
+ ttyio c
+ deflate c
+ fileio c
+ globals c
+ zip c
+ util c
+ crc32.c
+ zipfile c
+ zipup c
+ cmsmvs c
+ cms c
+MODULE:
+ zip module
diff --git a/cmsmvs/zipcloak.exec b/cmsmvs/zipcloak.exec
new file mode 100644
index 0000000..0b9de97
--- /dev/null
+++ b/cmsmvs/zipcloak.exec
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/* */
+/* Front-end EXEC to set up linkage to the C runtime libraries */
+/* before executing a MODULE generated from C code. */
+/* */
+/* Copy this file as an EXEC with a filename matching the C MODULE. */
+/* */
+/* Greg Hartwig (ghartwig@vnet.ibm.com) 7/31/97, 4/24/98. */
+/* */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT BA AD'
+'SET INPUT BB BD'
+
+Call CLIB
+If rc<>0 Then Do
+ Say 'The required C runtime libraries don''t appear to be available.'
+ Say myname 'can not run.'
+ Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking. */
+/* Removed TXTLIB setting. Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/* SET UP LIBRARIES FOR LE for MVS & VM */
+/***************************************************/
+Address COMMAND
+
+loadlib ='EDCLINK' /* C/370 runtime */
+loadlib ='SCEERUN' /* LE runtime */
+
+
+theirs=queued() /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO' /* old setting M068*/
+ LoadlibList='' /* init list M068*/
+rc=0
+ Do while queued()^=theirs /* all lines from cmdM068*/
+ Parse upper pull 'LOADLIB' '=' Ltemp /* get one line M068*/
+ LoadlibList= Ltemp Loadliblist /* was stacked LIFO M068*/
+ End /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+ 'GLOBAL LOADLIB' Loadlib /* enforce what we need */
+ End
+ Else Do
+ Do xx=1 to Words(loadlib)
+ If Find(loadliblist,word(loadlib,xx)) = 0 ,
+ then loadliblist = loadliblist word(loadlib,xx)
+ End
+ 'GLOBAL LOADLIB' loadliblist /* enforce what we need */
+ End
+Return
diff --git a/cmsmvs/zipmvsc.job b/cmsmvs/zipmvsc.job
new file mode 100644
index 0000000..3c786d7
--- /dev/null
+++ b/cmsmvs/zipmvsc.job
@@ -0,0 +1,89 @@
+//CCZIP JOB (BI09255),
+// MSGLEVEL=(1,1),MSGCLASS=C,CLASS=D,NOTIFY=C888090
+//PROCLIB JCLLIB ORDER=(SYS1.C370.PROCLIB.M24)
+//ZIP EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(ZIP)',
+// OUTFILE='C888090.ZIP.C.OBJ(ZIP),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//CRYPT EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(CRYPT)',
+// OUTFILE='C888090.ZIP.C.OBJ(CRYPT),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//TTYIO EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(TTYIO)',
+// OUTFILE='C888090.ZIP.C.OBJ(TTYIO),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//TREES EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(TREES)',
+// OUTFILE='C888090.ZIP.C.OBJ(TREES),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//DEFLATE EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(DEFLATE)',
+// OUTFILE='C888090.ZIP.C.OBJ(DEFLATE),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//FILEIO EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(FILEIO)',
+// OUTFILE='C888090.ZIP.C.OBJ(FILEIO),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//GLOBALS EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(GLOBALS)',
+// OUTFILE='C888090.ZIP.C.OBJ(GLOBALS),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//UTIL EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(UTIL)',
+// OUTFILE='C888090.ZIP.C.OBJ(UTIL),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//CRC32 EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(CRC32)',
+// OUTFILE='C888090.ZIP.C.OBJ(CRC32),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//ZIPFILE EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(ZIPFILE)',
+// OUTFILE='C888090.ZIP.C.OBJ(ZIPFILE),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//ZIPUP EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(ZIPUP)',
+// OUTFILE='C888090.ZIP.C.OBJ(ZIPUP),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//CMSMVS EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(CMSMVS)',
+// OUTFILE='C888090.ZIP.C.OBJ(CMSMVS),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//MVS EXEC EDCC,COND=(12,LE),CREGSIZ='4M',
+// INFILE='C888090.ZIP.C(MVS)',
+// OUTFILE='C888090.ZIP.C.OBJ(MVS),DISP=SHR',
+// CPARM='LONG,NOTERM,LIST,XREF,SOURCE,OPT(2),DEF(MVS)'
+//COMPILE.USERLIB DD DSN=C888090.ZIP.H,DISP=SHR
+//PLINK EXEC PROC=EDCPL,COND=(12,LE),
+// OUTFILE='C888090.ZIP.LOAD(ZIP),DISP=SHR',
+// PPARM='NONCAL,MAP',
+// LPARM='LIST,MAP,XREF'
+//SYSPRINT DD SYSOUT=*
+//PLKED.SYSIN DD DSN=C888090.ZIP.C.OBJ(ZIP),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(BITS),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(CRYPT),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(TREES),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(DEFLATE),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(FILEIO),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(GLOBALS),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(UTIL),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(CRC32),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(ZIPFILE),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(ZIPUP),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(CMSMVS),DISP=SHR
+// DD DSN=C888090.ZIP.C.OBJ(MVS),DISP=SHR
+//PLKED.SYSLIB DD DSN=SYS1.C370.SEDCBASE,DISP=SHR
+// DD DSN=SYS1.PL1.SIBMBASE,DISP=SHR
+//SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(2,2)),DISP=NEW
diff --git a/cmsmvs/zipname.conven b/cmsmvs/zipname.conven
new file mode 100644
index 0000000..e17fe9c
--- /dev/null
+++ b/cmsmvs/zipname.conven
@@ -0,0 +1,200 @@
+
+ Zip file/directories name convention under MVS
+ ---------------------------------------------------
+ Draft 1.1
+
+
+1. Translating native file names to Zip filenames.
+
+1.1 Zipping a PDS
+
+On MVS there are directories called PDS (Partition Data Set) which have
+the following format : name1.name2.name3(mname)
+for example: myuserid.unzip.c(unzip)
+
+So as you see the path delimiter is '.'. Each dir name can be max 8
+chars long beginning with a number.
+
+Between '(' and ')' there is the so called member name - it is also 8
+chars long. This is the actual file name.
+
+
+1.1.1 Converting MVS PDS name to zip path/filename (status: not implemented)
+
+The PDS name is converted to zippath as follows:
+in the zip : name1/name2/mname.name3
+becomes on MVS: name1.name2.name3(mname)
+
+
+1.2 Unzipping as PDS (status: implemented)
+
+When you unzip the file name myuserid/unzip/unzip.c the same process
+is done backwards, so you get : myuserid.unzip.c(unzip)
+
+Notice that the file extension is used as last dirname!
+
+
+1.2 Unzipping to a different PDS (status: implemented)
+
+You can also use -d option while unzipping for example:
+unzip mytest myuserid/unzip/unzip.c -dnewdest.test
+
+then the new name will become:
+newdest.test.myuserid.unzip.c(unzip)
+
+ Second example:
+
+unzip mytest myuserid/unzip/*.c -dnewdest.test
+
+then you get a PDS:
+newdest.test.myuserid.unzip.c(...)
+
+with all *.c files in it.
+
+
+1.3 Zipping a Sequential Dataset (status: not implemented)
+
+ Sequential dataset is a dataset with NO members.
+Such a dataset is translated from native MVS to zip format by replacing
+the '.' (points) with '/' (backslash).
+
+Example:
+on MVS: name1.name2.name3
+becomes in the zip : name1/name2/name3
+
+NOTE : The new filename in the zip has NO extension this way it can be
+ recognised as a Sequential dataset and not a PDS.
+ But this also means that all files in the zip archive that have
+ no extension will be unzipped as Sequential datasets!
+
+
+1.4 Using a DDNAMES for input. (status: not implemented)
+
+To use DDNAMES as input file names put a 'dd:' before the ddname:
+example: zip myzip dd:name1 dd:name2 dd:sales
+
+In the Zip archive the ddnames are saved as name.DDNAME so if you try
+the example above you will get in your zip file (when listing it) :
+
+..size .. date time .. crc .. NAME1.DDNAME
+..size .. date time .. crc .. NAME2.DDNAME
+..size .. date time .. crc .. SALES.DDNAME
+
+
+1.4 Using a DDNAMES as zip name (status: implemented)
+
+It is allowed to use a DDNAME as zipfile, just put dd: before it
+example: unzip dd:myzip *.c
+ this will unzip all .c files from ddname myzip
+
+example2: ZIP DD:MYZIP DD:MANE1 MYSOURCE.C MYDOC.TEXT(ZIPPING)
+ this will zip ddname name1 file mysource.c and PDS mydoc.text(zipping)
+ into as a zip file in the ddname myzip
+
+
+2. Converting longer path names (unix like) (status: not implemented)
+ to native MVS names.
+
+When in the zip archive there are dirnames longer that 8 chars they are
+chopped at the 8 position. For example
+ MyLongZippath/WithLongFileName.text
+is translated to:
+ MYLONGZI.TEXT(WITHLONG)
+
+Notice that all chars are converted to uppercase.
+
+
+2.1 Using special characters (status: implemented)
+
+Also all '_' (underscore), '+' (plus), '-' (minus), '(' and ')'
+from the file name/path in the zip archive are skipped because they
+are not valid in the MVS filenames.
+
+
+2.2 Numeric file names (status: not implemented)
+
+On MVS no name can begin with a number, so when a dir/file name begins with
+one, a leading letter 'N' is inserted. For example:
+ Contents.512
+becomes:
+ CONTENTS.N512
+
+
+
+
+ Zip file/directories name convention under VM/CMS
+ ---------------------------------------------------
+
+1. Translating native file names to Zip filenames.
+
+On VM/CMS (not ESA ) there are NO directories so you got only disks
+and files.
+
+The file names are delimited with spaces. But for use with unzip/zip
+you have to use '.' points as delimiters.
+
+For example on your A disk you have file called PROFILE EXEC
+if you want to zip it type : zip myzip profile.exec
+
+If the same file is on your F disk you have to type:
+zip myzip profile.exec.f
+
+So as you can see the general format is fname.ftype.fmode
+
+In the zipfile the disk from which the file comes is not saved!
+So only the fname.ftype is saved.
+
+If you unzip and you want to give a different destination disk just use
+the -d option like:
+
+ unzip mytest *.c -df
+
+This will unzip all *.c files to your F disk.
+
+
+2. Converting longer path names (unix like) to native VM/CMS names.
+
+When in the zip archive there are dirnames longer that 8 chars they are
+chopped at the 8 position. Also the path is removed. For example
+ Zippath/WithLongFileName.text
+is translated to:
+ WITHLONG.TEXT
+
+Notice that all chars are converted to uppercase.
+
+Also all '+' (plus), '-' (minus), '(' and ')'
+from the file name/path in the zip archive are skipped because they
+are not valid in the VM/CMS filenames.
+
+If there is no extension for the file name in the zip archive, unzip
+will add .NONAME for example:
+ mypath/dir1/testfile
+becomes:
+ TESTFILE.NONAME
+
+3. Future?
+
+There is also discussion for a new option on ZIP that you can give
+a virtual directory to be added before each file name that is zipped.
+
+For example you want to zip a few .c file and put them in the zip
+structure under the directory 'mydir/test', but you can't create dirs on
+VM/CMS so you have to the something like:
+
+ZIP myzip file1.c file2.c -dmydir/test
+
+and you get in the zip archive files:
+
+ mydir/test/file1.c
+ mydir/test/file2.c
+
+-------------------------------------------------------------------------
+
+
+NOTE: Not all of those functions are implemented in the first beta
+ release of VM/MVS UNZIP/ZIP.
+
+Every ideas/corrections/bugs will be appreciated.
+Mail to maillist: Info-ZIP@LISTS.WKU.EDU
+
+George Petrov
diff --git a/cmsmvs/zipnote.exec b/cmsmvs/zipnote.exec
new file mode 100644
index 0000000..0b9de97
--- /dev/null
+++ b/cmsmvs/zipnote.exec
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/* */
+/* Front-end EXEC to set up linkage to the C runtime libraries */
+/* before executing a MODULE generated from C code. */
+/* */
+/* Copy this file as an EXEC with a filename matching the C MODULE. */
+/* */
+/* Greg Hartwig (ghartwig@vnet.ibm.com) 7/31/97, 4/24/98. */
+/* */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT BA AD'
+'SET INPUT BB BD'
+
+Call CLIB
+If rc<>0 Then Do
+ Say 'The required C runtime libraries don''t appear to be available.'
+ Say myname 'can not run.'
+ Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking. */
+/* Removed TXTLIB setting. Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/* SET UP LIBRARIES FOR LE for MVS & VM */
+/***************************************************/
+Address COMMAND
+
+loadlib ='EDCLINK' /* C/370 runtime */
+loadlib ='SCEERUN' /* LE runtime */
+
+
+theirs=queued() /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO' /* old setting M068*/
+ LoadlibList='' /* init list M068*/
+rc=0
+ Do while queued()^=theirs /* all lines from cmdM068*/
+ Parse upper pull 'LOADLIB' '=' Ltemp /* get one line M068*/
+ LoadlibList= Ltemp Loadliblist /* was stacked LIFO M068*/
+ End /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+ 'GLOBAL LOADLIB' Loadlib /* enforce what we need */
+ End
+ Else Do
+ Do xx=1 to Words(loadlib)
+ If Find(loadliblist,word(loadlib,xx)) = 0 ,
+ then loadliblist = loadliblist word(loadlib,xx)
+ End
+ 'GLOBAL LOADLIB' loadliblist /* enforce what we need */
+ End
+Return
diff --git a/cmsmvs/zipsplit.exec b/cmsmvs/zipsplit.exec
new file mode 100644
index 0000000..0b9de97
--- /dev/null
+++ b/cmsmvs/zipsplit.exec
@@ -0,0 +1,66 @@
+/***********************************************************************/
+/* */
+/* Front-end EXEC to set up linkage to the C runtime libraries */
+/* before executing a MODULE generated from C code. */
+/* */
+/* Copy this file as an EXEC with a filename matching the C MODULE. */
+/* */
+/* Greg Hartwig (ghartwig@vnet.ibm.com) 7/31/97, 4/24/98. */
+/* */
+/***********************************************************************/
+Address Command
+Parse Arg argstring
+Parse Source . . myname .
+
+/* Set output and input character translation so brackets show up */
+'SET OUTPUT AD' 'BA'x
+'SET OUTPUT BD' 'BB'x
+'SET INPUT BA AD'
+'SET INPUT BB BD'
+
+Call CLIB
+If rc<>0 Then Do
+ Say 'The required C runtime libraries don''t appear to be available.'
+ Say myname 'can not run.'
+ Exit 12
+End
+
+/* Run the command */
+myname argstring
+Exit rc
+
+
+
+
+/* Contents of the CLIB EXEC, modified for RC checking. */
+/* Removed TXTLIB setting. Only LOADLIB needed for execution. */
+CLIB:
+/***************************************************/
+/* SET UP LIBRARIES FOR LE for MVS & VM */
+/***************************************************/
+Address COMMAND
+
+loadlib ='EDCLINK' /* C/370 runtime */
+loadlib ='SCEERUN' /* LE runtime */
+
+
+theirs=queued() /* old stack contentsM068*/
+ 'QUERY LOADLIB ( LIFO' /* old setting M068*/
+ LoadlibList='' /* init list M068*/
+rc=0
+ Do while queued()^=theirs /* all lines from cmdM068*/
+ Parse upper pull 'LOADLIB' '=' Ltemp /* get one line M068*/
+ LoadlibList= Ltemp Loadliblist /* was stacked LIFO M068*/
+ End /*M068*/
+ If loadlibList='NONE' ,
+ Then Do
+ 'GLOBAL LOADLIB' Loadlib /* enforce what we need */
+ End
+ Else Do
+ Do xx=1 to Words(loadlib)
+ If Find(loadliblist,word(loadlib,xx)) = 0 ,
+ then loadliblist = loadliblist word(loadlib,xx)
+ End
+ 'GLOBAL LOADLIB' loadliblist /* enforce what we need */
+ End
+Return
diff --git a/cmsmvs/zipup.h b/cmsmvs/zipup.h
new file mode 100644
index 0000000..0ea8962
--- /dev/null
+++ b/cmsmvs/zipup.h
@@ -0,0 +1,18 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow "r,byteseek"
+#define fhowb "rb,byteseek"
+
+#define fbad NULL
+typedef FILE *ftype;
+#define zopen(n,p) (ftype)fopen((n),(p))
+#define zread(f,b,n) fread((b),1,(n),(FILE*)(f))
+#define zclose(f) fclose((FILE*)(f))
+#define zerr(f) ferror((FILE*)(f))
+#define zstdin stdin
diff --git a/cmsmvs/zipvmc.exec b/cmsmvs/zipvmc.exec
new file mode 100644
index 0000000..3fdd800
--- /dev/null
+++ b/cmsmvs/zipvmc.exec
@@ -0,0 +1,48 @@
+/* VMCOMPIL EXEC Unzip compile for VM/CMS */
+/* Author : George Petrov, 11 Apr 1995 */
+
+signal on error
+
+parms = '(long def(VM_CMS)'
+
+/* Add local parms */
+parms = parms 'TARGET(COMPAT) SOURCE'
+
+
+say 'Compiling TREES C...'
+'cc trees c 'parms
+say 'Compiling CRYPT C...'
+'cc crypt c 'parms
+say 'Compiling TTYIO C...'
+'cc ttyio c 'parms
+say 'Compiling DEFLATE C...'
+'cc deflate c 'parms
+say 'Compiling FILEIO C...'
+'cc fileio c 'parms
+say 'Compiling GLOBALS C...'
+'cc globals c 'parms
+say 'Compiling ZIP C...'
+'cc zip c 'parms
+say 'Compiling UTIL C...'
+'cc util c 'parms
+say 'Compiling CRC32 C...'
+'cc crc32 c 'parms
+say 'Compiling ZIPFILE C...'
+'cc zipfile c 'parms
+say 'Compiling ZIPUP C...'
+'cc zipup c 'parms
+say 'Compiling CMSMVS C...'
+'cc cmsmvs c 'parms
+say 'Compiling CMS C...'
+'cc cms c 'parms
+
+say 'Linking all files...'
+'cmod zip zip trees crypt deflate fileio globals ttyio',
+ 'util crc32 zipfile zipup cmsmvs cms'
+say 'All Done!'
+say "To run enter : ZIP parms"
+exit rc
+
+error:
+say 'Error durring compilation!'
+exit rc
diff --git a/crc32.c b/crc32.c
new file mode 100644
index 0000000..6b2403b
--- /dev/null
+++ b/crc32.c
@@ -0,0 +1,732 @@
+/*
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results about a factor
+ * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* $Id: crc32.c,v 2.0 2007/01/07 05:20:36 spc Exp $ */
+
+#define __CRC32_C /* identifies this source module */
+
+#include "zip.h"
+
+#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+#include "crc32.h"
+
+/* When only the table of precomputed CRC values is needed, only the basic
+ system-independent table containing 256 entries is created; any support
+ for "unfolding" optimization is disabled.
+ */
+#if (defined(USE_ZLIB) || defined(CRC_TABLE_ONLY))
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+# undef IZ_CRCOPTIM_UNFOLDTBL
+# endif
+#endif /* (USE_ZLIB || CRC_TABLE_ONLY) */
+
+#if defined(IZ_CRCOPTIM_UNFOLDTBL)
+# define CRC_TBLS 4
+#else
+# define CRC_TBLS 1
+#endif
+
+
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first (or only) table is simply the CRC of all possible eight bit values.
+ This is all the information needed to generate CRC's on data a byte-at-a-time
+ for all combinations of CRC register values and incoming bytes.
+ The remaining 3 tables (if IZ_CRCOPTIM_UNFOLDTBL is enabled) allow for
+ word-at-a-time CRC calculation, where a word is four bytes.
+*/
+
+#ifdef DYNAMIC_CRC_TABLE
+
+/* =========================================================================
+ * Make the crc table. This function is needed only if you want to compute
+ * the table dynamically.
+ */
+
+local void make_crc_table OF((void));
+
+#if (defined(DYNALLOC_CRCTAB) && defined(REENTRANT))
+ error: Dynamic allocation of CRC table not safe with reentrant code.
+#endif /* DYNALLOC_CRCTAB && REENTRANT */
+
+#ifdef DYNALLOC_CRCTAB
+ local ulg near *crc_table = NULL;
+# if 0 /* not used, since sizeof("near *") <= sizeof(int) */
+ /* Use this section when access to a "local int" is faster than access to
+ a "local pointer" (e.g.: i86 16bit code with far pointers). */
+ local int crc_table_empty = 1;
+# define CRC_TABLE_IS_EMPTY (crc_table_empty != 0)
+# define MARK_CRCTAB_FILLED crc_table_empty = 0
+# define MARK_CRCTAB_EMPTY crc_table_empty = 1
+# else
+ /* Use this section on systems where the size of pointers and ints is
+ equal (e.g.: all 32bit systems). */
+# define CRC_TABLE_IS_EMPTY (crc_table == NULL)
+# define MARK_CRCTAB_FILLED crc_table = crctab_p
+# define MARK_CRCTAB_EMPTY crc_table = NULL
+# endif
+#else /* !DYNALLOC_CRCTAB */
+ local ulg near crc_table[CRC_TBLS*256];
+ local int crc_table_empty = 1;
+# define CRC_TABLE_IS_EMPTY (crc_table_empty != 0)
+# define MARK_CRCTAB_FILLED crc_table_empty = 0
+#endif /* ?DYNALLOC_CRCTAB */
+
+
+local void make_crc_table()
+{
+ ulg c; /* crc shift register */
+ int n; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+#ifdef DYNALLOC_CRCTAB
+ ulg near *crctab_p; /* temporary pointer to allocated crc_table area */
+#else /* !DYNALLOC_CRCTAB */
+# define crctab_p crc_table
+#endif /* DYNALLOC_CRCTAB */
+
+#ifdef COMPUTE_XOR_PATTERN
+ /* This piece of code has been left here to explain how the XOR pattern
+ * used in the creation of the crc_table values can be recomputed.
+ * For production versions of this function, it is more efficient to
+ * supply the resultant pattern at compile time.
+ */
+ ulg xor; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static ZCONST uch p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* make exclusive-or pattern from polynomial (0xedb88320L) */
+ xor = 0L;
+ for (n = 0; n < sizeof(p)/sizeof(uch); n++)
+ xor |= 1L << (31 - p[n]);
+#else
+# define xor 0xedb88320L
+#endif
+
+#ifdef DYNALLOC_CRCTAB
+ crctab_p = (ulg near *) nearmalloc (CRC_TBLS*256*sizeof(ulg));
+ if (crctab_p == NULL) {
+ ziperr(ZE_MEM, "crc_table allocation");
+ }
+#endif /* DYNALLOC_CRCTAB */
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (ulg)n;
+ for (k = 8; k; k--)
+ c = c & 1 ? xor ^ (c >> 1) : c >> 1;
+ crctab_p[n] = REV_BE(c);
+ }
+
+#ifdef IZ_CRCOPTIM_UNFOLDTBL
+ /* generate crc for each value followed by one, two, and three zeros */
+ for (n = 0; n < 256; n++) {
+ c = crctab_p[n];
+ for (k = 1; k < 4; k++) {
+ c = CRC32(c, 0, crctab_p);
+ crctab_p[k*256+n] = c;
+ }
+ }
+#endif /* IZ_CRCOPTIM_UNFOLDTBL */
+
+ MARK_CRCTAB_FILLED;
+}
+
+#else /* !DYNAMIC_CRC_TABLE */
+
+#ifdef DYNALLOC_CRCTAB
+ error: Inconsistent flags, DYNALLOC_CRCTAB without DYNAMIC_CRC_TABLE.
+#endif
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+local ZCONST ulg near crc_table[CRC_TBLS*256] = {
+# ifdef IZ_CRC_BE_OPTIMIZ
+ 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L,
+ 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L,
+ 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L,
+ 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L,
+ 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L,
+ 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L,
+ 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L,
+ 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L,
+ 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L,
+ 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L,
+ 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL,
+ 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L,
+ 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L,
+ 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L,
+ 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L,
+ 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L,
+ 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL,
+ 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L,
+ 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL,
+ 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L,
+ 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L,
+ 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L,
+ 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL,
+ 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL,
+ 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L,
+ 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL,
+ 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L,
+ 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL,
+ 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L,
+ 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L,
+ 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L,
+ 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L,
+ 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L,
+ 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL,
+ 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L,
+ 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L,
+ 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L,
+ 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L,
+ 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L,
+ 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L,
+ 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L,
+ 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L,
+ 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL,
+ 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L,
+ 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L,
+ 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L,
+ 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L,
+ 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L,
+ 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL,
+ 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L,
+ 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL,
+ 0x8def022dL
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+ ,
+ 0x00000000L, 0x41311b19L, 0x82623632L, 0xc3532d2bL, 0x04c56c64L,
+ 0x45f4777dL, 0x86a75a56L, 0xc796414fL, 0x088ad9c8L, 0x49bbc2d1L,
+ 0x8ae8effaL, 0xcbd9f4e3L, 0x0c4fb5acL, 0x4d7eaeb5L, 0x8e2d839eL,
+ 0xcf1c9887L, 0x5112c24aL, 0x1023d953L, 0xd370f478L, 0x9241ef61L,
+ 0x55d7ae2eL, 0x14e6b537L, 0xd7b5981cL, 0x96848305L, 0x59981b82L,
+ 0x18a9009bL, 0xdbfa2db0L, 0x9acb36a9L, 0x5d5d77e6L, 0x1c6c6cffL,
+ 0xdf3f41d4L, 0x9e0e5acdL, 0xa2248495L, 0xe3159f8cL, 0x2046b2a7L,
+ 0x6177a9beL, 0xa6e1e8f1L, 0xe7d0f3e8L, 0x2483dec3L, 0x65b2c5daL,
+ 0xaaae5d5dL, 0xeb9f4644L, 0x28cc6b6fL, 0x69fd7076L, 0xae6b3139L,
+ 0xef5a2a20L, 0x2c09070bL, 0x6d381c12L, 0xf33646dfL, 0xb2075dc6L,
+ 0x715470edL, 0x30656bf4L, 0xf7f32abbL, 0xb6c231a2L, 0x75911c89L,
+ 0x34a00790L, 0xfbbc9f17L, 0xba8d840eL, 0x79dea925L, 0x38efb23cL,
+ 0xff79f373L, 0xbe48e86aL, 0x7d1bc541L, 0x3c2ade58L, 0x054f79f0L,
+ 0x447e62e9L, 0x872d4fc2L, 0xc61c54dbL, 0x018a1594L, 0x40bb0e8dL,
+ 0x83e823a6L, 0xc2d938bfL, 0x0dc5a038L, 0x4cf4bb21L, 0x8fa7960aL,
+ 0xce968d13L, 0x0900cc5cL, 0x4831d745L, 0x8b62fa6eL, 0xca53e177L,
+ 0x545dbbbaL, 0x156ca0a3L, 0xd63f8d88L, 0x970e9691L, 0x5098d7deL,
+ 0x11a9ccc7L, 0xd2fae1ecL, 0x93cbfaf5L, 0x5cd76272L, 0x1de6796bL,
+ 0xdeb55440L, 0x9f844f59L, 0x58120e16L, 0x1923150fL, 0xda703824L,
+ 0x9b41233dL, 0xa76bfd65L, 0xe65ae67cL, 0x2509cb57L, 0x6438d04eL,
+ 0xa3ae9101L, 0xe29f8a18L, 0x21cca733L, 0x60fdbc2aL, 0xafe124adL,
+ 0xeed03fb4L, 0x2d83129fL, 0x6cb20986L, 0xab2448c9L, 0xea1553d0L,
+ 0x29467efbL, 0x687765e2L, 0xf6793f2fL, 0xb7482436L, 0x741b091dL,
+ 0x352a1204L, 0xf2bc534bL, 0xb38d4852L, 0x70de6579L, 0x31ef7e60L,
+ 0xfef3e6e7L, 0xbfc2fdfeL, 0x7c91d0d5L, 0x3da0cbccL, 0xfa368a83L,
+ 0xbb07919aL, 0x7854bcb1L, 0x3965a7a8L, 0x4b98833bL, 0x0aa99822L,
+ 0xc9fab509L, 0x88cbae10L, 0x4f5def5fL, 0x0e6cf446L, 0xcd3fd96dL,
+ 0x8c0ec274L, 0x43125af3L, 0x022341eaL, 0xc1706cc1L, 0x804177d8L,
+ 0x47d73697L, 0x06e62d8eL, 0xc5b500a5L, 0x84841bbcL, 0x1a8a4171L,
+ 0x5bbb5a68L, 0x98e87743L, 0xd9d96c5aL, 0x1e4f2d15L, 0x5f7e360cL,
+ 0x9c2d1b27L, 0xdd1c003eL, 0x120098b9L, 0x533183a0L, 0x9062ae8bL,
+ 0xd153b592L, 0x16c5f4ddL, 0x57f4efc4L, 0x94a7c2efL, 0xd596d9f6L,
+ 0xe9bc07aeL, 0xa88d1cb7L, 0x6bde319cL, 0x2aef2a85L, 0xed796bcaL,
+ 0xac4870d3L, 0x6f1b5df8L, 0x2e2a46e1L, 0xe136de66L, 0xa007c57fL,
+ 0x6354e854L, 0x2265f34dL, 0xe5f3b202L, 0xa4c2a91bL, 0x67918430L,
+ 0x26a09f29L, 0xb8aec5e4L, 0xf99fdefdL, 0x3accf3d6L, 0x7bfde8cfL,
+ 0xbc6ba980L, 0xfd5ab299L, 0x3e099fb2L, 0x7f3884abL, 0xb0241c2cL,
+ 0xf1150735L, 0x32462a1eL, 0x73773107L, 0xb4e17048L, 0xf5d06b51L,
+ 0x3683467aL, 0x77b25d63L, 0x4ed7facbL, 0x0fe6e1d2L, 0xccb5ccf9L,
+ 0x8d84d7e0L, 0x4a1296afL, 0x0b238db6L, 0xc870a09dL, 0x8941bb84L,
+ 0x465d2303L, 0x076c381aL, 0xc43f1531L, 0x850e0e28L, 0x42984f67L,
+ 0x03a9547eL, 0xc0fa7955L, 0x81cb624cL, 0x1fc53881L, 0x5ef42398L,
+ 0x9da70eb3L, 0xdc9615aaL, 0x1b0054e5L, 0x5a314ffcL, 0x996262d7L,
+ 0xd85379ceL, 0x174fe149L, 0x567efa50L, 0x952dd77bL, 0xd41ccc62L,
+ 0x138a8d2dL, 0x52bb9634L, 0x91e8bb1fL, 0xd0d9a006L, 0xecf37e5eL,
+ 0xadc26547L, 0x6e91486cL, 0x2fa05375L, 0xe836123aL, 0xa9070923L,
+ 0x6a542408L, 0x2b653f11L, 0xe479a796L, 0xa548bc8fL, 0x661b91a4L,
+ 0x272a8abdL, 0xe0bccbf2L, 0xa18dd0ebL, 0x62defdc0L, 0x23efe6d9L,
+ 0xbde1bc14L, 0xfcd0a70dL, 0x3f838a26L, 0x7eb2913fL, 0xb924d070L,
+ 0xf815cb69L, 0x3b46e642L, 0x7a77fd5bL, 0xb56b65dcL, 0xf45a7ec5L,
+ 0x370953eeL, 0x763848f7L, 0xb1ae09b8L, 0xf09f12a1L, 0x33cc3f8aL,
+ 0x72fd2493L
+ ,
+ 0x00000000L, 0x376ac201L, 0x6ed48403L, 0x59be4602L, 0xdca80907L,
+ 0xebc2cb06L, 0xb27c8d04L, 0x85164f05L, 0xb851130eL, 0x8f3bd10fL,
+ 0xd685970dL, 0xe1ef550cL, 0x64f91a09L, 0x5393d808L, 0x0a2d9e0aL,
+ 0x3d475c0bL, 0x70a3261cL, 0x47c9e41dL, 0x1e77a21fL, 0x291d601eL,
+ 0xac0b2f1bL, 0x9b61ed1aL, 0xc2dfab18L, 0xf5b56919L, 0xc8f23512L,
+ 0xff98f713L, 0xa626b111L, 0x914c7310L, 0x145a3c15L, 0x2330fe14L,
+ 0x7a8eb816L, 0x4de47a17L, 0xe0464d38L, 0xd72c8f39L, 0x8e92c93bL,
+ 0xb9f80b3aL, 0x3cee443fL, 0x0b84863eL, 0x523ac03cL, 0x6550023dL,
+ 0x58175e36L, 0x6f7d9c37L, 0x36c3da35L, 0x01a91834L, 0x84bf5731L,
+ 0xb3d59530L, 0xea6bd332L, 0xdd011133L, 0x90e56b24L, 0xa78fa925L,
+ 0xfe31ef27L, 0xc95b2d26L, 0x4c4d6223L, 0x7b27a022L, 0x2299e620L,
+ 0x15f32421L, 0x28b4782aL, 0x1fdeba2bL, 0x4660fc29L, 0x710a3e28L,
+ 0xf41c712dL, 0xc376b32cL, 0x9ac8f52eL, 0xada2372fL, 0xc08d9a70L,
+ 0xf7e75871L, 0xae591e73L, 0x9933dc72L, 0x1c259377L, 0x2b4f5176L,
+ 0x72f11774L, 0x459bd575L, 0x78dc897eL, 0x4fb64b7fL, 0x16080d7dL,
+ 0x2162cf7cL, 0xa4748079L, 0x931e4278L, 0xcaa0047aL, 0xfdcac67bL,
+ 0xb02ebc6cL, 0x87447e6dL, 0xdefa386fL, 0xe990fa6eL, 0x6c86b56bL,
+ 0x5bec776aL, 0x02523168L, 0x3538f369L, 0x087faf62L, 0x3f156d63L,
+ 0x66ab2b61L, 0x51c1e960L, 0xd4d7a665L, 0xe3bd6464L, 0xba032266L,
+ 0x8d69e067L, 0x20cbd748L, 0x17a11549L, 0x4e1f534bL, 0x7975914aL,
+ 0xfc63de4fL, 0xcb091c4eL, 0x92b75a4cL, 0xa5dd984dL, 0x989ac446L,
+ 0xaff00647L, 0xf64e4045L, 0xc1248244L, 0x4432cd41L, 0x73580f40L,
+ 0x2ae64942L, 0x1d8c8b43L, 0x5068f154L, 0x67023355L, 0x3ebc7557L,
+ 0x09d6b756L, 0x8cc0f853L, 0xbbaa3a52L, 0xe2147c50L, 0xd57ebe51L,
+ 0xe839e25aL, 0xdf53205bL, 0x86ed6659L, 0xb187a458L, 0x3491eb5dL,
+ 0x03fb295cL, 0x5a456f5eL, 0x6d2fad5fL, 0x801b35e1L, 0xb771f7e0L,
+ 0xeecfb1e2L, 0xd9a573e3L, 0x5cb33ce6L, 0x6bd9fee7L, 0x3267b8e5L,
+ 0x050d7ae4L, 0x384a26efL, 0x0f20e4eeL, 0x569ea2ecL, 0x61f460edL,
+ 0xe4e22fe8L, 0xd388ede9L, 0x8a36abebL, 0xbd5c69eaL, 0xf0b813fdL,
+ 0xc7d2d1fcL, 0x9e6c97feL, 0xa90655ffL, 0x2c101afaL, 0x1b7ad8fbL,
+ 0x42c49ef9L, 0x75ae5cf8L, 0x48e900f3L, 0x7f83c2f2L, 0x263d84f0L,
+ 0x115746f1L, 0x944109f4L, 0xa32bcbf5L, 0xfa958df7L, 0xcdff4ff6L,
+ 0x605d78d9L, 0x5737bad8L, 0x0e89fcdaL, 0x39e33edbL, 0xbcf571deL,
+ 0x8b9fb3dfL, 0xd221f5ddL, 0xe54b37dcL, 0xd80c6bd7L, 0xef66a9d6L,
+ 0xb6d8efd4L, 0x81b22dd5L, 0x04a462d0L, 0x33cea0d1L, 0x6a70e6d3L,
+ 0x5d1a24d2L, 0x10fe5ec5L, 0x27949cc4L, 0x7e2adac6L, 0x494018c7L,
+ 0xcc5657c2L, 0xfb3c95c3L, 0xa282d3c1L, 0x95e811c0L, 0xa8af4dcbL,
+ 0x9fc58fcaL, 0xc67bc9c8L, 0xf1110bc9L, 0x740744ccL, 0x436d86cdL,
+ 0x1ad3c0cfL, 0x2db902ceL, 0x4096af91L, 0x77fc6d90L, 0x2e422b92L,
+ 0x1928e993L, 0x9c3ea696L, 0xab546497L, 0xf2ea2295L, 0xc580e094L,
+ 0xf8c7bc9fL, 0xcfad7e9eL, 0x9613389cL, 0xa179fa9dL, 0x246fb598L,
+ 0x13057799L, 0x4abb319bL, 0x7dd1f39aL, 0x3035898dL, 0x075f4b8cL,
+ 0x5ee10d8eL, 0x698bcf8fL, 0xec9d808aL, 0xdbf7428bL, 0x82490489L,
+ 0xb523c688L, 0x88649a83L, 0xbf0e5882L, 0xe6b01e80L, 0xd1dadc81L,
+ 0x54cc9384L, 0x63a65185L, 0x3a181787L, 0x0d72d586L, 0xa0d0e2a9L,
+ 0x97ba20a8L, 0xce0466aaL, 0xf96ea4abL, 0x7c78ebaeL, 0x4b1229afL,
+ 0x12ac6fadL, 0x25c6adacL, 0x1881f1a7L, 0x2feb33a6L, 0x765575a4L,
+ 0x413fb7a5L, 0xc429f8a0L, 0xf3433aa1L, 0xaafd7ca3L, 0x9d97bea2L,
+ 0xd073c4b5L, 0xe71906b4L, 0xbea740b6L, 0x89cd82b7L, 0x0cdbcdb2L,
+ 0x3bb10fb3L, 0x620f49b1L, 0x55658bb0L, 0x6822d7bbL, 0x5f4815baL,
+ 0x06f653b8L, 0x319c91b9L, 0xb48adebcL, 0x83e01cbdL, 0xda5e5abfL,
+ 0xed3498beL
+ ,
+ 0x00000000L, 0x6567bcb8L, 0x8bc809aaL, 0xeeafb512L, 0x5797628fL,
+ 0x32f0de37L, 0xdc5f6b25L, 0xb938d79dL, 0xef28b4c5L, 0x8a4f087dL,
+ 0x64e0bd6fL, 0x018701d7L, 0xb8bfd64aL, 0xddd86af2L, 0x3377dfe0L,
+ 0x56106358L, 0x9f571950L, 0xfa30a5e8L, 0x149f10faL, 0x71f8ac42L,
+ 0xc8c07bdfL, 0xada7c767L, 0x43087275L, 0x266fcecdL, 0x707fad95L,
+ 0x1518112dL, 0xfbb7a43fL, 0x9ed01887L, 0x27e8cf1aL, 0x428f73a2L,
+ 0xac20c6b0L, 0xc9477a08L, 0x3eaf32a0L, 0x5bc88e18L, 0xb5673b0aL,
+ 0xd00087b2L, 0x6938502fL, 0x0c5fec97L, 0xe2f05985L, 0x8797e53dL,
+ 0xd1878665L, 0xb4e03addL, 0x5a4f8fcfL, 0x3f283377L, 0x8610e4eaL,
+ 0xe3775852L, 0x0dd8ed40L, 0x68bf51f8L, 0xa1f82bf0L, 0xc49f9748L,
+ 0x2a30225aL, 0x4f579ee2L, 0xf66f497fL, 0x9308f5c7L, 0x7da740d5L,
+ 0x18c0fc6dL, 0x4ed09f35L, 0x2bb7238dL, 0xc518969fL, 0xa07f2a27L,
+ 0x1947fdbaL, 0x7c204102L, 0x928ff410L, 0xf7e848a8L, 0x3d58149bL,
+ 0x583fa823L, 0xb6901d31L, 0xd3f7a189L, 0x6acf7614L, 0x0fa8caacL,
+ 0xe1077fbeL, 0x8460c306L, 0xd270a05eL, 0xb7171ce6L, 0x59b8a9f4L,
+ 0x3cdf154cL, 0x85e7c2d1L, 0xe0807e69L, 0x0e2fcb7bL, 0x6b4877c3L,
+ 0xa20f0dcbL, 0xc768b173L, 0x29c70461L, 0x4ca0b8d9L, 0xf5986f44L,
+ 0x90ffd3fcL, 0x7e5066eeL, 0x1b37da56L, 0x4d27b90eL, 0x284005b6L,
+ 0xc6efb0a4L, 0xa3880c1cL, 0x1ab0db81L, 0x7fd76739L, 0x9178d22bL,
+ 0xf41f6e93L, 0x03f7263bL, 0x66909a83L, 0x883f2f91L, 0xed589329L,
+ 0x546044b4L, 0x3107f80cL, 0xdfa84d1eL, 0xbacff1a6L, 0xecdf92feL,
+ 0x89b82e46L, 0x67179b54L, 0x027027ecL, 0xbb48f071L, 0xde2f4cc9L,
+ 0x3080f9dbL, 0x55e74563L, 0x9ca03f6bL, 0xf9c783d3L, 0x176836c1L,
+ 0x720f8a79L, 0xcb375de4L, 0xae50e15cL, 0x40ff544eL, 0x2598e8f6L,
+ 0x73888baeL, 0x16ef3716L, 0xf8408204L, 0x9d273ebcL, 0x241fe921L,
+ 0x41785599L, 0xafd7e08bL, 0xcab05c33L, 0x3bb659edL, 0x5ed1e555L,
+ 0xb07e5047L, 0xd519ecffL, 0x6c213b62L, 0x094687daL, 0xe7e932c8L,
+ 0x828e8e70L, 0xd49eed28L, 0xb1f95190L, 0x5f56e482L, 0x3a31583aL,
+ 0x83098fa7L, 0xe66e331fL, 0x08c1860dL, 0x6da63ab5L, 0xa4e140bdL,
+ 0xc186fc05L, 0x2f294917L, 0x4a4ef5afL, 0xf3762232L, 0x96119e8aL,
+ 0x78be2b98L, 0x1dd99720L, 0x4bc9f478L, 0x2eae48c0L, 0xc001fdd2L,
+ 0xa566416aL, 0x1c5e96f7L, 0x79392a4fL, 0x97969f5dL, 0xf2f123e5L,
+ 0x05196b4dL, 0x607ed7f5L, 0x8ed162e7L, 0xebb6de5fL, 0x528e09c2L,
+ 0x37e9b57aL, 0xd9460068L, 0xbc21bcd0L, 0xea31df88L, 0x8f566330L,
+ 0x61f9d622L, 0x049e6a9aL, 0xbda6bd07L, 0xd8c101bfL, 0x366eb4adL,
+ 0x53090815L, 0x9a4e721dL, 0xff29cea5L, 0x11867bb7L, 0x74e1c70fL,
+ 0xcdd91092L, 0xa8beac2aL, 0x46111938L, 0x2376a580L, 0x7566c6d8L,
+ 0x10017a60L, 0xfeaecf72L, 0x9bc973caL, 0x22f1a457L, 0x479618efL,
+ 0xa939adfdL, 0xcc5e1145L, 0x06ee4d76L, 0x6389f1ceL, 0x8d2644dcL,
+ 0xe841f864L, 0x51792ff9L, 0x341e9341L, 0xdab12653L, 0xbfd69aebL,
+ 0xe9c6f9b3L, 0x8ca1450bL, 0x620ef019L, 0x07694ca1L, 0xbe519b3cL,
+ 0xdb362784L, 0x35999296L, 0x50fe2e2eL, 0x99b95426L, 0xfcdee89eL,
+ 0x12715d8cL, 0x7716e134L, 0xce2e36a9L, 0xab498a11L, 0x45e63f03L,
+ 0x208183bbL, 0x7691e0e3L, 0x13f65c5bL, 0xfd59e949L, 0x983e55f1L,
+ 0x2106826cL, 0x44613ed4L, 0xaace8bc6L, 0xcfa9377eL, 0x38417fd6L,
+ 0x5d26c36eL, 0xb389767cL, 0xd6eecac4L, 0x6fd61d59L, 0x0ab1a1e1L,
+ 0xe41e14f3L, 0x8179a84bL, 0xd769cb13L, 0xb20e77abL, 0x5ca1c2b9L,
+ 0x39c67e01L, 0x80fea99cL, 0xe5991524L, 0x0b36a036L, 0x6e511c8eL,
+ 0xa7166686L, 0xc271da3eL, 0x2cde6f2cL, 0x49b9d394L, 0xf0810409L,
+ 0x95e6b8b1L, 0x7b490da3L, 0x1e2eb11bL, 0x483ed243L, 0x2d596efbL,
+ 0xc3f6dbe9L, 0xa6916751L, 0x1fa9b0ccL, 0x7ace0c74L, 0x9461b966L,
+ 0xf10605deL
+# endif /* IZ_CRCOPTIM_UNFOLDTBL */
+# else /* !IZ_CRC_BE_OPTIMIZ */
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+ ,
+ 0x00000000L, 0x191b3141L, 0x32366282L, 0x2b2d53c3L, 0x646cc504L,
+ 0x7d77f445L, 0x565aa786L, 0x4f4196c7L, 0xc8d98a08L, 0xd1c2bb49L,
+ 0xfaefe88aL, 0xe3f4d9cbL, 0xacb54f0cL, 0xb5ae7e4dL, 0x9e832d8eL,
+ 0x87981ccfL, 0x4ac21251L, 0x53d92310L, 0x78f470d3L, 0x61ef4192L,
+ 0x2eaed755L, 0x37b5e614L, 0x1c98b5d7L, 0x05838496L, 0x821b9859L,
+ 0x9b00a918L, 0xb02dfadbL, 0xa936cb9aL, 0xe6775d5dL, 0xff6c6c1cL,
+ 0xd4413fdfL, 0xcd5a0e9eL, 0x958424a2L, 0x8c9f15e3L, 0xa7b24620L,
+ 0xbea97761L, 0xf1e8e1a6L, 0xe8f3d0e7L, 0xc3de8324L, 0xdac5b265L,
+ 0x5d5daeaaL, 0x44469febL, 0x6f6bcc28L, 0x7670fd69L, 0x39316baeL,
+ 0x202a5aefL, 0x0b07092cL, 0x121c386dL, 0xdf4636f3L, 0xc65d07b2L,
+ 0xed705471L, 0xf46b6530L, 0xbb2af3f7L, 0xa231c2b6L, 0x891c9175L,
+ 0x9007a034L, 0x179fbcfbL, 0x0e848dbaL, 0x25a9de79L, 0x3cb2ef38L,
+ 0x73f379ffL, 0x6ae848beL, 0x41c51b7dL, 0x58de2a3cL, 0xf0794f05L,
+ 0xe9627e44L, 0xc24f2d87L, 0xdb541cc6L, 0x94158a01L, 0x8d0ebb40L,
+ 0xa623e883L, 0xbf38d9c2L, 0x38a0c50dL, 0x21bbf44cL, 0x0a96a78fL,
+ 0x138d96ceL, 0x5ccc0009L, 0x45d73148L, 0x6efa628bL, 0x77e153caL,
+ 0xbabb5d54L, 0xa3a06c15L, 0x888d3fd6L, 0x91960e97L, 0xded79850L,
+ 0xc7cca911L, 0xece1fad2L, 0xf5facb93L, 0x7262d75cL, 0x6b79e61dL,
+ 0x4054b5deL, 0x594f849fL, 0x160e1258L, 0x0f152319L, 0x243870daL,
+ 0x3d23419bL, 0x65fd6ba7L, 0x7ce65ae6L, 0x57cb0925L, 0x4ed03864L,
+ 0x0191aea3L, 0x188a9fe2L, 0x33a7cc21L, 0x2abcfd60L, 0xad24e1afL,
+ 0xb43fd0eeL, 0x9f12832dL, 0x8609b26cL, 0xc94824abL, 0xd05315eaL,
+ 0xfb7e4629L, 0xe2657768L, 0x2f3f79f6L, 0x362448b7L, 0x1d091b74L,
+ 0x04122a35L, 0x4b53bcf2L, 0x52488db3L, 0x7965de70L, 0x607eef31L,
+ 0xe7e6f3feL, 0xfefdc2bfL, 0xd5d0917cL, 0xcccba03dL, 0x838a36faL,
+ 0x9a9107bbL, 0xb1bc5478L, 0xa8a76539L, 0x3b83984bL, 0x2298a90aL,
+ 0x09b5fac9L, 0x10aecb88L, 0x5fef5d4fL, 0x46f46c0eL, 0x6dd93fcdL,
+ 0x74c20e8cL, 0xf35a1243L, 0xea412302L, 0xc16c70c1L, 0xd8774180L,
+ 0x9736d747L, 0x8e2de606L, 0xa500b5c5L, 0xbc1b8484L, 0x71418a1aL,
+ 0x685abb5bL, 0x4377e898L, 0x5a6cd9d9L, 0x152d4f1eL, 0x0c367e5fL,
+ 0x271b2d9cL, 0x3e001cddL, 0xb9980012L, 0xa0833153L, 0x8bae6290L,
+ 0x92b553d1L, 0xddf4c516L, 0xc4eff457L, 0xefc2a794L, 0xf6d996d5L,
+ 0xae07bce9L, 0xb71c8da8L, 0x9c31de6bL, 0x852aef2aL, 0xca6b79edL,
+ 0xd37048acL, 0xf85d1b6fL, 0xe1462a2eL, 0x66de36e1L, 0x7fc507a0L,
+ 0x54e85463L, 0x4df36522L, 0x02b2f3e5L, 0x1ba9c2a4L, 0x30849167L,
+ 0x299fa026L, 0xe4c5aeb8L, 0xfdde9ff9L, 0xd6f3cc3aL, 0xcfe8fd7bL,
+ 0x80a96bbcL, 0x99b25afdL, 0xb29f093eL, 0xab84387fL, 0x2c1c24b0L,
+ 0x350715f1L, 0x1e2a4632L, 0x07317773L, 0x4870e1b4L, 0x516bd0f5L,
+ 0x7a468336L, 0x635db277L, 0xcbfad74eL, 0xd2e1e60fL, 0xf9ccb5ccL,
+ 0xe0d7848dL, 0xaf96124aL, 0xb68d230bL, 0x9da070c8L, 0x84bb4189L,
+ 0x03235d46L, 0x1a386c07L, 0x31153fc4L, 0x280e0e85L, 0x674f9842L,
+ 0x7e54a903L, 0x5579fac0L, 0x4c62cb81L, 0x8138c51fL, 0x9823f45eL,
+ 0xb30ea79dL, 0xaa1596dcL, 0xe554001bL, 0xfc4f315aL, 0xd7626299L,
+ 0xce7953d8L, 0x49e14f17L, 0x50fa7e56L, 0x7bd72d95L, 0x62cc1cd4L,
+ 0x2d8d8a13L, 0x3496bb52L, 0x1fbbe891L, 0x06a0d9d0L, 0x5e7ef3ecL,
+ 0x4765c2adL, 0x6c48916eL, 0x7553a02fL, 0x3a1236e8L, 0x230907a9L,
+ 0x0824546aL, 0x113f652bL, 0x96a779e4L, 0x8fbc48a5L, 0xa4911b66L,
+ 0xbd8a2a27L, 0xf2cbbce0L, 0xebd08da1L, 0xc0fdde62L, 0xd9e6ef23L,
+ 0x14bce1bdL, 0x0da7d0fcL, 0x268a833fL, 0x3f91b27eL, 0x70d024b9L,
+ 0x69cb15f8L, 0x42e6463bL, 0x5bfd777aL, 0xdc656bb5L, 0xc57e5af4L,
+ 0xee530937L, 0xf7483876L, 0xb809aeb1L, 0xa1129ff0L, 0x8a3fcc33L,
+ 0x9324fd72L
+ ,
+ 0x00000000L, 0x01c26a37L, 0x0384d46eL, 0x0246be59L, 0x0709a8dcL,
+ 0x06cbc2ebL, 0x048d7cb2L, 0x054f1685L, 0x0e1351b8L, 0x0fd13b8fL,
+ 0x0d9785d6L, 0x0c55efe1L, 0x091af964L, 0x08d89353L, 0x0a9e2d0aL,
+ 0x0b5c473dL, 0x1c26a370L, 0x1de4c947L, 0x1fa2771eL, 0x1e601d29L,
+ 0x1b2f0bacL, 0x1aed619bL, 0x18abdfc2L, 0x1969b5f5L, 0x1235f2c8L,
+ 0x13f798ffL, 0x11b126a6L, 0x10734c91L, 0x153c5a14L, 0x14fe3023L,
+ 0x16b88e7aL, 0x177ae44dL, 0x384d46e0L, 0x398f2cd7L, 0x3bc9928eL,
+ 0x3a0bf8b9L, 0x3f44ee3cL, 0x3e86840bL, 0x3cc03a52L, 0x3d025065L,
+ 0x365e1758L, 0x379c7d6fL, 0x35dac336L, 0x3418a901L, 0x3157bf84L,
+ 0x3095d5b3L, 0x32d36beaL, 0x331101ddL, 0x246be590L, 0x25a98fa7L,
+ 0x27ef31feL, 0x262d5bc9L, 0x23624d4cL, 0x22a0277bL, 0x20e69922L,
+ 0x2124f315L, 0x2a78b428L, 0x2bbade1fL, 0x29fc6046L, 0x283e0a71L,
+ 0x2d711cf4L, 0x2cb376c3L, 0x2ef5c89aL, 0x2f37a2adL, 0x709a8dc0L,
+ 0x7158e7f7L, 0x731e59aeL, 0x72dc3399L, 0x7793251cL, 0x76514f2bL,
+ 0x7417f172L, 0x75d59b45L, 0x7e89dc78L, 0x7f4bb64fL, 0x7d0d0816L,
+ 0x7ccf6221L, 0x798074a4L, 0x78421e93L, 0x7a04a0caL, 0x7bc6cafdL,
+ 0x6cbc2eb0L, 0x6d7e4487L, 0x6f38fadeL, 0x6efa90e9L, 0x6bb5866cL,
+ 0x6a77ec5bL, 0x68315202L, 0x69f33835L, 0x62af7f08L, 0x636d153fL,
+ 0x612bab66L, 0x60e9c151L, 0x65a6d7d4L, 0x6464bde3L, 0x662203baL,
+ 0x67e0698dL, 0x48d7cb20L, 0x4915a117L, 0x4b531f4eL, 0x4a917579L,
+ 0x4fde63fcL, 0x4e1c09cbL, 0x4c5ab792L, 0x4d98dda5L, 0x46c49a98L,
+ 0x4706f0afL, 0x45404ef6L, 0x448224c1L, 0x41cd3244L, 0x400f5873L,
+ 0x4249e62aL, 0x438b8c1dL, 0x54f16850L, 0x55330267L, 0x5775bc3eL,
+ 0x56b7d609L, 0x53f8c08cL, 0x523aaabbL, 0x507c14e2L, 0x51be7ed5L,
+ 0x5ae239e8L, 0x5b2053dfL, 0x5966ed86L, 0x58a487b1L, 0x5deb9134L,
+ 0x5c29fb03L, 0x5e6f455aL, 0x5fad2f6dL, 0xe1351b80L, 0xe0f771b7L,
+ 0xe2b1cfeeL, 0xe373a5d9L, 0xe63cb35cL, 0xe7fed96bL, 0xe5b86732L,
+ 0xe47a0d05L, 0xef264a38L, 0xeee4200fL, 0xeca29e56L, 0xed60f461L,
+ 0xe82fe2e4L, 0xe9ed88d3L, 0xebab368aL, 0xea695cbdL, 0xfd13b8f0L,
+ 0xfcd1d2c7L, 0xfe976c9eL, 0xff5506a9L, 0xfa1a102cL, 0xfbd87a1bL,
+ 0xf99ec442L, 0xf85cae75L, 0xf300e948L, 0xf2c2837fL, 0xf0843d26L,
+ 0xf1465711L, 0xf4094194L, 0xf5cb2ba3L, 0xf78d95faL, 0xf64fffcdL,
+ 0xd9785d60L, 0xd8ba3757L, 0xdafc890eL, 0xdb3ee339L, 0xde71f5bcL,
+ 0xdfb39f8bL, 0xddf521d2L, 0xdc374be5L, 0xd76b0cd8L, 0xd6a966efL,
+ 0xd4efd8b6L, 0xd52db281L, 0xd062a404L, 0xd1a0ce33L, 0xd3e6706aL,
+ 0xd2241a5dL, 0xc55efe10L, 0xc49c9427L, 0xc6da2a7eL, 0xc7184049L,
+ 0xc25756ccL, 0xc3953cfbL, 0xc1d382a2L, 0xc011e895L, 0xcb4dafa8L,
+ 0xca8fc59fL, 0xc8c97bc6L, 0xc90b11f1L, 0xcc440774L, 0xcd866d43L,
+ 0xcfc0d31aL, 0xce02b92dL, 0x91af9640L, 0x906dfc77L, 0x922b422eL,
+ 0x93e92819L, 0x96a63e9cL, 0x976454abL, 0x9522eaf2L, 0x94e080c5L,
+ 0x9fbcc7f8L, 0x9e7eadcfL, 0x9c381396L, 0x9dfa79a1L, 0x98b56f24L,
+ 0x99770513L, 0x9b31bb4aL, 0x9af3d17dL, 0x8d893530L, 0x8c4b5f07L,
+ 0x8e0de15eL, 0x8fcf8b69L, 0x8a809decL, 0x8b42f7dbL, 0x89044982L,
+ 0x88c623b5L, 0x839a6488L, 0x82580ebfL, 0x801eb0e6L, 0x81dcdad1L,
+ 0x8493cc54L, 0x8551a663L, 0x8717183aL, 0x86d5720dL, 0xa9e2d0a0L,
+ 0xa820ba97L, 0xaa6604ceL, 0xaba46ef9L, 0xaeeb787cL, 0xaf29124bL,
+ 0xad6fac12L, 0xacadc625L, 0xa7f18118L, 0xa633eb2fL, 0xa4755576L,
+ 0xa5b73f41L, 0xa0f829c4L, 0xa13a43f3L, 0xa37cfdaaL, 0xa2be979dL,
+ 0xb5c473d0L, 0xb40619e7L, 0xb640a7beL, 0xb782cd89L, 0xb2cddb0cL,
+ 0xb30fb13bL, 0xb1490f62L, 0xb08b6555L, 0xbbd72268L, 0xba15485fL,
+ 0xb853f606L, 0xb9919c31L, 0xbcde8ab4L, 0xbd1ce083L, 0xbf5a5edaL,
+ 0xbe9834edL
+ ,
+ 0x00000000L, 0xb8bc6765L, 0xaa09c88bL, 0x12b5afeeL, 0x8f629757L,
+ 0x37def032L, 0x256b5fdcL, 0x9dd738b9L, 0xc5b428efL, 0x7d084f8aL,
+ 0x6fbde064L, 0xd7018701L, 0x4ad6bfb8L, 0xf26ad8ddL, 0xe0df7733L,
+ 0x58631056L, 0x5019579fL, 0xe8a530faL, 0xfa109f14L, 0x42acf871L,
+ 0xdf7bc0c8L, 0x67c7a7adL, 0x75720843L, 0xcdce6f26L, 0x95ad7f70L,
+ 0x2d111815L, 0x3fa4b7fbL, 0x8718d09eL, 0x1acfe827L, 0xa2738f42L,
+ 0xb0c620acL, 0x087a47c9L, 0xa032af3eL, 0x188ec85bL, 0x0a3b67b5L,
+ 0xb28700d0L, 0x2f503869L, 0x97ec5f0cL, 0x8559f0e2L, 0x3de59787L,
+ 0x658687d1L, 0xdd3ae0b4L, 0xcf8f4f5aL, 0x7733283fL, 0xeae41086L,
+ 0x525877e3L, 0x40edd80dL, 0xf851bf68L, 0xf02bf8a1L, 0x48979fc4L,
+ 0x5a22302aL, 0xe29e574fL, 0x7f496ff6L, 0xc7f50893L, 0xd540a77dL,
+ 0x6dfcc018L, 0x359fd04eL, 0x8d23b72bL, 0x9f9618c5L, 0x272a7fa0L,
+ 0xbafd4719L, 0x0241207cL, 0x10f48f92L, 0xa848e8f7L, 0x9b14583dL,
+ 0x23a83f58L, 0x311d90b6L, 0x89a1f7d3L, 0x1476cf6aL, 0xaccaa80fL,
+ 0xbe7f07e1L, 0x06c36084L, 0x5ea070d2L, 0xe61c17b7L, 0xf4a9b859L,
+ 0x4c15df3cL, 0xd1c2e785L, 0x697e80e0L, 0x7bcb2f0eL, 0xc377486bL,
+ 0xcb0d0fa2L, 0x73b168c7L, 0x6104c729L, 0xd9b8a04cL, 0x446f98f5L,
+ 0xfcd3ff90L, 0xee66507eL, 0x56da371bL, 0x0eb9274dL, 0xb6054028L,
+ 0xa4b0efc6L, 0x1c0c88a3L, 0x81dbb01aL, 0x3967d77fL, 0x2bd27891L,
+ 0x936e1ff4L, 0x3b26f703L, 0x839a9066L, 0x912f3f88L, 0x299358edL,
+ 0xb4446054L, 0x0cf80731L, 0x1e4da8dfL, 0xa6f1cfbaL, 0xfe92dfecL,
+ 0x462eb889L, 0x549b1767L, 0xec277002L, 0x71f048bbL, 0xc94c2fdeL,
+ 0xdbf98030L, 0x6345e755L, 0x6b3fa09cL, 0xd383c7f9L, 0xc1366817L,
+ 0x798a0f72L, 0xe45d37cbL, 0x5ce150aeL, 0x4e54ff40L, 0xf6e89825L,
+ 0xae8b8873L, 0x1637ef16L, 0x048240f8L, 0xbc3e279dL, 0x21e91f24L,
+ 0x99557841L, 0x8be0d7afL, 0x335cb0caL, 0xed59b63bL, 0x55e5d15eL,
+ 0x47507eb0L, 0xffec19d5L, 0x623b216cL, 0xda874609L, 0xc832e9e7L,
+ 0x708e8e82L, 0x28ed9ed4L, 0x9051f9b1L, 0x82e4565fL, 0x3a58313aL,
+ 0xa78f0983L, 0x1f336ee6L, 0x0d86c108L, 0xb53aa66dL, 0xbd40e1a4L,
+ 0x05fc86c1L, 0x1749292fL, 0xaff54e4aL, 0x322276f3L, 0x8a9e1196L,
+ 0x982bbe78L, 0x2097d91dL, 0x78f4c94bL, 0xc048ae2eL, 0xd2fd01c0L,
+ 0x6a4166a5L, 0xf7965e1cL, 0x4f2a3979L, 0x5d9f9697L, 0xe523f1f2L,
+ 0x4d6b1905L, 0xf5d77e60L, 0xe762d18eL, 0x5fdeb6ebL, 0xc2098e52L,
+ 0x7ab5e937L, 0x680046d9L, 0xd0bc21bcL, 0x88df31eaL, 0x3063568fL,
+ 0x22d6f961L, 0x9a6a9e04L, 0x07bda6bdL, 0xbf01c1d8L, 0xadb46e36L,
+ 0x15080953L, 0x1d724e9aL, 0xa5ce29ffL, 0xb77b8611L, 0x0fc7e174L,
+ 0x9210d9cdL, 0x2aacbea8L, 0x38191146L, 0x80a57623L, 0xd8c66675L,
+ 0x607a0110L, 0x72cfaefeL, 0xca73c99bL, 0x57a4f122L, 0xef189647L,
+ 0xfdad39a9L, 0x45115eccL, 0x764dee06L, 0xcef18963L, 0xdc44268dL,
+ 0x64f841e8L, 0xf92f7951L, 0x41931e34L, 0x5326b1daL, 0xeb9ad6bfL,
+ 0xb3f9c6e9L, 0x0b45a18cL, 0x19f00e62L, 0xa14c6907L, 0x3c9b51beL,
+ 0x842736dbL, 0x96929935L, 0x2e2efe50L, 0x2654b999L, 0x9ee8defcL,
+ 0x8c5d7112L, 0x34e11677L, 0xa9362eceL, 0x118a49abL, 0x033fe645L,
+ 0xbb838120L, 0xe3e09176L, 0x5b5cf613L, 0x49e959fdL, 0xf1553e98L,
+ 0x6c820621L, 0xd43e6144L, 0xc68bceaaL, 0x7e37a9cfL, 0xd67f4138L,
+ 0x6ec3265dL, 0x7c7689b3L, 0xc4caeed6L, 0x591dd66fL, 0xe1a1b10aL,
+ 0xf3141ee4L, 0x4ba87981L, 0x13cb69d7L, 0xab770eb2L, 0xb9c2a15cL,
+ 0x017ec639L, 0x9ca9fe80L, 0x241599e5L, 0x36a0360bL, 0x8e1c516eL,
+ 0x866616a7L, 0x3eda71c2L, 0x2c6fde2cL, 0x94d3b949L, 0x090481f0L,
+ 0xb1b8e695L, 0xa30d497bL, 0x1bb12e1eL, 0x43d23e48L, 0xfb6e592dL,
+ 0xe9dbf6c3L, 0x516791a6L, 0xccb0a91fL, 0x740cce7aL, 0x66b96194L,
+ 0xde0506f1L
+# endif /* IZ_CRCOPTIM_UNFOLDTBL */
+# endif /* ? IZ_CRC_BE_OPTIMIZ */
+};
+#endif /* ?DYNAMIC_CRC_TABLE */
+
+/* use "OF((void))" here to work around a Borland TC++ 1.0 problem */
+#ifdef USE_ZLIB
+ZCONST uLongf *get_crc_table OF((void))
+#else
+ZCONST ulg near *get_crc_table OF((void))
+#endif
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (CRC_TABLE_IS_EMPTY)
+ make_crc_table();
+#endif
+#ifdef USE_ZLIB
+ return (ZCONST uLongf *)crc_table;
+#else
+ return crc_table;
+#endif
+}
+
+#ifdef DYNALLOC_CRCTAB
+void free_crc_table()
+{
+ if (!CRC_TABLE_IS_EMPTY)
+ {
+ nearfree((ulg near *)crc_table);
+ MARK_CRCTAB_EMPTY;
+ }
+}
+#endif
+
+#ifndef USE_ZLIB
+#ifndef CRC_TABLE_ONLY
+#ifndef ASM_CRC
+
+#define DO1(crc, buf) crc = CRC32(crc, *buf++, crc_32_tab)
+#define DO2(crc, buf) DO1(crc, buf); DO1(crc, buf)
+#define DO4(crc, buf) DO2(crc, buf); DO2(crc, buf)
+#define DO8(crc, buf) DO4(crc, buf); DO4(crc, buf)
+
+#if (defined(IZ_CRC_BE_OPTIMIZ) || defined(IZ_CRC_LE_OPTIMIZ))
+
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+# ifdef IZ_CRC_BE_OPTIMIZ
+# define DO_OPT4(c, buf4) c ^= *(buf4)++; \
+ c = crc_32_tab[c & 0xff] ^ crc_32_tab[256+((c>>8) & 0xff)] ^ \
+ crc_32_tab[2*256+((c>>16) & 0xff)] ^ crc_32_tab[3*256+(c>>24)]
+# else /* !IZ_CRC_BE_OPTIMIZ */
+# define DO_OPT4(c, buf4) c ^= *(buf4)++; \
+ c = crc_32_tab[3*256+(c & 0xff)] ^ crc_32_tab[2*256+((c>>8) & 0xff)] \
+ ^ crc_32_tab[256+((c>>16) & 0xff)] ^ crc_32_tab[c>>24]
+# endif /* ?IZ_CRC_BE_OPTIMIZ */
+# else /* !IZ_CRCOPTIM_UNFOLDTBL */
+# define DO_OPT4(c, buf4) c ^= *(buf4)++; \
+ c = CRC32UPD(c, crc_32_tab); \
+ c = CRC32UPD(c, crc_32_tab); \
+ c = CRC32UPD(c, crc_32_tab); \
+ c = CRC32UPD(c, crc_32_tab)
+# endif /* ?IZ_CRCOPTIM_UNFOLDTBL */
+
+# define DO_OPT16(crc, buf4) DO_OPT4(crc, buf4); DO_OPT4(crc, buf4); \
+ DO_OPT4(crc, buf4); DO_OPT4(crc, buf4);
+
+#endif /* (IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */
+
+
+/* ========================================================================= */
+ulg crc32(crc, buf, len)
+ ulg crc; /* crc shift register */
+ register ZCONST uch *buf; /* pointer to bytes to pump through */
+ extent len; /* number of bytes in buf[] */
+/* Run a set of bytes through the crc shift register. If buf is a NULL
+ pointer, then initialize the crc shift register contents instead.
+ Return the current crc in either case. */
+{
+ register z_uint4 c;
+ register ZCONST ulg near *crc_32_tab;
+
+ if (buf == NULL) return 0L;
+
+ crc_32_tab = get_crc_table();
+
+ c = (REV_BE((z_uint4)crc) ^ 0xffffffffL);
+
+#if (defined(IZ_CRC_BE_OPTIMIZ) || defined(IZ_CRC_LE_OPTIMIZ))
+ /* Align buf pointer to next DWORD boundary. */
+ while (len && ((ptrdiff_t)buf & 3)) {
+ DO1(c, buf);
+ len--;
+ }
+ {
+ ZCONST z_uint4 *buf4 = (ZCONST z_uint4 *)buf;
+ while (len >= 16) {
+ DO_OPT16(c, buf4);
+ len -= 16;
+ }
+ while (len >= 4) {
+ DO_OPT4(c, buf4);
+ len -= 4;
+ }
+ buf = (ZCONST uch *)buf4;
+ }
+#else /* !(IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */
+#ifndef NO_UNROLLED_LOOPS
+ while (len >= 8) {
+ DO8(c, buf);
+ len -= 8;
+ }
+#endif /* !NO_UNROLLED_LOOPS */
+#endif /* ?(IZ_CRC_BE_OPTIMIZ || IZ_CRC_LE_OPTIMIZ) */
+ if (len) do {
+ DO1(c, buf);
+ } while (--len);
+
+ return REV_BE(c) ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
+}
+#endif /* !ASM_CRC */
+#endif /* !CRC_TABLE_ONLY */
+#endif /* !USE_ZLIB */
+#endif /* !USE_ZLIB || USE_OWN_CRCTAB */
diff --git a/crc32.h b/crc32.h
new file mode 100644
index 0000000..83af240
--- /dev/null
+++ b/crc32.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* crc32.h -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef __crc32_h
+#define __crc32_h /* identifies this source module */
+
+/* This header should be read AFTER zip.h resp. unzip.h
+ * (the latter with UNZIP_INTERNAL defined...).
+ */
+
+#ifndef OF
+# define OF(a) a
+#endif
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+#ifdef DYNALLOC_CRCTAB
+ void free_crc_table OF((void));
+#endif
+#ifndef USE_ZLIB
+ ZCONST ulg near *get_crc_table OF((void));
+#endif
+#if (defined(USE_ZLIB) || defined(CRC_TABLE_ONLY))
+# ifdef IZ_CRC_BE_OPTIMIZ
+# undef IZ_CRC_BE_OPTIMIZ
+# endif
+#else /* !(USE_ZLIB || CRC_TABLE_ONLY) */
+ ulg crc32 OF((ulg crc, ZCONST uch *buf, extent len));
+#endif /* ?(USE_ZLIB || CRC_TABLE_ONLY) */
+
+#ifndef CRC_32_TAB
+# define CRC_32_TAB crc_32_tab
+#endif
+
+#ifdef CRC32
+# undef CRC32
+#endif
+#ifdef IZ_CRC_BE_OPTIMIZ
+# define CRC32UPD(c, crctab) (crctab[((c) >> 24)] ^ ((c) << 8))
+# define CRC32(c, b, crctab) (crctab[(((int)(c) >> 24) ^ (b))] ^ ((c) << 8))
+# define REV_BE(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+#else
+# define CRC32UPD(c, crctab) (crctab[((int)(c)) & 0xff] ^ ((c) >> 8))
+# define CRC32(c, b, crctab) (crctab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
+# define REV_BE(w) w
+#endif
+
+#endif /* !__crc32_h */
diff --git a/crc_i386.S b/crc_i386.S
new file mode 100644
index 0000000..38dbc86
--- /dev/null
+++ b/crc_i386.S
@@ -0,0 +1,304 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * crc_i386.S, optimized CRC calculation function for Zip and UnZip,
+ * created by Paul Kienitz and Christian Spieler. Last revised 07 Jan 2007.
+ *
+ * GRR 961110: incorporated Scott Field optimizations from win32/crc_i386.asm
+ * => overall 6% speedup in "unzip -tq" on 9MB zipfile (486-66)
+ *
+ * SPC 970402: revised for Rodney Brown's optimizations (32-bit-wide
+ * aligned reads for most of the data from buffer), can be
+ * disabled by defining the macro NO_32_BIT_LOADS
+ *
+ * SPC 971012: added Rodney Brown's additional tweaks for 32-bit-optimized
+ * CPUs (like the Pentium Pro, Pentium II, and probably some
+ * Pentium clones). This optimization is controlled by the
+ * preprocessor switch "__686" and is disabled by default.
+ * (This default is based on the assumption that most users
+ * do not yet work on a Pentium Pro or Pentium II machine ...)
+ *
+ * COS 050116: Enabled the 686 build by default, because there are hardly any
+ * pre-686 CPUs in serious use nowadays. (See SPC 970402 above.)
+ *
+ * SPC 060103: Updated code to incorporate newer optimizations found in zlib.
+ *
+ * SPC 070107: Added conditional switch to deactivate crc32() compilation.
+ *
+ * FLAT memory model assumed. Calling interface:
+ * - args are pushed onto the stack from right to left,
+ * - return value is given in the EAX register,
+ * - all other registers (with exception of EFLAGS) are preserved. (With
+ * GNU C 2.7.x, %edx and %ecx are `scratch' registers, but preserving
+ * them nevertheless adds only 4 single byte instructions.)
+ *
+ * This source generates the function
+ * ulg crc32(ulg crc, ZCONST uch *buf, extent len).
+ *
+ * Loop unrolling can be disabled by defining the macro NO_UNROLLED_LOOPS.
+ * This results in shorter code at the expense of reduced performance.
+ */
+
+/* This file is NOT used in conjunction with zlib, or when only creation of
+ * the basic CRC_32_Table (for other purpose) is requested.
+ */
+#if !defined(USE_ZLIB) && !defined(CRC_TABLE_ONLY)
+
+/* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
+ * external symbols with an underline character '_'.
+ */
+#if defined(NO_UNDERLINE) || defined(__ELF__)
+# define _crc32 crc32
+# define _get_crc_table get_crc_table
+#endif
+/* Use 16-byte alignment if your assembler supports it. Warning: gas
+ * uses a log(x) parameter (.align 4 means 16-byte alignment). On SVR4
+ * the parameter is a number of bytes.
+ */
+#ifndef ALIGNMENT
+# define ALIGNMENT .align 4,0x90
+#endif
+
+#if defined(i386) || defined(_i386) || defined(_I386) || defined(__i386)
+
+/* This version is for 386 Unix, OS/2, MSDOS in 32 bit mode (gcc & gas).
+ * Warning: it uses the AT&T syntax: mov source,dest
+ * This file is only optional. If you want to use the C version,
+ * remove -DASM_CRC from CFLAGS in Makefile and set OBJA to an empty string.
+ */
+
+ .file "crc_i386.S"
+
+#if !defined(PRE_686) && !defined(__686)
+ /* Optimize for Pentium Pro and compatible CPUs by default. */
+# define __686
+#endif
+
+#if defined(NO_STD_STACKFRAME) && defined(USE_STD_STACKFRAME)
+# undef USE_STACKFRAME
+#else
+ /* The default is to use standard stack frame entry, because it
+ * results in smaller code!
+ */
+# ifndef USE_STD_STACKFRAME
+# define USE_STD_STACKFRAME
+# endif
+#endif
+
+#ifdef USE_STD_STACKFRAME
+# define _STD_ENTRY pushl %ebp ; movl %esp,%ebp
+# define arg1 8(%ebp)
+# define arg2 12(%ebp)
+# define arg3 16(%ebp)
+# define _STD_LEAVE popl %ebp
+#else /* !USE_STD_STACKFRAME */
+# define _STD_ENTRY
+# define arg1 24(%esp)
+# define arg2 28(%esp)
+# define arg3 32(%esp)
+# define _STD_LEAVE
+#endif /* ?USE_STD_STACKFRAME */
+
+/*
+ * These two (three) macros make up the loop body of the CRC32 cruncher.
+ * registers modified:
+ * eax : crc value "c"
+ * esi : pointer to next data byte (or lword) "buf++"
+ * registers read:
+ * edi : pointer to base of crc_table array
+ * scratch registers:
+ * ebx : index into crc_table array
+ * (requires upper three bytes = 0 when __686 is undefined)
+ */
+#ifndef __686 /* optimize for 386, 486, Pentium */
+#define Do_CRC /* c = (c >> 8) ^ table[c & 0xFF] */\
+ movb %al, %bl ;/* tmp = c & 0xFF */\
+ shrl $8, %eax ;/* c = (c >> 8) */\
+ xorl (%edi, %ebx, 4), %eax ;/* c ^= table[tmp] */
+#else /* __686 : optimize for Pentium Pro and compatible CPUs */
+#define Do_CRC /* c = (c >> 8) ^ table[c & 0xFF] */\
+ movzbl %al, %ebx ;/* tmp = c & 0xFF */\
+ shrl $8, %eax ;/* c = (c >> 8) */\
+ xorl (%edi, %ebx, 4), %eax ;/* c ^=table[tmp] */
+#endif /* ?__686 */
+
+#define Do_CRC_byte /* c = (c >> 8) ^ table[(c^*buf++)&0xFF] */\
+ xorb (%esi), %al ;/* c ^= *buf */\
+ incl %esi ;/* buf++ */\
+ Do_CRC
+
+#define Do_CRC_byteof(ofs) /* c = (c >> 8) ^ table[(c^*buf++)&0xFF] */\
+ xorb ofs(%esi), %al ;/* c ^= *buf */\
+ incl %esi ;/* buf++ */\
+ Do_CRC
+
+#ifndef NO_32_BIT_LOADS
+# ifdef IZ_CRCOPTIM_UNFOLDTBL
+ /* the edx register is needed in crc calculation */
+# define SavLen arg3
+# define UpdCRC_lword \
+ movzbl %al, %ebx ; \
+ movl 3072(%edi,%ebx,4), %edx ; \
+ movzbl %ah, %ebx ; \
+ shrl $16, %eax ; \
+ xor 2048(%edi,%ebx,4), %edx ; \
+ movzbl %al, %ebx ; \
+ shrl $8,%eax ; \
+ xorl 1024(%edi,%ebx,4), %edx ; \
+ movl (%edi,%eax,4), %eax ; \
+ xorl %edx,%eax ;
+# define UpdCRC_lword_sh(dwPtrIncr) \
+ movzbl %al, %ebx ; \
+ movl 3072(%edi,%ebx,4), %edx ; \
+ movzbl %ah, %ebx ; \
+ shrl $16, %eax ; \
+ xor 2048(%edi,%ebx,4), %edx ; \
+ movzbl %al, %ebx ; \
+ addl $4*(dwPtrIncr), %esi ;/* ((ulg *)buf)+=dwPtrIncr */\
+ shrl $8,%eax ; \
+ xorl 1024(%edi,%ebx,4), %edx ; \
+ movl (%edi,%eax,4),%eax ; \
+ xorl %edx,%eax ;
+# else /* !IZ_CRCOPTIM_UNFOLDTBL */
+ /* the edx register is not needed anywhere else */
+# define SavLen %edx
+# define UpdCRC_lword \
+ Do_CRC \
+ Do_CRC \
+ Do_CRC \
+ Do_CRC
+# define UpdCRC_lword_sh(dwPtrIncr) \
+ Do_CRC \
+ Do_CRC \
+ addl $4*(dwPtrIncr), %esi ;/* ((ulg *)buf)++ */\
+ Do_CRC \
+ Do_CRC
+# endif /* ?IZ_CRCOPTIM_UNFOLDTBL */
+#define Do_CRC_lword \
+ xorl (%esi), %eax ;/* c ^= *(ulg *)buf */\
+ UpdCRC_lword_sh(1) /* ... ((ulg *)buf)++ */
+#define Do_CRC_4lword \
+ xorl (%esi), %eax ;/* c ^= *(ulg *)buf */\
+ UpdCRC_lword \
+ xorl 4(%esi), %eax ;/* c ^= *((ulg *)buf+1) */\
+ UpdCRC_lword \
+ xorl 8(%esi), %eax ;/* c ^= *((ulg *)buf+2) */\
+ UpdCRC_lword \
+ xorl 12(%esi), %eax ;/* c ^= *((ulg *)buf]+3 */\
+ UpdCRC_lword_sh(4) /* ... ((ulg *)buf)+=4 */
+#endif /* !NO_32_BIT_LOADS */
+
+
+ .text
+
+ .globl _crc32
+
+_crc32: /* ulg crc32(ulg crc, uch *buf, extent len) */
+ _STD_ENTRY
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %edx
+ pushl %ecx
+
+ movl arg2, %esi /* 2nd arg: uch *buf */
+ subl %eax, %eax /* > if (!buf) */
+ testl %esi, %esi /* > return 0; */
+ jz .L_fine /* > else { */
+ call _get_crc_table
+ movl %eax, %edi
+ movl arg1, %eax /* 1st arg: ulg crc */
+#ifndef __686
+ subl %ebx, %ebx /* ebx=0; bl usable as dword */
+#endif
+ movl arg3, %ecx /* 3rd arg: extent len */
+ notl %eax /* > c = ~crc; */
+
+ testl %ecx, %ecx
+#ifndef NO_UNROLLED_LOOPS
+ jz .L_bail
+# ifndef NO_32_BIT_LOADS
+ /* Assert now have positive length */
+.L_align_loop:
+ testl $3, %esi /* Align buf on lword boundary */
+ jz .L_aligned_now
+ Do_CRC_byte
+ decl %ecx
+ jnz .L_align_loop
+.L_aligned_now:
+# endif /* !NO_32_BIT_LOADS */
+ movl %ecx, SavLen /* save current value of len */
+ shrl $4, %ecx /* ecx = len / 16 */
+ jz .L_No_Sixteens
+/* align loop head at start of 486 internal cache line !! */
+ ALIGNMENT
+.L_Next_Sixteen:
+# ifndef NO_32_BIT_LOADS
+ Do_CRC_4lword
+# else /* NO_32_BIT_LOADS */
+ Do_CRC_byteof(0)
+ Do_CRC_byteof(1)
+ Do_CRC_byteof(2)
+ Do_CRC_byteof(3)
+ Do_CRC_byteof(4)
+ Do_CRC_byteof(5)
+ Do_CRC_byteof(6)
+ Do_CRC_byteof(7)
+ Do_CRC_byteof(8)
+ Do_CRC_byteof(9)
+ Do_CRC_byteof(10)
+ Do_CRC_byteof(11)
+ Do_CRC_byteof(12)
+ Do_CRC_byteof(13)
+ Do_CRC_byteof(14)
+ Do_CRC_byteof(15)
+ addl $16,%esi ;/* buf += 16 */
+# endif /* ?NO_32_BIT_LOADS */
+ decl %ecx
+ jnz .L_Next_Sixteen
+
+.L_No_Sixteens:
+ movl SavLen, %ecx
+ andl $15, %ecx /* ecx = len % 16 */
+# ifndef NO_32_BIT_LOADS
+ shrl $2,%ecx /* ecx = len / 4 */
+ jz .L_No_Fours
+.L_Next_Four:
+ Do_CRC_lword
+ decl %ecx
+ jnz .L_Next_Four
+.L_No_Fours:
+ movl SavLen,%ecx
+ andl $3,%ecx /* ecx = len % 4 */
+# endif /* !NO_32_BIT_LOADS */
+#endif /* !NO_UNROLLED_LOOPS */
+ jz .L_bail /* > if (len) */
+/* align loop head at start of 486 internal cache line !! */
+ ALIGNMENT
+.L_loupe: /* > do { */
+ Do_CRC_byte /* c = CRC32(c,*buf++,crctab);*/
+ decl %ecx /* > } while (--len); */
+ jnz .L_loupe
+
+.L_bail: /* > } */
+ notl %eax /* > return ~c; */
+.L_fine:
+ popl %ecx
+ popl %edx
+ popl %ebx
+ popl %esi
+ popl %edi
+ _STD_LEAVE
+ ret
+
+#else
+ error: this asm version is for 386 only
+#endif /* i386 || _i386 || _I386 || __i386 */
+
+#endif /* !USE_ZLIB && !CRC_TABLE_ONLY */
diff --git a/crypt.c b/crypt.c
new file mode 100644
index 0000000..cc974ec
--- /dev/null
+++ b/crypt.c
@@ -0,0 +1,690 @@
+/*
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h]
+
+ The main encryption/decryption source code for Info-Zip software was
+ originally written in Europe. To the best of our knowledge, it can
+ be freely distributed in both source and object forms from any country,
+ including the USA under License Exception TSU of the U.S. Export
+ Administration Regulations (section 740.13(e)) of 6 June 2002.
+
+ NOTE on copyright history:
+ Previous versions of this source package (up to version 2.8) were
+ not copyrighted and put in the public domain. If you cannot comply
+ with the Info-Zip LICENSE, you may want to look for one of those
+ public domain versions.
+ */
+
+/*
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+ */
+
+#define ZCRYPT_INTERNAL
+#include "zip.h"
+#include "crypt.h"
+#include "ttyio.h"
+
+#if CRYPT
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifdef ZIP
+ /* For the encoding task used in Zip (and ZipCloak), we want to initialize
+ the crypt algorithm with some reasonably unpredictable bytes, see
+ the crypthead() function. The standard rand() library function is
+ used to supply these `random' bytes, which in turn is initialized by
+ a srand() call. The srand() function takes an "unsigned" (at least 16bit)
+ seed value as argument to determine the starting point of the rand()
+ pseudo-random number generator.
+ This seed number is constructed as "Seed = Seed1 .XOR. Seed2" with
+ Seed1 supplied by the current time (= "(unsigned)time()") and Seed2
+ as some (hopefully) nondeterministic bitmask. On many (most) systems,
+ we use some "process specific" number, as the PID or something similar,
+ but when nothing unpredictable is available, a fixed number may be
+ sufficient.
+ NOTE:
+ 1.) This implementation requires the availability of the following
+ standard UNIX C runtime library functions: time(), rand(), srand().
+ On systems where some of them are missing, the environment that
+ incorporates the crypt routines must supply suitable replacement
+ functions.
+ 2.) It is a very bad idea to use a second call to time() to set the
+ "Seed2" number! In this case, both "Seed1" and "Seed2" would be
+ (almost) identical, resulting in a (mostly) "zero" constant seed
+ number passed to srand().
+
+ The implementation environment defined in the "zip.h" header should
+ supply a reasonable definition for ZCR_SEED2 (an unsigned number; for
+ most implementations of rand() and srand(), only the lower 16 bits are
+ significant!). An example that works on many systems would be
+ "#define ZCR_SEED2 (unsigned)getpid()".
+ The default definition for ZCR_SEED2 supplied below should be regarded
+ as a fallback to allow successful compilation in "beta state"
+ environments.
+ */
+# include <time.h> /* time() function supplies first part of crypt seed */
+ /* "last resort" source for second part of crypt seed pattern */
+# ifndef ZCR_SEED2
+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as default pattern */
+# endif
+# ifdef GLOBAL /* used in Amiga system headers, maybe others too */
+# undef GLOBAL
+# endif
+# define GLOBAL(g) g
+#else /* !ZIP */
+# define GLOBAL(g) G.g
+#endif /* ?ZIP */
+
+
+#ifdef UNZIP
+ /* char *key = (char *)NULL; moved to globals.h */
+# ifndef FUNZIP
+ local int testp OF((__GPRO__ ZCONST uch *h));
+ local int testkey OF((__GPRO__ ZCONST uch *h, ZCONST char *key));
+# endif
+#else /* def UNZIP */ /* moved to globals.h for UnZip */
+ local z_uint4 keys[3]; /* keys defining the pseudo-random sequence */
+#endif /* def UNZIP [else] */
+
+#ifndef Trace
+# ifdef CRYPT_DEBUG
+# define Trace(x) fprintf x
+# else
+# define Trace(x)
+# endif
+#endif
+
+#include "crc32.h"
+
+#ifdef IZ_CRC_BE_OPTIMIZ
+ local z_uint4 near crycrctab[256];
+ local z_uint4 near *cry_crctb_p = NULL;
+ local z_uint4 near *crytab_init OF((__GPRO));
+# define CRY_CRC_TAB cry_crctb_p
+# undef CRC32
+# define CRC32(c, b, crctab) (crctab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
+#else
+# define CRY_CRC_TAB CRC_32_TAB
+#endif /* ?IZ_CRC_BE_OPTIMIZ */
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+int decrypt_byte(__G)
+ __GDEF
+{
+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
+ * unpredictable manner on 16-bit systems; not a problem
+ * with any known compiler so far, though */
+
+ temp = ((unsigned)GLOBAL(keys[2]) & 0xffff) | 2;
+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+int update_keys(__G__ c)
+ __GDEF
+ int c; /* byte of plain text */
+{
+ GLOBAL(keys[0]) = CRC32(GLOBAL(keys[0]), c, CRY_CRC_TAB);
+ GLOBAL(keys[1]) = (GLOBAL(keys[1])
+ + (GLOBAL(keys[0]) & 0xff))
+ * 134775813L + 1;
+ {
+ register int keyshift = (int)(GLOBAL(keys[1]) >> 24);
+ GLOBAL(keys[2]) = CRC32(GLOBAL(keys[2]), keyshift, CRY_CRC_TAB);
+ }
+ return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+void init_keys(__G__ passwd)
+ __GDEF
+ ZCONST char *passwd; /* password string with which to modify keys */
+{
+#ifdef IZ_CRC_BE_OPTIMIZ
+ if (cry_crctb_p == NULL) {
+ cry_crctb_p = crytab_init(__G);
+ }
+#endif
+ GLOBAL(keys[0]) = 305419896L;
+ GLOBAL(keys[1]) = 591751049L;
+ GLOBAL(keys[2]) = 878082192L;
+ while (*passwd != '\0') {
+ update_keys(__G__ (int)*passwd);
+ passwd++;
+ }
+}
+
+
+/***********************************************************************
+ * Initialize the local copy of the table of precomputed crc32 values.
+ * Whereas the public crc32-table is optimized for crc32 calculations
+ * on arrays of bytes, the crypt code needs the crc32 values in an
+ * byte-order-independent form as 32-bit unsigned numbers. On systems
+ * with Big-Endian byte order using the optimized crc32 code, this
+ * requires inverting the byte-order of the values in the
+ * crypt-crc32-table.
+ */
+#ifdef IZ_CRC_BE_OPTIMIZ
+local z_uint4 near *crytab_init(__G)
+ __GDEF
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ crycrctab[i] = REV_BE(CRC_32_TAB[i]);
+ }
+ return crycrctab;
+}
+#endif
+
+
+#ifdef ZIP
+
+/***********************************************************************
+ * Write encryption header to file zfile using the password passwd
+ * and the cyclic redundancy check crc.
+ */
+void crypthead(passwd, crc)
+ ZCONST char *passwd; /* password string */
+ ulg crc; /* crc of file being encrypted */
+{
+ int n; /* index in random header */
+ int t; /* temporary */
+ int c; /* random byte */
+ uch header[RAND_HEAD_LEN]; /* random header */
+ static unsigned calls = 0; /* ensure different random header each time */
+
+ /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+ * output of rand() to get less predictability, since rand() is
+ * often poorly implemented.
+ */
+ if (++calls == 1) {
+ srand((unsigned)time(NULL) ^ ZCR_SEED2);
+ }
+ init_keys(passwd);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++) {
+ c = (rand() >> 7) & 0xff;
+ header[n] = (uch)zencode(c, t);
+ }
+ /* Encrypt random header (last two bytes is high word of crc) */
+ init_keys(passwd);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++) {
+ header[n] = (uch)zencode(header[n], t);
+ }
+ header[RAND_HEAD_LEN-2] = (uch)zencode((int)(crc >> 16) & 0xff, t);
+ header[RAND_HEAD_LEN-1] = (uch)zencode((int)(crc >> 24) & 0xff, t);
+ bfwrite(header, 1, RAND_HEAD_LEN, BFWRITE_DATA);
+}
+
+
+#ifdef UTIL
+
+/***********************************************************************
+ * Encrypt the zip entry described by z from file in_file to file y
+ * using the password passwd. Return an error code in the ZE_ class.
+ */
+int zipcloak(z, passwd)
+ struct zlist far *z; /* zip entry to encrypt */
+ ZCONST char *passwd; /* password string */
+{
+ int c; /* input byte */
+ int res; /* result code */
+ zoff_t n; /* holds offset and counts size */
+ int t; /* temporary */
+ struct zlist far *localz; /* local header */
+ uch buf[1024]; /* write buffer */
+ int b; /* bytes in buffer */
+
+ /* Set encrypted bit, clear extended local header bit and write local
+ header to output file */
+ if ((n = (zoff_t)zftello(y)) == (zoff_t)-1L) return ZE_TEMP;
+
+ /* assume this archive is one disk and the file is open */
+
+ /* read the local header */
+ res = readlocal(&localz, z);
+
+ /* update disk and offset */
+ z->dsk = 0;
+ z->off = n;
+
+ /* Set encryption and unset any extended local header */
+ z->flg |= 1, z->flg &= ~8;
+ localz->lflg |= 1, localz->lflg &= ~8;
+
+ /* Add size of encryption header */
+ localz->siz += RAND_HEAD_LEN;
+ z->siz = localz->siz;
+
+ /* Put the local header */
+ if ((res = putlocal(localz, PUTLOCAL_WRITE)) != ZE_OK) return res;
+
+ /* Initialize keys with password and write random header */
+ crypthead(passwd, localz->crc);
+
+ /* Encrypt data */
+ b = 0;
+ for (n = z->siz - RAND_HEAD_LEN; n; n--) {
+ if ((c = getc(in_file)) == EOF) {
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ buf[b] = (uch)zencode(c, t);
+ b++;
+ if (b >= 1024) {
+ /* write the buffer */
+ bfwrite(buf, 1, b, BFWRITE_DATA);
+ b = 0;
+ }
+ }
+ if (b) {
+ /* write the buffer */
+ bfwrite(buf, 1, b, BFWRITE_DATA);
+ b = 0;
+ }
+
+ /* Since we seek to the start of each local header can skip
+ reading any extended local header */
+ /*
+ if ((flag & 8) != 0 && zfseeko(in_file, 16L, SEEK_CUR)) {
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ if (fflush(y) == EOF) return ZE_TEMP;
+ */
+
+ /* Update number of bytes written to output file */
+ tempzn += (4 + LOCHEAD) + localz->nam + localz->ext + localz->siz;
+
+ /* Free local header */
+ if (localz->ext) free(localz->extra);
+ if (localz->nam) free(localz->iname);
+ if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+ if (localz->uname) free(localz->uname);
+#endif
+ free(localz);
+
+ return ZE_OK;
+}
+
+/***********************************************************************
+ * Decrypt the zip entry described by z from file in_file to file y
+ * using the password passwd. Return an error code in the ZE_ class.
+ */
+int zipbare(z, passwd)
+ struct zlist far *z; /* zip entry to encrypt */
+ ZCONST char *passwd; /* password string */
+{
+#ifdef ZIP10
+ int c0 /* byte preceding the last input byte */
+#endif
+ int c1; /* last input byte */
+ /* all file offset and size now zoff_t - 8/28/04 EG */
+ zoff_t size; /* size of input data */
+ struct zlist far *localz; /* local header */
+ uch buf[1024]; /* write buffer */
+ int b; /* bytes in buffer */
+ zoff_t n;
+ int r; /* size of encryption header */
+ int res; /* return code */
+
+ /* Save position */
+ if ((n = (zoff_t)zftello(y)) == (zoff_t)-1L) return ZE_TEMP;
+
+ /* Read local header */
+ res = readlocal(&localz, z);
+
+ /* Update disk and offset */
+ z->dsk = 0;
+ z->off = n;
+
+ /* Initialize keys with password */
+ init_keys(passwd);
+
+ /* Decrypt encryption header, save last two bytes */
+ c1 = 0;
+ for (r = RAND_HEAD_LEN; r; r--) {
+#ifdef ZIP10
+ c0 = c1;
+#endif
+ if ((c1 = getc(in_file)) == EOF) {
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ Trace((stdout, " (%02x)", c1));
+ zdecode(c1);
+ Trace((stdout, " %02x", c1));
+ }
+ Trace((stdout, "\n"));
+
+ /* If last two bytes of header don't match crc (or file time in the
+ * case of an extended local header), back up and just copy. For
+ * pkzip 2.0, the check has been reduced to one byte only.
+ */
+#ifdef ZIP10
+ if ((ush)(c0 | (c1<<8)) !=
+ (z->flg & 8 ? (ush) z->tim & 0xffff : (ush)(z->crc >> 16))) {
+#else
+ if ((ush)c1 != (z->flg & 8 ? (ush) z->tim >> 8 : (ush)(z->crc >> 24))) {
+#endif
+ if (zfseeko(in_file, n, SEEK_SET)) {
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ if ((res = zipcopy(z)) != ZE_OK) {
+ ziperr(res, "was copying an entry");
+ }
+ return ZE_MISS;
+ }
+
+ z->siz -= RAND_HEAD_LEN;
+ localz->siz = z->siz;
+
+ localz->flg = z->flg &= ~9;
+ z->lflg = localz->lflg &= ~9;
+
+ if ((res = putlocal(localz, PUTLOCAL_WRITE)) != ZE_OK) return res;
+
+ /* Decrypt data */
+ b = 0;
+ for (size = z->siz; size; size--) {
+ if ((c1 = getc(in_file)) == EOF) {
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ zdecode(c1);
+ buf[b] = c1;
+ b++;
+ if (b >= 1024) {
+ /* write the buffer */
+ bfwrite(buf, 1, b, BFWRITE_DATA);
+ b = 0;
+ }
+ }
+ if (b) {
+ /* write the buffer */
+ bfwrite(buf, 1, b, BFWRITE_DATA);
+ b = 0;
+ }
+ /* Since we seek to the start of each local header can skip
+ reading any extended local header */
+
+ /* Update number of bytes written to output file */
+ tempzn += (4 + LOCHEAD) + localz->nam + localz->ext + localz->siz;
+
+ /* Free local header */
+ if (localz->ext) free(localz->extra);
+ if (localz->nam) free(localz->iname);
+ if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+ if (localz->uname) free(localz->uname);
+#endif
+ free(localz);
+
+ return ZE_OK;
+}
+
+
+#else /* !UTIL */
+
+/***********************************************************************
+ * If requested, encrypt the data in buf, and in any case call fwrite()
+ * with the arguments to zfwrite(). Return what fwrite() returns.
+ *
+ * now write to global y
+ *
+ * A bug has been found when encrypting large files that don't
+ * compress. See trees.c for the details and the fix.
+ */
+unsigned zfwrite(buf, item_size, nb)
+ zvoid *buf; /* data buffer */
+ extent item_size; /* size of each item in bytes */
+ extent nb; /* number of items */
+#if 0
+ FILE *f; /* file to write to */
+#endif
+{
+ int t; /* temporary */
+
+ if (key != (char *)NULL) { /* key is the global password pointer */
+ ulg size; /* buffer size */
+ char *p = (char *)buf; /* steps through buffer */
+
+ /* Encrypt data in buffer */
+ for (size = item_size*(ulg)nb; size != 0; p++, size--) {
+ *p = (char)zencode(*p, t);
+ }
+ }
+ /* Write the buffer out */
+ return bfwrite(buf, item_size, nb, BFWRITE_DATA);
+}
+
+#endif /* ?UTIL */
+#endif /* ZIP */
+
+
+#if (defined(UNZIP) && !defined(FUNZIP))
+
+/***********************************************************************
+ * Get the password and set up keys for current zipfile member.
+ * Return PK_ class error.
+ */
+int decrypt(__G__ passwrd)
+ __GDEF
+ ZCONST char *passwrd;
+{
+ ush b;
+ int n, r;
+ uch h[RAND_HEAD_LEN];
+
+ Trace((stdout, "\n[incnt = %d]: ", GLOBAL(incnt)));
+
+ /* get header once (turn off "encrypted" flag temporarily so we don't
+ * try to decrypt the same data twice) */
+ GLOBAL(pInfo->encrypted) = FALSE;
+ defer_leftover_input(__G);
+ for (n = 0; n < RAND_HEAD_LEN; n++) {
+ b = NEXTBYTE;
+ h[n] = (uch)b;
+ Trace((stdout, " (%02x)", h[n]));
+ }
+ undefer_input(__G);
+ GLOBAL(pInfo->encrypted) = TRUE;
+
+ if (GLOBAL(newzip)) { /* this is first encrypted member in this zipfile */
+ GLOBAL(newzip) = FALSE;
+ if (passwrd != (char *)NULL) { /* user gave password on command line */
+ if (!GLOBAL(key)) {
+ if ((GLOBAL(key) = (char *)malloc(strlen(passwrd)+1)) ==
+ (char *)NULL)
+ return PK_MEM2;
+ strcpy(GLOBAL(key), passwrd);
+ GLOBAL(nopwd) = TRUE; /* inhibit password prompting! */
+ }
+ } else if (GLOBAL(key)) { /* get rid of previous zipfile's key */
+ free(GLOBAL(key));
+ GLOBAL(key) = (char *)NULL;
+ }
+ }
+
+ /* if have key already, test it; else allocate memory for it */
+ if (GLOBAL(key)) {
+ if (!testp(__G__ h))
+ return PK_COOL; /* existing password OK (else prompt for new) */
+ else if (GLOBAL(nopwd))
+ return PK_WARN; /* user indicated no more prompting */
+ } else if ((GLOBAL(key) = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL)
+ return PK_MEM2;
+
+ /* try a few keys */
+ n = 0;
+ do {
+ r = (*G.decr_passwd)((zvoid *)&G, &n, GLOBAL(key), IZ_PWLEN+1,
+ GLOBAL(zipfn), GLOBAL(filename));
+ if (r == IZ_PW_ERROR) { /* internal error in fetch of PW */
+ free (GLOBAL(key));
+ GLOBAL(key) = NULL;
+ return PK_MEM2;
+ }
+ if (r != IZ_PW_ENTERED) { /* user replied "skip" or "skip all" */
+ *GLOBAL(key) = '\0'; /* We try the NIL password, ... */
+ n = 0; /* and cancel fetch for this item. */
+ }
+ if (!testp(__G__ h))
+ return PK_COOL;
+ if (r == IZ_PW_CANCELALL) /* User replied "Skip all" */
+ GLOBAL(nopwd) = TRUE; /* inhibit any further PW prompt! */
+ } while (n > 0);
+
+ return PK_WARN;
+
+} /* end function decrypt() */
+
+
+
+/***********************************************************************
+ * Test the password. Return -1 if bad, 0 if OK.
+ */
+local int testp(__G__ h)
+ __GDEF
+ ZCONST uch *h;
+{
+ int r;
+ char *key_translated;
+
+ /* On systems with "obscure" native character coding (e.g., EBCDIC),
+ * the first test translates the password to the "main standard"
+ * character coding. */
+
+#ifdef STR_TO_CP1
+ /* allocate buffer for translated password */
+ if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL)
+ return -1;
+ /* first try, test password translated "standard" charset */
+ r = testkey(__G__ h, STR_TO_CP1(key_translated, GLOBAL(key)));
+#else /* !STR_TO_CP1 */
+ /* first try, test password as supplied on the extractor's host */
+ r = testkey(__G__ h, GLOBAL(key));
+#endif /* ?STR_TO_CP1 */
+
+#ifdef STR_TO_CP2
+ if (r != 0) {
+#ifndef STR_TO_CP1
+ /* now prepare for second (and maybe third) test with translated pwd */
+ if ((key_translated = malloc(strlen(GLOBAL(key)) + 1)) == (char *)NULL)
+ return -1;
+#endif
+ /* second try, password translated to alternate ("standard") charset */
+ r = testkey(__G__ h, STR_TO_CP2(key_translated, GLOBAL(key)));
+#ifdef STR_TO_CP3
+ if (r != 0)
+ /* third try, password translated to another "standard" charset */
+ r = testkey(__G__ h, STR_TO_CP3(key_translated, GLOBAL(key)));
+#endif
+#ifndef STR_TO_CP1
+ free(key_translated);
+#endif
+ }
+#endif /* STR_TO_CP2 */
+
+#ifdef STR_TO_CP1
+ free(key_translated);
+ if (r != 0) {
+ /* last resort, test password as supplied on the extractor's host */
+ r = testkey(__G__ h, GLOBAL(key));
+ }
+#endif /* STR_TO_CP1 */
+
+ return r;
+
+} /* end function testp() */
+
+
+local int testkey(__G__ h, key)
+ __GDEF
+ ZCONST uch *h; /* decrypted header */
+ ZCONST char *key; /* decryption password to test */
+{
+ ush b;
+#ifdef ZIP10
+ ush c;
+#endif
+ int n;
+ uch *p;
+ uch hh[RAND_HEAD_LEN]; /* decrypted header */
+
+ /* set keys and save the encrypted header */
+ init_keys(__G__ key);
+ memcpy(hh, h, RAND_HEAD_LEN);
+
+ /* check password */
+ for (n = 0; n < RAND_HEAD_LEN; n++) {
+ zdecode(hh[n]);
+ Trace((stdout, " %02x", hh[n]));
+ }
+
+ /* use fzofft to format zoff_t as strings - 10/19/04 from SMS */
+ Trace((stdout,
+ "\n lrec.crc= %08lx crec.crc= %08lx pInfo->ExtLocHdr= %s\n",
+ GLOBAL(lrec.crc32), GLOBAL(pInfo->crc),
+ GLOBAL(pInfo->ExtLocHdr) ? "true":"false"));
+ Trace((stdout, " incnt = %d unzip offset into zipfile = %s\n",
+ GLOBAL(incnt),
+ fzofft(GLOBAL(cur_zipfile_bufstart)+(GLOBAL(inptr)-GLOBAL(inbuf)),
+ NULL, NULL)));
+
+ /* same test as in zipbare(): */
+
+#ifdef ZIP10 /* check two bytes */
+ c = hh[RAND_HEAD_LEN-2], b = hh[RAND_HEAD_LEN-1];
+ Trace((stdout,
+ " (c | (b<<8)) = %04x (crc >> 16) = %04x lrec.time = %04x\n",
+ (ush)(c | (b<<8)), (ush)(GLOBAL(lrec.crc32) >> 16),
+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff))));
+ if ((ush)(c | (b<<8)) != (GLOBAL(pInfo->ExtLocHdr) ?
+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) & 0xffff) :
+ (ush)(GLOBAL(lrec.crc32) >> 16)))
+ return -1; /* bad */
+#else
+ b = hh[RAND_HEAD_LEN-1];
+ Trace((stdout, " b = %02x (crc >> 24) = %02x (lrec.time >> 8) = %02x\n",
+ b, (ush)(GLOBAL(lrec.crc32) >> 24),
+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff));
+ if (b != (GLOBAL(pInfo->ExtLocHdr) ?
+ ((ush)GLOBAL(lrec.last_mod_dos_datetime) >> 8) & 0xff :
+ (ush)(GLOBAL(lrec.crc32) >> 24)))
+ return -1; /* bad */
+#endif
+ /* password OK: decrypt current buffer contents before leaving */
+ for (n = (zoff_t)GLOBAL(incnt) > GLOBAL(csize) ?
+ (int)GLOBAL(csize) : GLOBAL(incnt),
+ p = GLOBAL(inptr); n--; p++)
+ zdecode(*p);
+ return 0; /* OK */
+
+} /* end function testkey() */
+
+#endif /* UNZIP && !FUNZIP */
+
+#else /* !CRYPT */
+
+/* something "externally visible" to shut up compiler/linker warnings */
+int zcr_dummy;
+
+#endif /* ?CRYPT */
diff --git a/crypt.h b/crypt.h
new file mode 100644
index 0000000..61f3234
--- /dev/null
+++ b/crypt.h
@@ -0,0 +1,169 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ crypt.h (full version) by Info-ZIP. Last revised: [see CR_VERSION_DATE]
+
+ The main encryption/decryption source code for Info-Zip software was
+ originally written in Europe. To the best of our knowledge, it can
+ be freely distributed in both source and object forms from any country,
+ including the USA under License Exception TSU of the U.S. Export
+ Administration Regulations (section 740.13(e)) of 6 June 2002.
+
+ NOTE on copyright history:
+ Previous versions of this source package (up to version 2.8) were
+ not copyrighted and put in the public domain. If you cannot comply
+ with the Info-Zip LICENSE, you may want to look for one of those
+ public domain versions.
+ */
+
+#ifndef __crypt_h /* don't include more than once */
+#define __crypt_h
+
+#ifdef CRYPT
+# undef CRYPT
+#endif
+/*
+ Logic of selecting "full crypt" code:
+ a) default behaviour:
+ - dummy crypt code when compiling UnZipSFX stub, to minimize size
+ - full crypt code when used to compile Zip, UnZip and fUnZip
+ b) USE_CRYPT defined:
+ - always full crypt code
+ c) NO_CRYPT defined:
+ - never full crypt code
+ NO_CRYPT takes precedence over USE_CRYPT
+ */
+#if defined(NO_CRYPT)
+# define CRYPT 0 /* dummy version */
+#else
+#if defined(USE_CRYPT)
+# define CRYPT 1 /* full version */
+#else
+#if !defined(SFX)
+# define CRYPT 1 /* full version for zip and main unzip */
+#else
+# define CRYPT 0 /* dummy version for unzip sfx */
+#endif
+#endif /* ?USE_CRYPT */
+#endif /* ?NO_CRYPT */
+
+#if CRYPT
+/* full version */
+
+#ifdef CR_BETA
+# undef CR_BETA /* this is not a beta release */
+#endif
+
+#define CR_MAJORVER 2
+#define CR_MINORVER 91
+#ifdef CR_BETA
+# define CR_BETA_VER "c BETA"
+# define CR_VERSION_DATE "05 Jan 2007" /* last real code change */
+#else
+# define CR_BETA_VER ""
+# define CR_VERSION_DATE "05 Jan 2007" /* last public release date */
+# define CR_RELEASE
+#endif
+
+#ifndef __G /* UnZip only, for now (DLL stuff) */
+# define __G
+# define __G__
+# define __GDEF
+# define __GPRO void
+# define __GPRO__
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32)
+# ifndef DOS_OS2_W32
+# define DOS_OS2_W32
+# endif
+#endif
+
+#if defined(DOS_OS2_W32) || defined(__human68k__)
+# ifndef DOS_H68_OS2_W32
+# define DOS_H68_OS2_W32
+# endif
+#endif
+
+#if defined(VM_CMS) || defined(MVS)
+# ifndef CMS_MVS
+# define CMS_MVS
+# endif
+#endif
+
+/* To allow combining of Zip and UnZip static libraries in a single binary,
+ * the Zip and UnZip versions of the crypt core functions have to be named
+ * differently.
+ */
+#ifdef ZIP
+# ifdef REALLY_SHORT_SYMS
+# define decrypt_byte zdcrby
+# else
+# define decrypt_byte zp_decrypt_byte
+# endif
+# define update_keys zp_update_keys
+# define init_keys zp_init_keys
+#else /* !ZIP */
+# ifdef REALLY_SHORT_SYMS
+# define decrypt_byte dcrbyt
+# endif
+#endif /* ?ZIP */
+
+#define IZ_PWLEN 80 /* input buffer size for reading encryption key */
+#ifndef PWLEN /* for compatibility with previous zcrypt release... */
+# define PWLEN IZ_PWLEN
+#endif
+#define RAND_HEAD_LEN 12 /* length of encryption random header */
+
+/* the crc_32_tab array has to be provided externally for the crypt calculus */
+
+/* encode byte c, using temp t. Warning: c must not have side effects. */
+#define zencode(c,t) (t=decrypt_byte(__G), update_keys(c), t^(c))
+
+/* decode byte c in place */
+#define zdecode(c) update_keys(__G__ c ^= decrypt_byte(__G))
+
+int decrypt_byte OF((__GPRO));
+int update_keys OF((__GPRO__ int c));
+void init_keys OF((__GPRO__ ZCONST char *passwd));
+
+#ifdef ZIP
+ void crypthead OF((ZCONST char *, ulg));
+# ifdef UTIL
+ int zipcloak OF((struct zlist far *, ZCONST char *));
+ int zipbare OF((struct zlist far *, ZCONST char *));
+# else
+ unsigned zfwrite OF((zvoid *, extent, extent));
+ extern char *key;
+# endif
+#endif /* ZIP */
+
+#if (defined(UNZIP) && !defined(FUNZIP))
+ int decrypt OF((__GPRO__ ZCONST char *passwrd));
+#endif
+
+#ifdef FUNZIP
+ extern int encrypted;
+# ifdef NEXTBYTE
+# undef NEXTBYTE
+# endif
+# define NEXTBYTE \
+ (encrypted? update_keys(__G__ getc(G.in)^decrypt_byte(__G)) : getc(G.in))
+#endif /* FUNZIP */
+
+#else /* !CRYPT */
+/* dummy version */
+
+#define zencode
+#define zdecode
+
+#define zfwrite(b,s,c) bfwrite(b,s,c,BFWRITE_DATA)
+
+#endif /* ?CRYPT */
+#endif /* !__crypt_h */
diff --git a/deflate.c b/deflate.c
new file mode 100644
index 0000000..c830854
--- /dev/null
+++ b/deflate.c
@@ -0,0 +1,929 @@
+/*
+ deflate.c - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * deflate.c by Jean-loup Gailly.
+ *
+ * PURPOSE
+ *
+ * Identify new text as repetitions of old text within a fixed-
+ * length sliding window trailing behind the new text.
+ *
+ * DISCUSSION
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many info-zippers for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ * INTERFACE
+ *
+ * void lm_init (int pack_level, ush *flags)
+ * Initialize the "longest match" routines for a new file
+ *
+ * ulg deflate (void)
+ * Processes a new input file and return its compressed length. Sets
+ * the compressed length, crc, deflate flags and internal file
+ * attributes.
+ */
+
+#define __DEFLATE_C
+
+#include "zip.h"
+
+#ifndef USE_ZLIB
+
+/* ===========================================================================
+ * Configuration parameters
+ */
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+# define HASH_BITS 13 /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+# define HASH_BITS 14
+#endif
+#ifndef HASH_BITS
+# define HASH_BITS 15
+ /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#define FAST 4
+#define SLOW 2
+/* speed options for the general purpose bit flag */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#if (defined(ASMV) && !defined(MSDOS16) && defined(DYN_ALLOC))
+ error: DYN_ALLOC not yet supported in match.S or match32.asm
+#endif
+
+#ifdef MEMORY16
+# define MAXSEG_64K
+#endif
+
+/* ===========================================================================
+ * Local data used by the "longest match" routines.
+ */
+
+#if defined(MMAP) || defined(BIG_MEM)
+ typedef unsigned Pos; /* must be at least 32 bits */
+#else
+ typedef ush Pos;
+#endif
+typedef unsigned IPos;
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+#ifndef DYN_ALLOC
+ uch window[2L*WSIZE];
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least WSIZE
+ * bytes. With this organization, matches are limited to a distance of
+ * WSIZE-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: limit the window size to WSIZE+CBSZ if SMALL_MEM (the code would
+ * be less efficient since the data would have to be copied WSIZE/CBSZ times)
+ */
+ Pos prev[WSIZE];
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+ Pos head[HASH_SIZE];
+ /* Heads of the hash chains or NIL. If your compiler thinks that
+ * HASH_SIZE is a dynamic value, recompile with -DDYN_ALLOC.
+ */
+#else
+ uch far * near window = NULL;
+ Pos far * near prev = NULL;
+ Pos far * near head;
+#endif
+ulg window_size;
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+long block_start;
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+local int sliding;
+/* Set to false when the input file is already in memory */
+
+local unsigned ins_h; /* hash index of string to be inserted */
+
+#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_h must be shifted at each
+ * input step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+unsigned int near prev_length;
+/* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ unsigned near strstart; /* start of string to insert */
+ unsigned near match_start; /* start of matching string */
+local int eofile; /* flag set at end of input file */
+local unsigned lookahead; /* number of valid bytes ahead in window */
+
+unsigned near max_chain_length;
+/* To speed up deflation, hash chains are never searched beyond this length.
+ * A higher limit improves compression ratio but degrades the speed.
+ */
+
+local unsigned int max_lazy_match;
+/* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+#define max_insert_length max_lazy_match
+/* Insert new strings in the hash table only if the match length
+ * is not greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+unsigned near good_match;
+/* Use a faster search when the previous match is longer than this */
+
+#ifdef FULL_SEARCH
+# define nice_match MAX_MATCH
+#else
+ int near nice_match; /* Stop searching when current match exceeds this */
+#endif
+
+
+/* Values for max_lazy_match, good_match, nice_match and max_chain_length,
+ * depending on the desired pack level (0..9). The values given below have
+ * been tuned to exclude worst case performance for pathological files.
+ * Better values may be found for specific files.
+ */
+
+typedef struct config {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+} config;
+
+local config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0}, /* store only */
+/* 1 */ {4, 4, 8, 4}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8},
+/* 3 */ {4, 6, 32, 32},
+
+/* 4 */ {4, 4, 16, 16}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32},
+/* 6 */ {8, 16, 128, 128},
+/* 7 */ {8, 32, 128, 256},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ * Prototypes for local functions.
+ */
+
+local void fill_window OF((void));
+
+local uzoff_t deflate_fast OF((void)); /* now use uzoff_t 7/24/04 EG */
+
+ int longest_match OF((IPos cur_match));
+#if defined(ASMV) && !defined(RISCOS)
+ void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG
+local void check_match OF((IPos start, IPos match, int length));
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of s are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+ (UPDATE_HASH(ins_h, window[(s) + (MIN_MATCH-1)]), \
+ prev[(s) & WMASK] = match_head = head[ins_h], \
+ head[ins_h] = (s))
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ *
+ * IN assertion: window_size is > 0 if the input file is already read or
+ * mmap'ed in the window[] array, 0 otherwise. In the first case,
+ * window_size is sufficient to contain the whole input file plus
+ * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end
+ * of window[] when looking for matches towards the end).
+ */
+void lm_init (pack_level, flags)
+ int pack_level; /* 0: store, 1: best speed, 9: best compression */
+ ush *flags; /* general purpose bit flag */
+{
+ register unsigned j;
+
+ if (pack_level < 1 || pack_level > 9) error("bad pack level");
+
+ /* Do not slide the window if the whole input is already in memory
+ * (window_size > 0)
+ */
+ sliding = 0;
+ if (window_size == 0L) {
+ sliding = 1;
+ window_size = (ulg)2L*WSIZE;
+ }
+
+ /* Use dynamic allocation if compiler does not like big static arrays: */
+#ifdef DYN_ALLOC
+ if (window == NULL) {
+ window = (uch far *) zcalloc(WSIZE, 2*sizeof(uch));
+ if (window == NULL) ziperr(ZE_MEM, "window allocation");
+ }
+ if (prev == NULL) {
+ prev = (Pos far *) zcalloc(WSIZE, sizeof(Pos));
+ head = (Pos far *) zcalloc(HASH_SIZE, sizeof(Pos));
+ if (prev == NULL || head == NULL) {
+ ziperr(ZE_MEM, "hash table allocation");
+ }
+ }
+#endif /* DYN_ALLOC */
+
+ /* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+ head[HASH_SIZE-1] = NIL;
+ memset((char*)head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*head));
+
+ /* Set the default configuration parameters:
+ */
+ max_lazy_match = configuration_table[pack_level].max_lazy;
+ good_match = configuration_table[pack_level].good_length;
+#ifndef FULL_SEARCH
+ nice_match = configuration_table[pack_level].nice_length;
+#endif
+ max_chain_length = configuration_table[pack_level].max_chain;
+ if (pack_level <= 2) {
+ *flags |= FAST;
+ } else if (pack_level >= 8) {
+ *flags |= SLOW;
+ }
+ /* ??? reduce max_chain_length for binary files */
+
+ strstart = 0;
+ block_start = 0L;
+#if defined(ASMV) && !defined(RISCOS)
+ match_init(); /* initialize the asm code */
+#endif
+
+ j = WSIZE;
+#ifndef MAXSEG_64K
+ if (sizeof(int) > 2) j <<= 1; /* Can read 64K in one step */
+#endif
+ lookahead = (*read_buf)((char*)window, j);
+
+ if (lookahead == 0 || lookahead == (unsigned)EOF) {
+ eofile = 1, lookahead = 0;
+ return;
+ }
+ eofile = 0;
+ /* Make sure that we always have enough lookahead. This is important
+ * if input comes from a device such as a tty.
+ */
+ if (lookahead < MIN_LOOKAHEAD) fill_window();
+
+ ins_h = 0;
+ for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+ * not important since only literal bytes will be emitted.
+ */
+}
+
+/* ===========================================================================
+ * Free the window and hash table
+ */
+void lm_free()
+{
+#ifdef DYN_ALLOC
+ if (window != NULL) {
+ zcfree(window);
+ window = NULL;
+ }
+ if (prev != NULL) {
+ zcfree(prev);
+ zcfree(head);
+ prev = head = NULL;
+ }
+#endif /* DYN_ALLOC */
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0 and ARM, an optimized version is in match.asm or
+ * match.S. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+int longest_match(cur_match)
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = max_chain_length; /* max hash chain length */
+ register uch far *scan = window + strstart; /* current string */
+ register uch far *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = prev_length; /* best match length so far */
+ IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+
+/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+ error: Code too clever
+#endif
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register uch far *strend = window + strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ush far *)scan;
+ register ush scan_end = *(ush far *)(scan+best_len-1);
+#else
+ register uch far *strend = window + strstart + MAX_MATCH;
+ register uch scan_end1 = scan[best_len-1];
+ register uch scan_end = scan[best_len];
+#endif
+
+ /* Do not waste too much time if we already have a good match: */
+ if (prev_length >= good_match) {
+ chain_length >>= 2;
+ }
+
+ Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+ do {
+ Assert(cur_match < strstart, "no future");
+ match = window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ush far *)(match+best_len-1) != scan_end ||
+ *(ush far *)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ scan++, match++;
+ do {
+ } while (*(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+ *(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+ *(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+ *(ush far *)(scan+=2) == *(ush far *)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= window+(unsigned)(window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ush far *)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & WMASK]) > limit
+ && --chain_length != 0);
+
+ return best_len;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(start, match, length)
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (memcmp((char*)window + match,
+ (char*)window + start, length) != EQUAL) {
+ fprintf(mesg,
+ " start %d, match %d, length %d\n",
+ start, match, length);
+ error("invalid match");
+ }
+ if (verbose > 1) {
+ fprintf(mesg,"\\[%d,%d]", start-match, length);
+#ifndef WINDLL
+ do { putc(window[start++], mesg); } while (--length != 0);
+#else
+ do { fprintf(stdout,"%c",window[start++]); } while (--length != 0);
+#endif
+ }
+}
+#else
+# define check_match(start, match, length)
+#endif
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK(eof) \
+ flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
+ (char*)NULL, (ulg)strstart - (ulg)block_start, (eof))
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or eofile is set; file reads are
+ * performed for at least two bytes (required for the translate_eol option).
+ */
+local void fill_window()
+{
+ register unsigned n, m;
+ unsigned more; /* Amount of free space at the end of the window. */
+
+ do {
+ more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (more == (unsigned)EOF) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+
+ /* For MMAP or BIG_MEM, the whole input file is already in memory so
+ * we must not perform sliding. We must however call (*read_buf)() in
+ * order to compute the crc, update lookahead and possibly set eofile.
+ */
+ } else if (strstart >= WSIZE+MAX_DIST && sliding) {
+
+#ifdef FORCE_METHOD
+ /* When methods "stored" or "store_block" are requested, the
+ * current block must be flushed before sliding the window.
+ */
+ if (level <= 2) FLUSH_BLOCK(0), block_start = strstart;
+#endif
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
+ match_start -= WSIZE;
+ strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+ block_start -= (long) WSIZE;
+
+ for (n = 0; n < HASH_SIZE; n++) {
+ m = head[n];
+ head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+ }
+ for (n = 0; n < WSIZE; n++) {
+ m = prev[n];
+ prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ }
+ more += WSIZE;
+ if (dot_size > 0 && !display_globaldots) {
+ /* initial space */
+ if (noisy && dot_count == -1) {
+#ifndef WINDLL
+ putc(' ', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",' ');
+#endif
+ dot_count++;
+ }
+ dot_count++;
+ if (dot_size <= (dot_count + 1) * WSIZE) dot_count = 0;
+ }
+ if ((verbose || noisy) && dot_size && !dot_count) {
+#ifndef WINDLL
+ putc('.', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",'.');
+#endif
+ mesg_line_started = 1;
+ }
+ }
+ if (eofile) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the MMAP or BIG_MEM case (not yet supported in gzip),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = (*read_buf)((char*)window+strstart+lookahead, more);
+ if (n == 0 || n == (unsigned)EOF) {
+ eofile = 1;
+ } else {
+ lookahead += n;
+ }
+ } while (lookahead < MIN_LOOKAHEAD && !eofile);
+}
+
+/* ===========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local uzoff_t deflate_fast()
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int flush; /* set if current block must be flushed */
+ unsigned match_length = 0; /* length of best match */
+
+ prev_length = MIN_MATCH-1;
+ while (lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+#ifndef DEFL_UNDETERM
+ if (lookahead >= MIN_MATCH)
+#endif
+ INSERT_STRING(strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && strstart - hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifndef HUFFMAN_ONLY
+# ifndef DEFL_UNDETERM
+ /* Do not look for matches beyond the end of the input.
+ * This is necessary to make deflate deterministic.
+ */
+ if ((unsigned)nice_match > lookahead) nice_match = (int)lookahead;
+# endif
+ match_length = longest_match (hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > lookahead) match_length = lookahead;
+#endif
+ }
+ if (match_length >= MIN_MATCH) {
+ check_match(strstart, match_start, match_length);
+
+ flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
+
+ lookahead -= match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if (match_length <= max_insert_length
+#ifndef DEFL_UNDETERM
+ && lookahead >= MIN_MATCH
+#endif
+ ) {
+ match_length--; /* string at strstart already in hash table */
+ do {
+ strstart++;
+ INSERT_STRING(strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+#ifdef DEFL_UNDETERM
+ /* If lookahead < MIN_MATCH these bytes are garbage,
+ * but it does not matter since the next lookahead bytes
+ * will be emitted as literals.
+ */
+#endif
+ } while (--match_length != 0);
+ strstart++;
+ } else {
+ strstart += match_length;
+ match_length = 0;
+ ins_h = window[strstart];
+ UPDATE_HASH(ins_h, window[strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c",window[strstart]));
+ flush = ct_tally (0, window[strstart]);
+ lookahead--;
+ strstart++;
+ }
+ if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (lookahead < MIN_LOOKAHEAD) fill_window();
+ }
+ return FLUSH_BLOCK(1); /* eof */
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+uzoff_t deflate()
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ IPos prev_match; /* previous match */
+ int flush; /* set if current block must be flushed */
+ int match_available = 0; /* set if previous match exists */
+ register unsigned match_length = MIN_MATCH-1; /* length of best match */
+#ifdef DEBUG
+ extern uzoff_t isize; /* byte length of input file, for debug only */
+#endif
+
+ if (level <= 3) return deflate_fast(); /* optimized for speed */
+
+ /* Process the input block. */
+ while (lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+#ifndef DEFL_UNDETERM
+ if (lookahead >= MIN_MATCH)
+#endif
+ INSERT_STRING(strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ prev_length = match_length, prev_match = match_start;
+ match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && prev_length < max_lazy_match &&
+ strstart - hash_head <= MAX_DIST) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifndef HUFFMAN_ONLY
+# ifndef DEFL_UNDETERM
+ /* Do not look for matches beyond the end of the input.
+ * This is necessary to make deflate deterministic.
+ */
+ if ((unsigned)nice_match > lookahead) nice_match = (int)lookahead;
+# endif
+ match_length = longest_match (hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > lookahead) match_length = lookahead;
+#endif
+
+#ifdef FILTERED
+ /* Ignore matches of length <= 5 */
+ if (match_length <= 5) {
+#else
+ /* Ignore a length 3 match if it is too distant: */
+ if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
+#endif
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+#ifndef DEFL_UNDETERM
+ unsigned max_insert = strstart + lookahead - MIN_MATCH;
+
+#endif
+ check_match(strstart-1, prev_match, prev_length);
+
+ flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted.
+ */
+ lookahead -= prev_length-1;
+ prev_length -= 2;
+#ifndef DEFL_UNDETERM
+ do {
+ if (++strstart <= max_insert) {
+ INSERT_STRING(strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ }
+ } while (--prev_length != 0);
+ strstart++;
+#else /* DEFL_UNDETERM */
+ do {
+ strstart++;
+ INSERT_STRING(strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since the
+ * next lookahead bytes will always be emitted as literals.
+ */
+ } while (--prev_length != 0);
+ strstart++;
+#endif /* ?DEFL_UNDETERM */
+ match_available = 0;
+ match_length = MIN_MATCH-1;
+
+ if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+ } else if (match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c",window[strstart-1]));
+ if (ct_tally (0, window[strstart-1])) {
+ FLUSH_BLOCK(0), block_start = strstart;
+ }
+ strstart++;
+ lookahead--;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ match_available = 1;
+ strstart++;
+ lookahead--;
+ }
+ Assert(strstart <= isize && lookahead <= isize, "a bit too far");
+
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (lookahead < MIN_LOOKAHEAD) fill_window();
+ }
+ if (match_available) ct_tally (0, window[strstart-1]);
+
+ return FLUSH_BLOCK(1); /* eof */
+}
+#endif /* !USE_ZLIB */
diff --git a/ebcdic.h b/ebcdic.h
new file mode 100644
index 0000000..a52de1e
--- /dev/null
+++ b/ebcdic.h
@@ -0,0 +1,328 @@
+/*
+ ebcdic.h
+
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/licen
+*/
+/*---------------------------------------------------------------------------
+
+ ebcdic.h
+
+ The CECP 1047 (Extended de-facto EBCDIC) <-> ISO 8859-1 conversion tables,
+ from ftp://aix1.segi.ulg.ac.be/pub/docs/iso8859/iso8859.networking
+
+ NOTES:
+ <Paul_von_Behren@stortek.com> (OS/390 port 12/97)
+ These table no longer represent the standard mappings (for example in the
+ OS/390 iconv utility). In order to follow current standards I remapped
+ ebcdic x0a to ascii x15 and
+ ebcdic x85 to ascii x25 (and vice-versa)
+ Without these changes, newlines in auto-convert text files appeared
+ as literal \045.
+ I'm not sure what effect this remap would have on the MVS and CMS ports, so
+ I ifdef'd these changes. Hopefully these ifdef's can be removed when the
+ MVS/CMS folks test the new mappings.
+
+ Christian Spieler <spieler@ikp.tu-darmstadt.de>, 27-Apr-1998
+ The problem mentioned by Paul von Behren was already observed previously
+ on VM/CMS, during the preparation of the CMS&MVS port of UnZip 5.20 in
+ 1996. At that point, the ebcdic tables were not changed since they seemed
+ to be an adopted standard (to my knowledge, these tables are still used
+ as presented in mainfraime KERMIT). Instead, the "end-of-line" conversion
+ feature of Zip's and UnZip's "text-translation" mode was used to force
+ correct mappings between ASCII and EBCDIC newline markers.
+ Before interchanging the ASCII mappings of the EBCDIC control characters
+ "NL" 0x25 and "LF" 0x15 according to the OS/390 setting, we have to
+ make sure that EBCDIC 0x15 is never used as line termination.
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef __ebcdic_h /* prevent multiple inclusions */
+#define __ebcdic_h
+
+
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+#ifdef EBCDIC
+#ifndef MTS /* MTS uses a slightly "special" EBCDIC code page */
+
+ZCONST uch ebcdic[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, /* 00 - 07 */
+#ifdef OS390
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */
+#else
+ 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */
+#endif
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, /* 10 - 17 */
+ 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 27 */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, /* 28 - 2F */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 30 - 37 */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, /* 38 - 3F */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 47 */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, /* 48 - 4F */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, /* 50 - 57 */
+ 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, /* 58 - 5F */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60 - 67 */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 68 - 6F */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, /* 70 - 77 */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, /* 78 - 7F */
+#ifdef OS390
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17, /* 80 - 87 */
+#else
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, /* 80 - 87 */
+#endif
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, /* 88 - 8F */
+ 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, /* 90 - 97 */
+ 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, /* 98 - 9F */
+ 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, /* A0 - A7 */
+ 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, /* A8 - AF */
+ 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, /* B0 - B7 */
+ 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, /* B8 - BF */
+ 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, /* C0 - C7 */
+ 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* C8 - CF */
+ 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, /* D0 - D7 */
+ 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59, /* D8 - DF */
+ 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, /* E0 - E7 */
+ 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* E8 - EF */
+ 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, /* F0 - F7 */
+ 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF /* F8 - FF */
+};
+
+#if (defined(ZIP) || CRYPT)
+ZCONST uch ascii[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, /* 00 - 07 */
+ 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */
+#ifdef OS390
+ 0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87, /* 10 - 17 */
+#else
+ 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, /* 10 - 17 */
+#endif
+ 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */
+#ifdef OS390
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B, /* 20 - 27 */
+#else
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, /* 20 - 27 */
+#endif
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, /* 28 - 2F */
+ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, /* 30 - 37 */
+ 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, /* 38 - 3F */
+ 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, /* 40 - 47 */
+ 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, /* 48 - 4F */
+ 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, /* 50 - 57 */
+ 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, /* 58 - 5F */
+ 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, /* 60 - 67 */
+ 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, /* 68 - 6F */
+ 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, /* 70 - 77 */
+ 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, /* 78 - 7F */
+ 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 80 - 87 */
+ 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, /* 88 - 8F */
+ 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, /* 90 - 97 */
+ 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, /* 98 - 9F */
+ 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* A0 - A7 */
+ 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, /* A8 - AF */
+ 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, /* B0 - B7 */
+ 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, /* B8 - BF */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* C0 - C7 */
+ 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, /* C8 - CF */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, /* D0 - D7 */
+ 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, /* D8 - DF */
+ 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* E0 - E7 */
+ 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, /* E8 - EF */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* F0 - F7 */
+ 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F /* F8 - FF */
+};
+#endif /* ZIP || CRYPT */
+
+#else /* MTS */
+
+/*
+ * This is the MTS ASCII->EBCDIC translation table. It provides a 1-1
+ * translation from ISO 8859/1 8-bit ASCII to IBM Code Page 37 EBCDIC.
+ */
+
+ZCONST uch ebcdic[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, /* 00 - 07 */
+ 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, /* 10 - 17 */
+ 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 27 */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, /* 28 - 2F */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 30 - 37 */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, /* 38 - 3F */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 47 */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, /* 48 - 4F */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, /* 50 - 57 */
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, /* 58 - 5F */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60 - 67 */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 68 - 6F */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, /* 70 - 77 */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, /* 78 - 7F */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, /* 80 - 87 */
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, /* 88 - 8F */
+ 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, /* 90 - 97 */
+ 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, /* 98 - 9F */
+ 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, /* A0 - A7 */
+ 0xBD, 0xB4, 0x9A, 0x8A, 0x5F, 0xCA, 0xAF, 0xBC, /* A8 - AF */
+ 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, /* B0 - B7 */
+ 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, /* B8 - BF */
+ 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, /* C0 - C7 */
+ 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, /* C8 - CF */
+ 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, /* D0 - D7 */
+ 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xAD, 0xAE, 0x59, /* D8 - DF */
+ 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, /* E0 - E7 */
+ 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, /* E8 - EF */
+ 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, /* F0 - F7 */
+ 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF /* F8 - FF */
+};
+
+#if (defined(ZIP) || CRYPT)
+ZCONST uch ascii[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, /* 00 - 07 */
+ 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 08 - 0F */
+ 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, /* 10 - 17 */
+ 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, /* 18 - 1F */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, /* 20 - 27 */
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, /* 28 - 2F */
+ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, /* 30 - 37 */
+ 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, /* 38 - 3F */
+ 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, /* 40 - 47 */
+ 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, /* 48 - 4F */
+ 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, /* 50 - 57 */
+ 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC, /* 58 - 5F */
+ 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, /* 60 - 67 */
+ 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, /* 68 - 6F */
+ 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, /* 70 - 77 */
+ 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, /* 78 - 7F */
+ 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 80 - 87 */
+ 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, /* 88 - 8F */
+ 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, /* 90 - 97 */
+ 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, /* 98 - 9F */
+ 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* A0 - A7 */
+ 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE, /* A8 - AF */
+ 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, /* B0 - B7 */
+ 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7, /* B8 - BF */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* C0 - C7 */
+ 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, /* C8 - CF */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, /* D0 - D7 */
+ 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, /* D8 - DF */
+ 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* E0 - E7 */
+ 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, /* E8 - EF */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* F0 - F7 */
+ 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F /* F8 - FF */
+};
+#endif /* ZIP || CRYPT */
+
+#endif /* ?MTS */
+#endif /* EBCDIC */
+
+/*---------------------------------------------------------------------------
+
+ The following conversion tables translate between IBM PC CP 850
+ (OEM codepage) and the "Western Europe & America" Windows codepage 1252.
+ The Windows codepage 1252 contains the ISO 8859-1 "Latin 1" codepage,
+ with some additional printable characters in the range (0x80 - 0x9F),
+ that is reserved to control codes in the ISO 8859-1 character table.
+
+ The ISO <--> OEM conversion tables were constructed with the help
+ of the WIN32 (Win16?) API's OemToAnsi() and AnsiToOem() conversion
+ functions and have been checked against the CP850 and LATIN1 tables
+ provided in the MS-Kermit 3.14 distribution.
+
+ ---------------------------------------------------------------------------*/
+
+#ifdef IZ_ISO2OEM_ARRAY
+#ifdef OEM_RUSS
+ZCONST uch Far iso2oem[] = {
+ 0x3F, 0x3F, 0x27, 0x9F, 0x22, 0x2E, 0xC5, 0xCE, /* 80 - 87 */
+ 0xFD, 0x25, 0x53, 0x3C, 0x4F, 0x3F, 0x3F, 0x3F, /* 88 - 8F */
+ 0x3F, 0x27, 0x27, 0x22, 0x22, 0xF9, 0x2D, 0x2D, /* 90 - 97 */
+ 0x7E, 0x54, 0x73, 0x3E, 0x6F, 0x3F, 0x3F, 0x59, /* 98 - 9F */
+ 0xFF, 0xF6, 0xF7, 0x9C, 0xCF, 0xBE, 0xFE, 0xF5, /* A0 - A7 */
+ 0xF0, 0xB8, 0xF2, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, /* A8 - AF */
+ 0xF8, 0xFB, 0xF4, 0xF5, 0xEF, 0xE6, 0xF4, 0xFA, /* B0 - B7 */
+ 0xF1, 0xFC, 0xF3, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, /* B8 - BF */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x86, 0x86, 0x87, /* C0 - C7 */
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, /* C8 - CF */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* D0 - D7 */
+ 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, /* D8 - DF */
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, /* E0 - E7 */
+ 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, /* E8 - EF */
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, /* F0 - F7 */
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF /* F8 - FF */
+};
+#else /* OEM_RUS */
+ZCONST uch Far iso2oem[] = {
+ 0x3F, 0x3F, 0x27, 0x9F, 0x22, 0x2E, 0xC5, 0xCE, /* 80 - 87 */
+ 0x5E, 0x25, 0x53, 0x3C, 0x4F, 0x3F, 0x3F, 0x3F, /* 88 - 8F */
+ 0x3F, 0x27, 0x27, 0x22, 0x22, 0x07, 0x2D, 0x2D, /* 90 - 97 */
+ 0x7E, 0x54, 0x73, 0x3E, 0x6F, 0x3F, 0x3F, 0x59, /* 98 - 9F */
+ 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, /* A0 - A7 */
+ 0xF9, 0xB8, 0xA6, 0xAE, 0xAA, 0xF0, 0xA9, 0xEE, /* A8 - AF */
+ 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, /* B0 - B7 */
+ 0xF7, 0xFB, 0xA7, 0xAF, 0xAC, 0xAB, 0xF3, 0xA8, /* B8 - BF */
+ 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, /* C0 - C7 */
+ 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, /* C8 - CF */
+ 0xD1, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, /* D0 - D7 */
+ 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, /* D8 - DF */
+ 0x85, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, /* E0 - E7 */
+ 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1, 0x8C, 0x8B, /* E8 - EF */
+ 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, /* F0 - F7 */
+ 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 /* F8 - FF */
+};
+#endif /* OEM_RUS */
+#endif /* IZ_ISO2OEM_ARRAY */
+
+#ifdef IZ_OEM2ISO_ARRAY
+#ifdef OEM_RUSS
+ZCONST uch Far oem2iso[] = {
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 80 - 87 */
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, /* 88 - 8F */
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, /* 90 - 97 */
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, /* 98 - 9F */
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, /* A0 - A7 */
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, /* A8 - AF */
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xC1, 0xC2, 0xC0, /* B0 - B7 */
+ 0xA9, 0xA6, 0xA6, 0x2B, 0x2B, 0xA2, 0xA5, 0x2B, /* B8 - BF */
+ 0x2B, 0x2D, 0x2D, 0x2B, 0x2D, 0x2B, 0xE3, 0xC3, /* C0 - C7 */
+ 0x2B, 0x2B, 0x2D, 0x2D, 0xA6, 0x2D, 0x2B, 0xA4, /* C8 - CF */
+ 0xF0, 0xD0, 0xCA, 0xCB, 0xC8, 0x69, 0xCD, 0xCE, /* D0 - D7 */
+ 0xCF, 0x2B, 0x2B, 0xA6, 0x5F, 0xA6, 0xCC, 0xAF, /* D8 - DF */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* E0 - E7 */
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, /* E8 - EF */
+ 0xA8, 0xB8, 0xAA, 0xBA, 0xB2, 0xB3, 0xA1, 0xA2, /* F0 - F7 */
+ 0xB0, 0x95, 0xB7, 0xB1, 0xB9, 0x88, 0xA6, 0xA0 /* F8 - FF */
+};
+#else /* OEM_RUS */
+ZCONST uch Far oem2iso[] = {
+ 0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7, /* 80 - 87 */
+ 0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5, /* 88 - 8F */
+ 0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9, /* 90 - 97 */
+ 0xFF, 0xD6, 0xDC, 0xF8, 0xA3, 0xD8, 0xD7, 0x83, /* 98 - 9F */
+ 0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA, /* A0 - A7 */
+ 0xBF, 0xAE, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB, /* A8 - AF */
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xC1, 0xC2, 0xC0, /* B0 - B7 */
+ 0xA9, 0xA6, 0xA6, 0x2B, 0x2B, 0xA2, 0xA5, 0x2B, /* B8 - BF */
+ 0x2B, 0x2D, 0x2D, 0x2B, 0x2D, 0x2B, 0xE3, 0xC3, /* C0 - C7 */
+ 0x2B, 0x2B, 0x2D, 0x2D, 0xA6, 0x2D, 0x2B, 0xA4, /* C8 - CF */
+ 0xF0, 0xD0, 0xCA, 0xCB, 0xC8, 0x69, 0xCD, 0xCE, /* D0 - D7 */
+ 0xCF, 0x2B, 0x2B, 0xA6, 0x5F, 0xA6, 0xCC, 0xAF, /* D8 - DF */
+ 0xD3, 0xDF, 0xD4, 0xD2, 0xF5, 0xD5, 0xB5, 0xFE, /* E0 - E7 */
+ 0xDE, 0xDA, 0xDB, 0xD9, 0xFD, 0xDD, 0xAF, 0xB4, /* E8 - EF */
+ 0xAD, 0xB1, 0x3D, 0xBE, 0xB6, 0xA7, 0xF7, 0xB8, /* F0 - F7 */
+ 0xB0, 0xA8, 0xB7, 0xB9, 0xB3, 0xB2, 0xA6, 0xA0 /* F8 - FF */
+};
+#endif /* OEM_RUS */
+#endif /* IZ_OEM2ISO_ARRAY */
+
+#if defined(THEOS) || defined(THEOS_SUPPORT)
+# include "theos/charconv.h"
+#endif
+
+#endif /* __ebcdic_h */
diff --git a/file_id.diz b/file_id.diz
new file mode 100644
index 0000000..5e3f34e
--- /dev/null
+++ b/file_id.diz
@@ -0,0 +1,15 @@
+Info-ZIP's Zip 3.0: generic C sources.
+ Complete C source code for Info-ZIP's
+ PKZIP-compatible .zip archiver, for
+ all supported compilers and platforms
+ (Unix, OS/2, MS-DOS, NT, VMS, Amiga,
+ Atari, Mac, Acorn, VM/CMS, etc.), plus
+ lots of pretty decent documentation.
+ Includes Info-ZIP's ZCrypt 2.9 for
+ PKWARE-compatible standard encryption
+ and decryption support for Info-ZIP's
+ Zip 2.32, Zip 3.0, UnZip 5.52,
+ UnZip 6.0, and WiZ 5.02 (and later).
+This is FREE (but copyrighted) software.
+See LICENSE for details on distribution
+and reuse.
diff --git a/fileio.c b/fileio.c
new file mode 100644
index 0000000..1847e62
--- /dev/null
+++ b/fileio.c
@@ -0,0 +1,4903 @@
+/*
+ fileio.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * fileio.c by Mark Adler
+ */
+#define __FILEIO_C
+
+#include "zip.h"
+#include "crc32.h"
+
+#ifdef MACOS
+# include "helpers.h"
+#endif
+
+#ifdef VMS
+# include "vms/vms.h"
+#endif /* def VMS */
+
+#include <time.h>
+
+#ifdef NO_MKTIME
+time_t mktime OF((struct tm *));
+#endif
+
+#ifdef OSF
+#define EXDEV 18 /* avoid a bug in the DEC OSF/1 header files. */
+#else
+#include <errno.h>
+#endif
+
+#ifdef NO_ERRNO
+extern int errno;
+#endif
+
+/* -----------------------
+ For long option support
+ ----------------------- */
+#include <ctype.h>
+
+
+#if defined(VMS) || defined(TOPS20)
+# define PAD 5
+#else
+# define PAD 0
+#endif
+
+#ifdef NO_RENAME
+int rename OF((ZCONST char *, ZCONST char *));
+#endif
+
+
+/* Local functions */
+local int optionerr OF((char *, ZCONST char *, int, int));
+local unsigned long get_shortopt OF((char **, int, int *, int *, char **, int *, int));
+local unsigned long get_longopt OF((char **, int, int *, int *, char **, int *, int));
+
+#ifdef UNICODE_SUPPORT
+local int utf8_char_bytes OF((ZCONST char *utf8));
+local long ucs4_char_from_utf8 OF((ZCONST char **utf8 ));
+local int utf8_from_ucs4_char OF((char *utf8buf, ulg ch));
+local int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *usc4buf,
+ int buflen));
+local int ucs4_string_to_utf8 OF((ZCONST ulg *ucs4, char *utf8buf,
+ int buflen));
+#if 0
+ local int utf8_chars OF((ZCONST char *utf8));
+#endif
+#endif /* UNICODE_SUPPORT */
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+local int fqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
+local int fqcmpz OF((ZCONST zvoid *, ZCONST zvoid *));
+
+
+/* Local module level variables. */
+char *label = NULL; /* global, but only used in `system'.c */
+local z_stat zipstatb; /* now use z_stat globally - 7/24/04 EG */
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ local zw_stat zipstatbw;
+#endif
+#if (!defined(MACOS) && !defined(WINDLL))
+local int zipstate = -1;
+#else
+int zipstate;
+#endif
+/* -1 unknown, 0 old zip file exists, 1 new zip file */
+
+#if 0
+char *getnam(n, fp)
+char *n; /* where to put name (must have >=FNMAX+1 bytes) */
+#endif
+
+/* converted to return string pointer from malloc to avoid
+ size limitation - 11/8/04 EG */
+#define GETNAM_MAX 9000 /* hopefully big enough for now */
+char *getnam(fp)
+ FILE *fp;
+ /* Read a \n or \r delimited name from stdin into n, and return
+ n. If EOF, then return NULL. Also, if problem return NULL. */
+{
+ char name[GETNAM_MAX + 1];
+ int c; /* last character read */
+ char *p; /* pointer into name area */
+
+
+ p = name;
+ while ((c = getc(fp)) == '\n' || c == '\r')
+ ;
+ if (c == EOF)
+ return NULL;
+ do {
+ if (p - name >= GETNAM_MAX)
+ return NULL;
+ *p++ = (char) c;
+ c = getc(fp);
+ } while (c != EOF && (c != '\n' && c != '\r'));
+#ifdef WIN32
+/*
+ * WIN32 strips off trailing spaces and periods in filenames
+ * XXX what about a filename that only consists of spaces ?
+ * Answer: on WIN32, a filename must contain at least one non-space char
+ */
+ while (p > name) {
+ if ((c = p[-1]) != ' ' && c != '.')
+ break;
+ --p;
+ }
+#endif
+ *p = 0;
+ /* malloc a copy */
+ if ((p = malloc(strlen(name) + 1)) == NULL) {
+ return NULL;
+ }
+ strcpy(p, name);
+ return p;
+}
+
+struct flist far *fexpel(f)
+struct flist far *f; /* entry to delete */
+/* Delete the entry *f in the doubly-linked found list. Return pointer to
+ next entry to allow stepping through list. */
+{
+ struct flist far *t; /* temporary variable */
+
+ t = f->nxt;
+ *(f->lst) = t; /* point last to next, */
+ if (t != NULL)
+ t->lst = f->lst; /* and next to last */
+ if (f->name != NULL) /* free memory used */
+ free((zvoid *)(f->name));
+ if (f->zname != NULL)
+ free((zvoid *)(f->zname));
+ if (f->iname != NULL)
+ free((zvoid *)(f->iname));
+#ifdef UNICODE_SUPPORT
+ if (f->uname)
+ free((zvoid *)f->uname);
+# ifdef WIN32
+ if (f->namew)
+ free((zvoid *)f->namew);
+ if (f->inamew)
+ free((zvoid *)f->inamew);
+ if (f->znamew)
+ free((zvoid *)f->znamew);
+# endif
+#endif
+ farfree((zvoid far *)f);
+ fcount--; /* decrement count */
+ return t; /* return pointer to next */
+}
+
+local int fqcmp(a, b)
+ ZCONST zvoid *a, *b; /* pointers to pointers to found entries */
+/* Used by qsort() to compare entries in the found list by name. */
+{
+ return strcmp((*(struct flist far **)a)->name,
+ (*(struct flist far **)b)->name);
+}
+
+local int fqcmpz(a, b)
+ ZCONST zvoid *a, *b; /* pointers to pointers to found entries */
+/* Used by qsort() to compare entries in the found list by iname. */
+{
+ return strcmp((*(struct flist far **)a)->iname,
+ (*(struct flist far **)b)->iname);
+}
+
+char *last(p, c)
+ char *p; /* sequence of path components */
+ int c; /* path components separator character */
+/* Return a pointer to the start of the last path component. For a directory
+ * name terminated by the character in c, the return value is an empty string.
+ */
+{
+ char *t; /* temporary variable */
+
+ if ((t = strrchr(p, c)) != NULL)
+ return t + 1;
+ else
+#ifndef AOS_VS
+ return p;
+#else
+/* We want to allow finding of end of path in either AOS/VS-style pathnames
+ * or Unix-style pathnames. This presents a few little problems ...
+ */
+ {
+ if (*p == '=' || *p == '^') /* like ./ and ../ respectively */
+ return p + 1;
+ else
+ return p;
+ }
+#endif
+}
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+wchar_t *lastw(pw, c)
+ wchar_t *pw; /* sequence of path components */
+ wchar_t c; /* path components separator character */
+/* Return a pointer to the start of the last path component. For a directory
+ * name terminated by the character in c, the return value is an empty string.
+ */
+{
+ wchar_t *tw; /* temporary variable */
+
+ if ((tw = wcsrchr(pw, c)) != NULL)
+ return tw + 1;
+ else
+# ifndef AOS_VS
+ return pw;
+# else
+/* We want to allow finding of end of path in either AOS/VS-style pathnames
+ * or Unix-style pathnames. This presents a few little problems ...
+ */
+ {
+ if (*pw == (wchar_t)'=' || *pw == (wchar_t)'^') /* like ./ and ../ respectively */
+ return pw + 1;
+ else
+ return pw;
+ }
+# endif
+}
+#endif
+
+
+char *msname(n)
+ char *n;
+/* Reduce all path components to MSDOS upper case 8.3 style names. */
+{
+ int c; /* current character */
+ int f; /* characters in current component */
+ char *p; /* source pointer */
+ char *q; /* destination pointer */
+
+ p = q = n;
+ f = 0;
+ while ((c = (unsigned char)*POSTINCSTR(p)) != 0)
+ if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
+ c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
+ c == '?' || c == '[' || c == ']' || c == '|')
+ continue; /* char is discarded */
+ else if (c == '/')
+ {
+ *POSTINCSTR(q) = (char)c;
+ f = 0; /* new component */
+ }
+#ifdef __human68k__
+ else if (ismbblead(c) && *p)
+ {
+ if (f == 7 || f == 11)
+ f++;
+ else if (*p && f < 12 && f != 8)
+ {
+ *q++ = c;
+ *q++ = *p++;
+ f += 2;
+ }
+ }
+#endif /* __human68k__ */
+ else if (c == '.')
+ {
+ if (f == 0)
+ continue; /* leading dots are discarded */
+ else if (f < 9)
+ {
+ *POSTINCSTR(q) = (char)c;
+ f = 9; /* now in file type */
+ }
+ else
+ f = 12; /* now just excess characters */
+ }
+ else
+ if (f < 12 && f != 8)
+ {
+ f += CLEN(p); /* do until end of name or type */
+ *POSTINCSTR(q) = (char)(to_up(c));
+ }
+ *q = 0;
+ return n;
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *msnamew(nw)
+ wchar_t *nw;
+/* Reduce all path components to MSDOS upper case 8.3 style names. */
+{
+ wchar_t c; /* current character */
+ int f; /* characters in current component */
+ wchar_t *pw; /* source pointer */
+ wchar_t *qw; /* destination pointer */
+
+ pw = qw = nw;
+ f = 0;
+ while ((c = (unsigned char)*pw++) != 0)
+ if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
+ c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
+ c == '?' || c == '[' || c == ']' || c == '|')
+ continue; /* char is discarded */
+ else if (c == '/')
+ {
+ *qw++ = c;
+ f = 0; /* new component */
+ }
+#ifdef __human68k__
+ else if (ismbblead(c) && *pw)
+ {
+ if (f == 7 || f == 11)
+ f++;
+ else if (*pw && f < 12 && f != 8)
+ {
+ *qw++ = c;
+ *qw++ = *pw++;
+ f += 2;
+ }
+ }
+#endif /* __human68k__ */
+ else if (c == '.')
+ {
+ if (f == 0)
+ continue; /* leading dots are discarded */
+ else if (f < 9)
+ {
+ *qw++ = c;
+ f = 9; /* now in file type */
+ }
+ else
+ f = 12; /* now just excess characters */
+ }
+ else
+ if (f < 12 && f != 8)
+ {
+ f++; /* do until end of name or type */
+ *qw++ = towupper(c);
+ }
+ *qw = 0;
+ return nw;
+}
+#endif
+
+
+int proc_archive_name(n, caseflag)
+ char *n; /* name to process */
+ int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression in existing archive to operate
+ on (or exclude). Return an error code in the ZE_ class. */
+{
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) { /* if compressing stdin */
+ zipwarn("Cannot select stdin when selecting archive entries", "");
+ return ZE_MISS;
+ }
+ else
+ {
+ /* Search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->oname);
+ m = 0;
+ }
+ }
+#ifdef UNICODE_SUPPORT
+ /* also check escaped Unicode names */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (z->zuname) {
+#ifdef WIN32
+ /* It seems something is lost in going from a listed
+ name from zip -su in a console window to using that
+ name in a command line. This kluge may fix it
+ and just takes zuname, converts to oem (i.e. ouname),
+ then converts it back which ends up not the same as
+ started with.
+ */
+ char *zuname = z->wuname;
+#else
+ char *zuname = z->zuname;
+#endif
+ if (MATCH(p, zuname, caseflag))
+ {
+ z->mark = pcount ? filter(zuname, caseflag) : 1;
+ if (verbose) {
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->oname);
+ fprintf(mesg, " Escaped Unicode: %s\n",
+ z->ouname);
+ }
+ m = 0;
+ }
+ }
+ }
+#endif
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+}
+
+
+int check_dup()
+/* Sort the found list and remove duplicates.
+ Return an error code in the ZE_ class. */
+{
+ struct flist far *f; /* steps through found linked list */
+ extent j, k; /* indices for s */
+ struct flist far **s; /* sorted table */
+ struct flist far **nodup; /* sorted table without duplicates */
+
+ /* sort found list, remove duplicates */
+ if (fcount)
+ {
+ extent fl_size = fcount * sizeof(struct flist far *);
+ if ((fl_size / sizeof(struct flist far *)) != fcount ||
+ (s = (struct flist far **)malloc(fl_size)) == NULL)
+ return ZE_MEM;
+ for (j = 0, f = found; f != NULL; f = f->nxt)
+ s[j++] = f;
+ /* Check names as given (f->name) */
+ qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
+ for (k = j = fcount - 1; j > 0; j--)
+ if (strcmp(s[j - 1]->name, s[j]->name) == 0)
+ /* remove duplicate entry from list */
+ fexpel(s[j]); /* fexpel() changes fcount */
+ else
+ /* copy valid entry into destination position */
+ s[k--] = s[j];
+ s[k] = s[0]; /* First entry is always valid */
+ nodup = &s[k]; /* Valid entries are at end of array s */
+
+ /* sort only valid items and check for unique internal names (f->iname) */
+ qsort((char *)nodup, fcount, sizeof(struct flist far *), fqcmpz);
+ for (j = 1; j < fcount; j++)
+ if (strcmp(nodup[j - 1]->iname, nodup[j]->iname) == 0)
+ {
+ char tempbuf[FNMAX+4081];
+
+ sprintf(errbuf, " first full name: %s\n", nodup[j - 1]->name);
+ sprintf(tempbuf, " second full name: %s\n", nodup[j]->name);
+ strcat(errbuf, " ");
+ strcat(errbuf, tempbuf);
+#ifdef EBCDIC
+ strtoebc(nodup[j]->iname, nodup[j]->iname);
+#endif
+ sprintf(tempbuf, "name in zip file repeated: %s", nodup[j]->iname);
+ strcat(errbuf, " ");
+ strcat(errbuf, tempbuf);
+ if (pathput == 0) {
+ strcat(errbuf, "\n this may be a result of using -j");
+ }
+#ifdef EBCDIC
+ strtoasc(nodup[j]->iname, nodup[j]->iname);
+#endif
+ zipwarn(errbuf, "");
+ return ZE_PARMS;
+ }
+ free((zvoid *)s);
+ }
+ return ZE_OK;
+}
+
+int filter(name, casesensitive)
+ char *name;
+ int casesensitive;
+ /* Scan the -R, -i and -x lists for matches to the given name.
+ Return TRUE if the name must be included, FALSE otherwise.
+ Give precedence to -x over -i and -R.
+ Note that if both R and i patterns are given then must
+ have a match for both.
+ This routine relies on the following global variables:
+ patterns array of match pattern structures
+ pcount total number of patterns
+ icount number of -i patterns
+ Rcount number of -R patterns
+ These data are set up by the command line parsing code.
+ */
+{
+ unsigned int n;
+ int slashes;
+ char *p, *q;
+ /* without -i patterns, every name matches the "-i select rules" */
+ int imatch = (icount == 0);
+ /* without -R patterns, every name matches the "-R select rules" */
+ int Rmatch = (Rcount == 0);
+
+ if (pcount == 0) return TRUE;
+
+ for (n = 0; n < pcount; n++) {
+ if (!patterns[n].zname[0]) /* it can happen... */
+ continue;
+ p = name;
+ switch (patterns[n].select) {
+ case 'R':
+ if (Rmatch)
+ /* one -R match is sufficient, skip this pattern */
+ continue;
+ /* With -R patterns, if the pattern has N path components (that is,
+ N-1 slashes), then we test only the last N components of name.
+ */
+ slashes = 0;
+ for (q = patterns[n].zname; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
+ slashes++;
+ /* The name may have M path components (M-1 slashes) */
+ for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
+ slashes--;
+ /* Now, "slashes" contains the difference "N-M" between the number
+ of path components in the pattern (N) and in the name (M).
+ */
+ if (slashes < 0)
+ /* We found "M > N"
+ --> skip the first (M-N) path components of the name.
+ */
+ for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
+ if (++slashes == 0) {
+ p = q + 1; /* q points at '/', mblen("/") is 1 */
+ break;
+ }
+ break;
+ case 'i':
+ if (imatch)
+ /* one -i match is sufficient, skip this pattern */
+ continue;
+ break;
+ }
+ if (MATCH(patterns[n].zname, p, casesensitive)) {
+ switch (patterns[n].select) {
+ case 'x':
+ /* The -x match takes precedence over everything else */
+ return FALSE;
+ case 'R':
+ Rmatch = TRUE;
+ break;
+ default:
+ /* this must be a type -i match */
+ imatch = TRUE;
+ break;
+ }
+ }
+ }
+ return imatch && Rmatch;
+}
+
+
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+
+int newnamew(namew, isdir, casesensitive)
+ wchar_t *namew; /* name to add (or exclude) */
+ int isdir; /* true for a directory */
+ int casesensitive; /* true for case-sensitive matching */
+/* Add (or exclude) the name of an existing disk file. Return an error
+ code in the ZE_ class. */
+{
+ wchar_t *inamew = NULL; /* internal name */
+ wchar_t *znamew = NULL; /* external version of iname */
+ wchar_t *undosmw = NULL; /* zname version with "-j" and "-k" options disabled */
+ char *oname = NULL; /* iname converted for display */
+ char *name = NULL;
+ char *iname = NULL;
+ char *zname = NULL;
+ char *zuname = NULL;
+ char *undosm = NULL;
+ struct flist far *f; /* where in found, or new found entry */
+ struct zlist far *z; /* where in zfiles (if found) */
+ int dosflag;
+
+ /* Scanning files ...
+ *
+ * After 5 seconds output Scanning files...
+ * then a dot every 2 seconds
+ */
+ if (noisy) {
+ /* If find files then output message after delay */
+ if (scan_count == 0) {
+ time_t current = time(NULL);
+ scan_start = current;
+ }
+ scan_count++;
+ if (scan_count % 100 == 0) {
+ time_t current = time(NULL);
+
+ if (current - scan_start > scan_delay) {
+ if (scan_last == 0) {
+ zipmessage_nl("Scanning files ", 0);
+ scan_last = current;
+ }
+ if (current - scan_last > scan_dot_time) {
+ scan_last = current;
+ fprintf(mesg, ".");
+ fflush(mesg);
+ }
+ }
+ }
+ }
+
+ /* Search for name in zip file. If there, mark it, else add to
+ list of new names to do (or remove from that list). */
+ if ((inamew = ex2inw(namew, isdir, &dosflag)) == NULL)
+ return ZE_MEM;
+
+ /* Discard directory names with zip -rj */
+ if (*inamew == (wchar_t)'\0') {
+
+ /* If extensions needs to be swapped, we will have empty directory names
+ instead of the original directory. For example, zipping 'c.', 'c.main'
+ should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
+
+ if (pathput && !recurse) error("empty name without -j or -r");
+ free((zvoid *)inamew);
+ return ZE_OK;
+ }
+
+ if (dosflag || !pathput) {
+ int save_dosify = dosify, save_pathput = pathput;
+ dosify = 0;
+ pathput = 1;
+ /* zname is temporarly mis-used as "undosmode" iname pointer */
+ if ((znamew = ex2inw(namew, isdir, NULL)) != NULL) {
+ undosmw = in2exw(znamew);
+ free(znamew);
+ }
+ dosify = save_dosify;
+ pathput = save_pathput;
+ }
+ if ((znamew = in2exw(inamew)) == NULL)
+ return ZE_MEM;
+
+ /* Convert names from wchar_t to char */
+
+ name = wchar_to_local_string(namew);
+ iname = wchar_to_local_string(inamew);
+ zname = wchar_to_local_string(znamew);
+
+ oname = local_to_display_string(zname);
+
+ zuname = wchar_to_local_string(znamew);
+
+ if (undosmw == NULL)
+ undosmw = znamew;
+ undosm = wchar_to_local_string(undosmw);
+
+ if ((z = zsearch(zuname)) != NULL) {
+ if (pcount && !filter(undosm, casesensitive)) {
+ /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
+ * is in effect, two files with different filter options may hit the
+ * same z entry.
+ */
+ if (verbose)
+ fprintf(mesg, "excluding %s\n", oname);
+ } else {
+ z->mark = 1;
+ if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
+ if (undosmw != znamew)
+ free(undosmw);
+ if (undosm) free(undosm);
+ if (inamew) free(inamew);
+ if (znamew) free(znamew);
+ if (name) free(name);
+ if (iname) free(iname);
+ if (zname) free(zname);
+ if (oname) free(oname);
+ if (zuname) free(zuname);
+ return ZE_MEM;
+ }
+ strcpy(z->name, name);
+ z->oname = oname;
+ oname = NULL;
+ z->dosflag = dosflag;
+
+#ifdef FORCE_NEWNAME
+ free((zvoid *)(z->iname));
+ z->iname = iname;
+ iname = NULL;
+#else
+ /* Better keep the old name. Useful when updating on MSDOS a zip file
+ * made on Unix.
+ */
+#endif /* ? FORCE_NEWNAME */
+ }
+
+ if ((z->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
+ if (undosmw != znamew)
+ free(undosmw);
+ if (undosm) free(undosm);
+ if (inamew) free(inamew);
+ if (znamew) free(znamew);
+ if (name) free(name);
+ if (iname) free(iname);
+ if (zname) free(zname);
+ if (oname) free(oname);
+ if (zuname) free(zuname);
+ return ZE_MEM;
+ }
+ wcscpy(z->namew, namew);
+ z->inamew = inamew;
+ inamew = NULL;
+ z->znamew = znamew;
+ znamew = NULL;
+ z->uname = wchar_to_utf8_string(z->inamew);
+ if (name == label) {
+ label = z->name;
+ }
+ } else if (pcount == 0 || filter(undosm, casesensitive)) {
+
+ /* Check that we are not adding the zip file to itself. This
+ * catches cases like "zip -m foo ../dir/foo.zip".
+ */
+/* Version of stat() for CMS/MVS isn't complete enough to see if */
+/* files match. Just let ZIP.C compare the filenames. That's good */
+/* enough for CMS anyway since there aren't paths to worry about. */
+ zw_stat statbw; /* need for wide stat */
+ wchar_t *zipfilew = local_to_wchar_string(zipfile);
+
+ if (zipstate == -1)
+ zipstate = strcmp(zipfile, "-") != 0 &&
+ zwstat(zipfilew, &zipstatbw) == 0;
+ free(zipfilew);
+
+ if (zipstate == 1 && (statbw = zipstatbw, zwstat(namew, &statbw) == 0
+ && zipstatbw.st_mode == statbw.st_mode
+ && zipstatbw.st_ino == statbw.st_ino
+ && zipstatbw.st_dev == statbw.st_dev
+ && zipstatbw.st_uid == statbw.st_uid
+ && zipstatbw.st_gid == statbw.st_gid
+ && zipstatbw.st_size == statbw.st_size
+ && zipstatbw.st_mtime == statbw.st_mtime
+ && zipstatbw.st_ctime == statbw.st_ctime)) {
+ /* Don't compare a_time since we are reading the file */
+ if (verbose)
+ fprintf(mesg, "file matches zip file -- skipping\n");
+ if (undosmw != znamew)
+ free(undosmw);
+ if (undosm) free(undosm);
+ if (inamew) free(inamew);
+ if (znamew) free(znamew);
+ if (name) free(name);
+ if (iname) free(iname);
+ if (zname) free(zname);
+ if (oname) free(oname);
+ if (zuname) free(zuname);
+ return ZE_OK;
+ }
+
+ /* allocate space and add to list */
+ if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
+ fcount + 1 < fcount ||
+ (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
+ {
+ if (f != NULL)
+ farfree((zvoid far *)f);
+ if (undosmw != znamew)
+ free(undosmw);
+ if (undosm) free(undosm);
+ if (inamew) free(inamew);
+ if (znamew) free(znamew);
+ if (name) free(name);
+ if (iname) free(iname);
+ if (zname) free(zname);
+ if (oname) free(oname);
+ if (zuname) free(zuname);
+ return ZE_MEM;
+ }
+ if (undosmw != znamew)
+ free((zvoid *)undosmw);
+ strcpy(f->name, name);
+ f->iname = iname;
+ iname = NULL;
+ f->zname = zname;
+ zname = NULL;
+ /* Unicode */
+ if ((f->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
+ if (f != NULL)
+ farfree((zvoid far *)f);
+ if (undosmw != znamew)
+ free(undosmw);
+ if (undosm) free(undosm);
+ if (inamew) free(inamew);
+ if (znamew) free(znamew);
+ if (name) free(name);
+ if (iname) free(iname);
+ if (zname) free(zname);
+ if (oname) free(oname);
+ if (zuname) free(zuname);
+ return ZE_MEM;
+ }
+ wcscpy(f->namew, namew);
+ f->znamew = znamew;
+ znamew = NULL;
+ f->uname = wchar_to_utf8_string(inamew);
+ f->inamew = inamew;
+ inamew = NULL;
+ f->oname = oname;
+ oname = NULL;
+ f->dosflag = dosflag;
+ *fnxt = f;
+ f->lst = fnxt;
+ f->nxt = NULL;
+ fnxt = &f->nxt;
+ fcount++;
+ if (name == label) {
+ label = f->name;
+ }
+ }
+ if (undosm) free(undosm);
+ if (inamew) free(inamew);
+ if (znamew) free(znamew);
+ if (name) free(name);
+ if (iname) free(iname);
+ if (zname) free(zname);
+ if (oname) free(oname);
+ if (zuname) free(zuname);
+ return ZE_OK;
+}
+
+# endif
+#endif
+
+int newname(name, isdir, casesensitive)
+ char *name; /* name to add (or exclude) */
+ int isdir; /* true for a directory */
+ int casesensitive; /* true for case-sensitive matching */
+/* Add (or exclude) the name of an existing disk file. Return an error
+ code in the ZE_ class. */
+{
+ char *iname, *zname; /* internal name, external version of iname */
+ char *undosm; /* zname version with "-j" and "-k" options disabled */
+ char *oname; /* iname converted for display */
+ struct flist far *f; /* where in found, or new found entry */
+ struct zlist far *z; /* where in zfiles (if found) */
+ int dosflag;
+
+ /* Scanning files ...
+ *
+ * After 5 seconds output Scanning files...
+ * then a dot every 2 seconds
+ */
+ if (noisy) {
+ /* If find files then output message after delay */
+ if (scan_count == 0) {
+ time_t current = time(NULL);
+ scan_start = current;
+ }
+ scan_count++;
+ if (scan_count % 100 == 0) {
+ time_t current = time(NULL);
+
+ if (current - scan_start > scan_delay) {
+ if (scan_last == 0) {
+ zipmessage_nl("Scanning files ", 0);
+ scan_last = current;
+ }
+ if (current - scan_last > scan_dot_time) {
+ scan_last = current;
+ fprintf(mesg, ".");
+ fflush(mesg);
+ }
+ }
+ }
+ }
+
+ /* Search for name in zip file. If there, mark it, else add to
+ list of new names to do (or remove from that list). */
+ if ((iname = ex2in(name, isdir, &dosflag)) == NULL)
+ return ZE_MEM;
+
+ /* Discard directory names with zip -rj */
+ if (*iname == '\0') {
+#ifndef AMIGA
+/* A null string is a legitimate external directory name in AmigaDOS; also,
+ * a command like "zip -r zipfile FOO:" produces an empty internal name.
+ */
+# ifndef RISCOS
+ /* If extensions needs to be swapped, we will have empty directory names
+ instead of the original directory. For example, zipping 'c.', 'c.main'
+ should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
+
+ if (pathput && !recurse) error("empty name without -j or -r");
+
+# endif /* !RISCOS */
+#endif /* !AMIGA */
+ free((zvoid *)iname);
+ return ZE_OK;
+ }
+ undosm = NULL;
+ if (dosflag || !pathput) {
+ int save_dosify = dosify, save_pathput = pathput;
+ dosify = 0;
+ pathput = 1;
+ /* zname is temporarly mis-used as "undosmode" iname pointer */
+ if ((zname = ex2in(name, isdir, NULL)) != NULL) {
+ undosm = in2ex(zname);
+ free(zname);
+ }
+ dosify = save_dosify;
+ pathput = save_pathput;
+ }
+ if ((zname = in2ex(iname)) == NULL)
+ return ZE_MEM;
+#ifdef UNICODE_SUPPORT
+ /* Convert name to display or OEM name */
+ oname = local_to_display_string(iname);
+#else
+ if ((oname = malloc(strlen(zname) + 1)) == NULL)
+ return ZE_MEM;
+ strcpy(oname, zname);
+#endif
+ if (undosm == NULL)
+ undosm = zname;
+ if ((z = zsearch(zname)) != NULL) {
+ if (pcount && !filter(undosm, casesensitive)) {
+ /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
+ * is in effect, two files with different filter options may hit the
+ * same z entry.
+ */
+ if (verbose)
+ fprintf(mesg, "excluding %s\n", oname);
+ free((zvoid *)iname);
+ free((zvoid *)zname);
+ } else {
+ z->mark = 1;
+ if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
+ if (undosm != zname)
+ free((zvoid *)undosm);
+ free((zvoid *)iname);
+ free((zvoid *)zname);
+ return ZE_MEM;
+ }
+ strcpy(z->name, name);
+ z->oname = oname;
+ z->dosflag = dosflag;
+
+#ifdef FORCE_NEWNAME
+ free((zvoid *)(z->iname));
+ z->iname = iname;
+#else
+ /* Better keep the old name. Useful when updating on MSDOS a zip file
+ * made on Unix.
+ */
+ free((zvoid *)iname);
+ free((zvoid *)zname);
+#endif /* ? FORCE_NEWNAME */
+ }
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ z->namew = NULL;
+ z->inamew = NULL;
+ z->znamew = NULL;
+#endif
+ if (name == label) {
+ label = z->name;
+ }
+ } else if (pcount == 0 || filter(undosm, casesensitive)) {
+
+ /* Check that we are not adding the zip file to itself. This
+ * catches cases like "zip -m foo ../dir/foo.zip".
+ */
+#ifndef CMS_MVS
+/* Version of stat() for CMS/MVS isn't complete enough to see if */
+/* files match. Just let ZIP.C compare the filenames. That's good */
+/* enough for CMS anyway since there aren't paths to worry about. */
+ z_stat statb; /* now use structure z_stat and function zstat globally 7/24/04 EG */
+
+ if (zipstate == -1)
+ zipstate = strcmp(zipfile, "-") != 0 &&
+ zstat(zipfile, &zipstatb) == 0;
+
+ if (zipstate == 1 && (statb = zipstatb, zstat(name, &statb) == 0
+ && zipstatb.st_mode == statb.st_mode
+#ifdef VMS
+ && memcmp(zipstatb.st_ino, statb.st_ino, sizeof(statb.st_ino)) == 0
+ && strcmp(zipstatb.st_dev, statb.st_dev) == 0
+ && zipstatb.st_uid == statb.st_uid
+#else /* !VMS */
+ && zipstatb.st_ino == statb.st_ino
+ && zipstatb.st_dev == statb.st_dev
+ && zipstatb.st_uid == statb.st_uid
+ && zipstatb.st_gid == statb.st_gid
+#endif /* ?VMS */
+ && zipstatb.st_size == statb.st_size
+ && zipstatb.st_mtime == statb.st_mtime
+ && zipstatb.st_ctime == statb.st_ctime)) {
+ /* Don't compare a_time since we are reading the file */
+ if (verbose)
+ fprintf(mesg, "file matches zip file -- skipping\n");
+ if (undosm != zname)
+ free((zvoid *)zname);
+ if (undosm != iname)
+ free((zvoid *)undosm);
+ free((zvoid *)iname);
+ free(oname);
+ return ZE_OK;
+ }
+#endif /* CMS_MVS */
+
+ /* allocate space and add to list */
+ if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
+ fcount + 1 < fcount ||
+ (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
+ {
+ if (f != NULL)
+ farfree((zvoid far *)f);
+ if (undosm != zname)
+ free((zvoid *)undosm);
+ free((zvoid *)iname);
+ free((zvoid *)zname);
+ free(oname);
+ return ZE_MEM;
+ }
+ strcpy(f->name, name);
+ f->iname = iname;
+ f->zname = zname;
+#ifdef UNICODE_SUPPORT
+ /* Unicode */
+ f->uname = local_to_utf8_string(iname);
+#ifdef WIN32
+ f->namew = NULL;
+ f->inamew = NULL;
+ f->znamew = NULL;
+ if (strcmp(f->name, "-") == 0) {
+ f->namew = local_to_wchar_string(f->name);
+ }
+#endif
+
+#endif
+ f->oname = oname;
+ f->dosflag = dosflag;
+
+ *fnxt = f;
+ f->lst = fnxt;
+ f->nxt = NULL;
+ fnxt = &f->nxt;
+ fcount++;
+ if (name == label) {
+ label = f->name;
+ }
+ }
+ if (undosm != zname)
+ free((zvoid *)undosm);
+ return ZE_OK;
+}
+
+ulg dostime(y, n, d, h, m, s)
+int y; /* year */
+int n; /* month */
+int d; /* day */
+int h; /* hour */
+int m; /* minute */
+int s; /* second */
+/* Convert the date y/n/d and time h:m:s to a four byte DOS date and
+ time (date in high two bytes, time in low two bytes allowing magnitude
+ comparison). */
+{
+ return y < 1980 ? DOSTIME_MINIMUM /* dostime(1980, 1, 1, 0, 0, 0) */ :
+ (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
+ ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
+}
+
+
+ulg unix2dostime(t)
+time_t *t; /* unix time to convert */
+/* Return the Unix time t in DOS format, rounded up to the next two
+ second boundary. */
+{
+ time_t t_even;
+ struct tm *s; /* result of localtime() */
+
+ t_even = (time_t)(((unsigned long)(*t) + 1) & (~1));
+ /* Round up to even seconds. */
+ s = localtime(&t_even); /* Use local time since MSDOS does. */
+ if (s == (struct tm *)NULL) {
+ /* time conversion error; use current time as emergency value
+ (assuming that localtime() does at least accept this value!) */
+ t_even = (time_t)(((unsigned long)time(NULL) + 1) & (~1));
+ s = localtime(&t_even);
+ }
+ return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
+ s->tm_hour, s->tm_min, s->tm_sec);
+}
+
+int issymlnk(a)
+ulg a; /* Attributes returned by filetime() */
+/* Return true if the attributes are those of a symbolic link */
+{
+#ifndef QDOS
+#ifdef S_IFLNK
+#ifdef __human68k__
+ int *_dos_importlnenv(void);
+
+ if (_dos_importlnenv() == NULL)
+ return 0;
+#endif
+ return ((a >> 16) & S_IFMT) == S_IFLNK;
+#else /* !S_IFLNK */
+ return (int)a & 0; /* avoid warning on unused parameter */
+#endif /* ?S_IFLNK */
+#else
+ return 0;
+#endif
+}
+
+#endif /* !UTIL */
+
+
+#if (!defined(UTIL) && !defined(ZP_NEED_GEN_D2U_TIME))
+ /* There is no need for dos2unixtime() in the ZipUtils' code. */
+# define ZP_NEED_GEN_D2U_TIME
+#endif
+#if ((defined(OS2) || defined(VMS)) && defined(ZP_NEED_GEN_D2U_TIME))
+ /* OS/2 and VMS use a special solution to handle time-stams of files. */
+# undef ZP_NEED_GEN_D2U_TIME
+#endif
+#if (defined(W32_STATROOT_FIX) && !defined(ZP_NEED_GEN_D2U_TIME))
+ /* The Win32 stat()-bandaid to fix stat'ing root directories needs
+ * dos2unixtime() to calculate the time-stamps. */
+# define ZP_NEED_GEN_D2U_TIME
+#endif
+
+#ifdef ZP_NEED_GEN_D2U_TIME
+
+time_t dos2unixtime(dostime)
+ulg dostime; /* DOS time to convert */
+/* Return the Unix time_t value (GMT/UTC time) for the DOS format (local)
+ * time dostime, where dostime is a four byte value (date in most significant
+ * word, time in least significant word), see dostime() function.
+ */
+{
+ struct tm *t; /* argument for mktime() */
+ ZCONST time_t clock = time(NULL);
+
+ t = localtime(&clock);
+ t->tm_isdst = -1; /* let mktime() determine if DST is in effect */
+ /* Convert DOS time to UNIX time_t format */
+ t->tm_sec = (((int)dostime) << 1) & 0x3e;
+ t->tm_min = (((int)dostime) >> 5) & 0x3f;
+ t->tm_hour = (((int)dostime) >> 11) & 0x1f;
+ t->tm_mday = (int)(dostime >> 16) & 0x1f;
+ t->tm_mon = ((int)(dostime >> 21) & 0x0f) - 1;
+ t->tm_year = ((int)(dostime >> 25) & 0x7f) + 80;
+
+ return mktime(t);
+}
+
+#undef ZP_NEED_GEN_D2U_TIME
+#endif /* ZP_NEED_GEN_D2U_TIME */
+
+
+#ifndef MACOS
+int destroy(f)
+ char *f; /* file to delete */
+/* Delete the file *f, returning non-zero on failure. */
+{
+ return unlink(f);
+}
+
+
+int replace(d, s)
+char *d, *s; /* destination and source file names */
+/* Replace file *d by file *s, removing the old *s. Return an error code
+ in the ZE_ class. This function need not preserve the file attributes,
+ this will be done by setfileattr() later.
+ */
+{
+ z_stat t; /* results of stat() */
+#if defined(CMS_MVS)
+ /* cmsmvs.h defines FOPW_TEMP as memory(hiperspace). Since memory is
+ * lost at end of run, always do copy instead of rename.
+ */
+ int copy = 1;
+#else
+ int copy = 0;
+#endif
+ int d_exists;
+
+#if defined(VMS) || defined(CMS_MVS)
+ /* stat() is broken on VMS remote files (accessed through Decnet).
+ * This patch allows creation of remote zip files, but is not sufficient
+ * to update them or compress remote files */
+ unlink(d);
+#else /* !(VMS || CMS_MVS) */
+ d_exists = (LSTAT(d, &t) == 0);
+ if (d_exists)
+ {
+ /*
+ * respect existing soft and hard links!
+ */
+ if (t.st_nlink > 1
+# ifdef S_IFLNK
+ || (t.st_mode & S_IFMT) == S_IFLNK
+# endif
+ )
+ copy = 1;
+ else if (unlink(d))
+ return ZE_CREAT; /* Can't erase zip file--give up */
+ }
+#endif /* ?(VMS || CMS_MVS) */
+#ifndef CMS_MVS
+ if (!copy) {
+ if (rename(s, d)) { /* Just move s on top of d */
+ copy = 1; /* failed ? */
+#if !defined(VMS) && !defined(ATARI) && !defined(AZTEC_C)
+#if !defined(CMS_MVS) && !defined(RISCOS) && !defined(QDOS)
+ /* For VMS, ATARI, AMIGA Aztec, VM_CMS, MVS, RISCOS,
+ always assume that failure is EXDEV */
+ if (errno != EXDEV
+# ifdef THEOS
+ && errno != EEXIST
+# else
+# ifdef ENOTSAM
+ && errno != ENOTSAM /* Used at least on Turbo C */
+# endif
+# endif
+ ) return ZE_CREAT;
+#endif /* !CMS_MVS && !RISCOS */
+#endif /* !VMS && !ATARI && !AZTEC_C */
+ }
+ }
+#endif /* !CMS_MVS */
+
+ if (copy) {
+ FILE *f, *g; /* source and destination files */
+ int r; /* temporary variable */
+
+#ifdef RISCOS
+ if (SWI_OS_FSControl_26(s,d,0xA1)!=NULL) {
+#endif
+
+ /* Use zfopen for almost all opens where fopen is used. For
+ most OS that support large files we use the 64-bit file
+ environment and zfopen maps to fopen, but this allows
+ tweeking ports that don't do that. 7/24/04 */
+ if ((f = zfopen(s, FOPR)) == NULL) {
+ fprintf(mesg," replace: can't open %s\n", s);
+ return ZE_TEMP;
+ }
+ if ((g = zfopen(d, FOPW)) == NULL)
+ {
+ fclose(f);
+ return ZE_CREAT;
+ }
+
+ r = fcopy(f, g, (ulg)-1L);
+ fclose(f);
+ if (fclose(g) || r != ZE_OK)
+ {
+ unlink(d);
+ return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
+ }
+ unlink(s);
+#ifdef RISCOS
+ }
+#endif
+ }
+ return ZE_OK;
+}
+#endif /* !MACOS */
+
+
+int getfileattr(f)
+char *f; /* file path */
+/* Return the file attributes for file f or 0 if failure */
+{
+#ifdef __human68k__
+ struct _filbuf buf;
+
+ return _dos_files(&buf, f, 0xff) < 0 ? 0x20 : buf.atr;
+#else
+ z_stat s;
+
+ return SSTAT(f, &s) == 0 ? (int) s.st_mode : 0;
+#endif
+}
+
+
+int setfileattr(f, a)
+char *f; /* file path */
+int a; /* attributes returned by getfileattr() */
+/* Give the file f the attributes a, return non-zero on failure */
+{
+#if defined(TOPS20) || defined (CMS_MVS)
+ return 0;
+#else
+#ifdef __human68k__
+ return _dos_chmod(f, a) < 0 ? -1 : 0;
+#else
+ return chmod(f, a);
+#endif
+#endif
+}
+
+
+/* tempname */
+
+#ifndef VMS /* VMS-specific function is in VMS.C. */
+
+char *tempname(zip)
+ char *zip; /* path name of zip file to generate temp name for */
+
+/* Return a temporary file name in its own malloc'ed space, using tempath. */
+{
+ char *t = zip; /* malloc'ed space for name (use zip to avoid warning) */
+
+# ifdef CMS_MVS
+ if ((t = malloc(strlen(tempath) + L_tmpnam + 2)) == NULL)
+ return NULL;
+
+# ifdef VM_CMS
+ tmpnam(t);
+ /* Remove filemode and replace with tempath, if any. */
+ /* Otherwise A-disk is used by default */
+ *(strrchr(t, ' ')+1) = '\0';
+ if (tempath!=NULL)
+ strcat(t, tempath);
+ return t;
+# else /* !VM_CMS */
+ /* For MVS */
+ tmpnam(t);
+ if (tempath != NULL)
+ {
+ int l1 = strlen(t);
+ char *dot;
+ if (*t == '\'' && *(t+l1-1) == '\'' && (dot = strchr(t, '.')))
+ {
+ /* MVS and not OE. tmpnam() returns quoted string of 5 qualifiers.
+ * First is HLQ, rest are timestamps. User can only replace HLQ.
+ */
+ int l2 = strlen(tempath);
+ if (strchr(tempath, '.') || l2 < 1 || l2 > 8)
+ ziperr(ZE_PARMS, "On MVS and not OE, tempath (-b) can only be HLQ");
+ memmove(t+1+l2, dot, l1+1-(dot-t)); /* shift dot ready for new hlq */
+ memcpy(t+1, tempath, l2); /* insert new hlq */
+ }
+ else
+ {
+ /* MVS and probably OE. tmpnam() returns filename based on TMPDIR,
+ * no point in even attempting to change it. User should modify TMPDIR
+ * instead.
+ */
+ zipwarn("MVS, assumed to be OE, change TMPDIR instead of option -b: ",
+ tempath);
+ }
+ }
+ return t;
+# endif /* !VM_CMS */
+
+# else /* !CMS_MVS */
+
+# ifdef TANDEM
+ char cur_subvol [FILENAME_MAX];
+ char temp_subvol [FILENAME_MAX];
+ char *zptr;
+ char *ptr;
+ char *cptr = &cur_subvol[0];
+ char *tptr = &temp_subvol[0];
+ short err;
+ FILE *tempf;
+ int attempts;
+
+ t = (char *)malloc(NAMELEN); /* malloc here as you cannot free */
+ /* tmpnam allocated storage later */
+
+ zptr = strrchr(zip, TANDEM_DELIMITER);
+
+ if (zptr != NULL) {
+ /* ZIP file specifies a Subvol so make temp file there so it can just
+ be renamed at end */
+
+ *tptr = *cptr = '\0';
+ strcat(cptr, getenv("DEFAULTS"));
+
+ strncat(tptr, zip, _min(FILENAME_MAX, (zptr - zip)) ); /* temp subvol */
+ strncat(t, zip, _min(NAMELEN, ((zptr - zip) + 1)) ); /* temp stem */
+
+ err = chvol(tptr);
+ ptr = t + strlen(t); /* point to end of stem */
+ }
+ else
+ ptr = t;
+
+ /* If two zips are running in same subvol then we can get contention problems
+ with the temporary filename. As a work around we attempt to create
+ the file here, and if it already exists we get a new temporary name */
+
+ attempts = 0;
+ do {
+ attempts++;
+ tmpnam(ptr); /* Add filename */
+ tempf = zfopen(ptr, FOPW_TMP); /* Attempt to create file */
+ } while (tempf == NULL && attempts < 100);
+
+ if (attempts >= 100) {
+ ziperr(ZE_TEMP, "Could not get unique temp file name");
+ }
+
+ fclose(tempf);
+
+ if (zptr != NULL) {
+ err = chvol(cptr); /* Put ourself back to where we came in */
+ }
+
+ return t;
+
+# else /* !CMS_MVS && !TANDEM */
+/*
+ * Do something with TMPDIR, TMP, TEMP ????
+ */
+ if (tempath != NULL)
+ {
+ if ((t = malloc(strlen(tempath) + 12)) == NULL)
+ return NULL;
+ strcpy(t, tempath);
+
+# if (!defined(VMS) && !defined(TOPS20))
+# ifdef MSDOS
+ {
+ char c = (char)lastchar(t);
+ if (c != '/' && c != ':' && c != '\\')
+ strcat(t, "/");
+ }
+# else
+
+# ifdef AMIGA
+ {
+ char c = (char)lastchar(t);
+ if (c != '/' && c != ':')
+ strcat(t, "/");
+ }
+# else /* !AMIGA */
+# ifdef RISCOS
+ if (lastchar(t) != '.')
+ strcat(t, ".");
+# else /* !RISCOS */
+
+# ifdef QDOS
+ if (lastchar(t) != '_')
+ strcat(t, "_");
+# else
+ if (lastchar(t) != '/')
+ strcat(t, "/");
+# endif /* ?QDOS */
+# endif /* ?RISCOS */
+# endif /* ?AMIGA */
+# endif /* ?MSDOS */
+# endif /* !VMS && !TOPS20 */
+ }
+ else
+ {
+ if ((t = malloc(12)) == NULL)
+ return NULL;
+ *t = 0;
+ }
+# ifdef NO_MKTEMP
+ {
+ char *p = t + strlen(t);
+ sprintf(p, "%08lx", (ulg)time(NULL));
+ return t;
+ }
+# else
+ strcat(t, "ziXXXXXX"); /* must use lowercase for Linux dos file system */
+# if defined(UNIX) && !defined(NO_MKSTEMP)
+ /* tempname should not be called */
+ return t;
+# else
+ return mktemp(t);
+# endif
+# endif /* NO_MKTEMP */
+# endif /* TANDEM */
+# endif /* CMS_MVS */
+}
+#endif /* !VMS */
+
+int fcopy(f, g, n)
+ FILE *f, *g; /* source and destination files */
+ /* now use uzoff_t for all file sizes 5/14/05 CS */
+ uzoff_t n; /* number of bytes to copy or -1 for all */
+/* Copy n bytes from file *f to file *g, or until EOF if (zoff_t)n == -1.
+ Return an error code in the ZE_ class. */
+{
+ char *b; /* malloc'ed buffer for copying */
+ extent k; /* result of fread() */
+ uzoff_t m; /* bytes copied so far */
+
+ if ((b = malloc(CBSZ)) == NULL)
+ return ZE_MEM;
+ m = 0;
+ while (n == (uzoff_t)(-1L) || m < n)
+ {
+ if ((k = fread(b, 1, n == (uzoff_t)(-1) ?
+ CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
+ {
+ if (ferror(f))
+ {
+ free((zvoid *)b);
+ return ZE_READ;
+ }
+ else
+ break;
+ }
+ if (fwrite(b, 1, k, g) != k)
+ {
+ free((zvoid *)b);
+ fprintf(mesg," fcopy: write error\n");
+ return ZE_TEMP;
+ }
+ m += k;
+ }
+ free((zvoid *)b);
+ return ZE_OK;
+}
+
+
+/* from zipfile.c */
+
+#ifdef THEOS
+ /* Macros cause stack overflow in compiler */
+ ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); }
+ ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); }
+#else /* !THEOS */
+ /* Macros for converting integers in little-endian to machine format */
+# define SH(a) ((ush)(((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8)))
+# define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
+# ifdef ZIP64_SUPPORT /* zip64 support 08/31/2003 R.Nausedat */
+# define LLG(a) ((zoff_t)LG(a) | ((zoff_t)LG((a)+4) << 32))
+# endif
+#endif /* ?THEOS */
+
+
+/* always copies from global in_file to global output file y */
+int bfcopy(n)
+ /* now use uzoff_t for all file sizes 5/14/05 CS */
+ uzoff_t n; /* number of bytes to copy or -1 for all */
+/* Copy n bytes from in_file to out_file, or until EOF if (zoff_t)n == -1.
+
+ Normally we have the compressed size from either the central directory
+ entry or the local header.
+
+ If n != -1 and EOF, close current split and open next and continue
+ copying.
+
+ If n == -2, copy until find the extended header (data descriptor). Only
+ used for -FF when no size available.
+
+ If fix == 1 calculate CRC of input entry and verify matches.
+
+ If fix == 2 and this entry using data descriptor keep a sliding
+ window in the buffer for looking for signature.
+
+ Return an error code in the ZE_ class. */
+{
+ char *b; /* malloc'ed buffer for copying */
+ extent k; /* result of fread() */
+ uzoff_t m; /* bytes copied so far */
+ extent brd; /* bytes to read */
+ zoff_t data_start = 0;
+ zoff_t des_start = 0;
+ char *split_path;
+ extent kk;
+ int i;
+ char sbuf[4]; /* buffer for sliding signature window for fix = 2 */
+ int des = 0; /* this entry has data descriptor to find */
+
+ if ((b = malloc(CBSZ)) == NULL)
+ return ZE_MEM;
+
+ if (copy_only && !display_globaldots) {
+ /* initialize dot count */
+ dot_count = -1;
+ }
+
+ if (fix == 2 && n == (uzoff_t) -2) {
+ data_start = zftello(in_file);
+ for (kk = 0; kk < 4; kk++)
+ sbuf[kk] = 0;
+ des = 1;
+ }
+
+ des_good = 0;
+
+ m = 0;
+ while (des || n == (uzoff_t)(-1L) || m < n)
+ {
+ if (des || n == (uzoff_t)(-1))
+ brd = CBSZ;
+ else
+ brd = (n - m < CBSZ ? (extent)(n - m) : CBSZ);
+
+ des_start = zftello(in_file);
+
+ if ((k = fread(b, 1, brd, in_file)) == 0)
+ {
+ if (fix == 2 && k < brd) {
+ free((zvoid *)b);
+ return ZE_READ;
+ }
+ else if (ferror(in_file))
+ {
+ free((zvoid *)b);
+ return ZE_READ;
+ }
+ else {
+ break;
+ }
+ }
+
+
+ /* end at extended local header (data descriptor) signature */
+ if (des) {
+ des_crc = 0;
+ des_csize = 0;
+ des_usize = 0;
+
+ /* If first 4 bytes in buffer are data descriptor signature then
+ try to read the data descriptor.
+ If not, scan for signature and break if found, let bfwrite flush
+ the data and then next read should put the data descriptor at
+ the beginning of the buffer.
+ */
+
+ if (
+ (b[0] != 0x50 /*'P' except EBCDIC*/ ||
+ b[1] != 0x4b /*'K' except EBCDIC*/ ||
+ b[2] != '\07' ||
+ b[3] != '\010')) {
+ /* buffer is not start of data descriptor */
+
+ for (kk = 0; kk < k; kk++) {
+ /* add byte to end of sbuf */
+ for (i = 0; i < 3; i++)
+ sbuf[i] = sbuf[i + 1];
+ sbuf[3] = b[kk];
+
+ /* see if this is signature */
+ if (
+ (sbuf[0] == 0x50 /*'P' except EBCDIC*/ &&
+ sbuf[1] == 0x4b /*'K' except EBCDIC*/ &&
+ sbuf[2] == '\07' &&
+ sbuf[3] == '\010')) {
+ kk -= 3;
+ if (zfseeko(in_file, bytes_this_split + kk, SEEK_SET) != 0) {
+ /* seek error */
+ ZIPERR(ZE_READ, "seek failed reading descriptor");
+ }
+ des_start = zftello(in_file);
+ k = kk;
+ break;
+ }
+ }
+ }
+ else
+
+ /* signature at start of buffer */
+ {
+ des_good = 0;
+
+#ifdef ZIP64_SUPPORT
+ if (zip64_entry) {
+
+ /* read Zip64 data descriptor */
+ if (k < 24) {
+ /* not enough bytes, so can't be data descriptor
+ as data descriptors can't be split across splits
+ */
+ }
+ else
+ {
+ /* read the Zip64 descriptor */
+
+ des_crc = LG(b + 4);
+ des_csize = LLG(b + 8);
+ des_usize = LLG(b + 16);
+
+ /* if this is the right data descriptor then the sizes should match */
+ if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
+ /* apparently this signature does not go with this data so skip */
+
+ /* write out signature as data */
+ k = 4;
+ if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+ /* seek error */
+ ZIPERR(ZE_READ, "seek failed reading descriptor");
+ }
+ if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
+ {
+ free((zvoid *)b);
+ fprintf(mesg," fcopy: write error\n");
+ return ZE_TEMP;
+ }
+ m += k;
+ continue;
+ }
+ else
+ {
+ /* apparently this is the correct data descriptor */
+
+ /* we should check the CRC but would need to inflate
+ the data */
+
+ /* skip descriptor as will write out later */
+ des_good = 1;
+ k = 24;
+ data_start = zftello(in_file);
+ if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+ /* seek error */
+ ZIPERR(ZE_READ, "seek failed reading descriptor");
+ }
+ data_start = zftello(in_file);
+ }
+ }
+
+ }
+ else
+#endif
+ {
+ /* read standard data descriptor */
+
+ if (k < 16) {
+ /* not enough bytes, so can't be data descriptor
+ as data descriptors can't be split across splits
+ */
+ }
+ else
+ {
+ /* read the descriptor */
+
+ des_crc = LG(b + 4);
+ des_csize = LG(b + 8);
+ des_usize = LG(b + 12);
+
+ /* if this is the right data descriptor then the sizes should match */
+ if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
+ /* apparently this signature does not go with this data so skip */
+
+ /* write out signature as data */
+ k = 4;
+ if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+ /* seek error */
+ ZIPERR(ZE_READ, "seek failed reading descriptor");
+ }
+ if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
+ {
+ free((zvoid *)b);
+ fprintf(mesg," fcopy: write error\n");
+ return ZE_TEMP;
+ }
+ m += k;
+ continue;
+ }
+ else
+ {
+ /* apparently this is the correct data descriptor */
+
+ /* we should check the CRC but this does not work for
+ encrypted data */
+
+ /* skip descriptor as will write out later */
+ des_good = 1;
+ data_start = zftello(in_file);
+ k = 16;
+ if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
+ /* seek error */
+ ZIPERR(ZE_READ, "seek failed reading descriptor");
+ }
+ data_start = zftello(in_file);
+ }
+ }
+
+
+ }
+ }
+ }
+
+
+ if (des_good) {
+ /* skip descriptor as will write out later */
+ } else {
+ /* write out apparently wrong descriptor as data */
+ if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
+ {
+ free((zvoid *)b);
+ fprintf(mesg," fcopy: write error\n");
+ return ZE_TEMP;
+ }
+ m += k;
+ }
+
+ if (copy_only && !display_globaldots) {
+ if (dot_size > 0) {
+ /* initial space */
+ if (noisy && dot_count == -1) {
+#ifndef WINDLL
+ putc(' ', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",' ');
+#endif
+ dot_count++;
+ }
+ dot_count += k;
+ if (dot_size <= dot_count) dot_count = 0;
+ }
+ if ((verbose || noisy) && dot_size && !dot_count) {
+#ifndef WINDLL
+ putc('.', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",'.');
+#endif
+ mesg_line_started = 1;
+ }
+ }
+
+ if (des_good)
+ break;
+
+ if (des)
+ continue;
+
+ if ((des || n != (uzoff_t)(-1L)) && m < n && feof(in_file)) {
+ /* open next split */
+ current_in_disk++;
+
+ if (current_in_disk >= total_disks) {
+ /* done */
+ break;
+
+ } else if (current_in_disk == total_disks - 1) {
+ /* last disk is archive.zip */
+ if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+ zipwarn("reading archive: ", in_path);
+ return ZE_MEM;
+ }
+ strcpy(split_path, in_path);
+ } else {
+ /* other disks are archive.z01, archive.z02, ... */
+ split_path = get_in_split_path(in_path, current_in_disk);
+ }
+
+ fclose(in_file);
+
+ /* open the split */
+ while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+ int r = 0;
+
+ /* could not open split */
+
+ if (fix == 1 && skip_this_disk) {
+ free(split_path);
+ free((zvoid *)b);
+ return ZE_FORM;
+ }
+
+ /* Ask for directory with split. Updates in_path */
+ r = ask_for_split_read_path(current_in_disk);
+ if (r == ZE_ABORT) {
+ zipwarn("could not find split: ", split_path);
+ free(split_path);
+ free((zvoid *)b);
+ return ZE_ABORT;
+ }
+ if (r == ZE_EOF) {
+ zipmessage_nl("", 1);
+ zipwarn("user ended reading - closing archive", "");
+ free(split_path);
+ free((zvoid *)b);
+ return ZE_EOF;
+ }
+ if (fix == 2 && skip_this_disk) {
+ /* user asked to skip this disk */
+ zipwarn("skipping split file: ", split_path);
+ current_in_disk++;
+ }
+
+ if (current_in_disk == total_disks - 1) {
+ /* last disk is archive.zip */
+ if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+ zipwarn("reading archive: ", in_path);
+ return ZE_MEM;
+ }
+ strcpy(split_path, in_path);
+ } else {
+ /* other disks are archive.z01, archive.z02, ... */
+ split_path = get_in_split_path(zipfile, current_in_disk);
+ }
+ }
+ if (fix == 2 && skip_this_disk) {
+ /* user asked to skip this disk */
+ free(split_path);
+ free((zvoid *)b);
+ return ZE_FORM;
+ }
+ free(split_path);
+ }
+ }
+ free((zvoid *)b);
+ return ZE_OK;
+}
+
+
+
+#ifdef NO_RENAME
+int rename(from, to)
+ZCONST char *from;
+ZCONST char *to;
+{
+ unlink(to);
+ if (link(from, to) == -1)
+ return -1;
+ if (unlink(from) == -1)
+ return -1;
+ return 0;
+}
+
+#endif /* NO_RENAME */
+
+
+#ifdef ZMEM
+
+/************************/
+/* Function memset() */
+/************************/
+
+/*
+ * memset - for systems without it
+ * bill davidsen - March 1990
+ */
+
+char *
+memset(buf, init, len)
+register char *buf; /* buffer loc */
+register int init; /* initializer */
+register unsigned int len; /* length of the buffer */
+{
+ char *start;
+
+ start = buf;
+ while (len--) *(buf++) = init;
+ return(start);
+}
+
+
+/************************/
+/* Function memcpy() */
+/************************/
+
+char *
+memcpy(dst,src,len) /* v2.0f */
+register char *dst, *src;
+register unsigned int len;
+{
+ char *start;
+
+ start = dst;
+ while (len--)
+ *dst++ = *src++;
+ return(start);
+}
+
+
+/************************/
+/* Function memcmp() */
+/************************/
+
+int
+memcmp(b1,b2,len) /* jpd@usl.edu -- 11/16/90 */
+register char *b1, *b2;
+register unsigned int len;
+{
+
+ if (len) do { /* examine each byte (if any) */
+ if (*b1++ != *b2++)
+ return (*((uch *)b1-1) - *((uch *)b2-1)); /* exit when miscompare */
+ } while (--len);
+
+ return(0); /* no miscompares, yield 0 result */
+}
+
+#endif /* ZMEM */
+
+
+/*------------------------------------------------------------------
+ * Split archives
+ */
+
+
+/* ask_for_split_read_path
+ *
+ * If the next split file is not in the current directory, ask
+ * the user where it is.
+ *
+ * in_path is the base path for reading splits and is usually
+ * the same as zipfile. The path in in_path must be the archive
+ * file ending in .zip as this is assumed by get_in_split_path().
+ *
+ * Updates in_path if changed. Returns ZE_OK if OK or ZE_ABORT if
+ * user cancels reading archive.
+ *
+ * If fix = 1 then allow skipping disk (user may not have it).
+ */
+
+#define SPLIT_MAXPATH (FNMAX + 4010)
+
+int ask_for_split_read_path(current_disk)
+ ulg current_disk;
+{
+ FILE *f;
+ int is_readable = 0;
+ int i;
+ char *split_dir = NULL;
+ char *archive_name = NULL;
+ char *split_name = NULL;
+ char *split_path = NULL;
+ char buf[SPLIT_MAXPATH + 100];
+
+ /* get split path */
+ split_path = get_in_split_path(in_path, current_disk);
+
+ /* get the directory */
+ if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(split_dir, in_path);
+
+ /* remove any name at end */
+ for (i = strlen(split_dir) - 1; i >= 0; i--) {
+ if (split_dir[i] == '/' || split_dir[i] == '\\'
+ || split_dir[i] == ':') {
+ split_dir[i + 1] = '\0';
+ break;
+ }
+ }
+ if (i < 0)
+ split_dir[0] = '\0';
+
+ /* get the name of the archive */
+ if ((archive_name = malloc(strlen(in_path) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ if (strlen(in_path) == strlen(split_dir)) {
+ archive_name[0] = '\0';
+ } else {
+ strcpy(archive_name, in_path + strlen(split_dir));
+ }
+
+ /* get the name of the split */
+ if ((split_name = malloc(strlen(split_path) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ if (strlen(in_path) == strlen(split_dir)) {
+ split_name[0] = '\0';
+ } else {
+ strcpy(split_name, split_path + strlen(split_dir));
+ }
+ if (i < 0) {
+ strcpy(split_dir, "(current directory)");
+ }
+
+ fprintf(mesg, "\n\nCould not find:\n");
+ fprintf(mesg, " %s\n", split_path);
+ /*
+ fprintf(mesg, "Please enter the path directory (. for cur dir) where\n");
+ fprintf(mesg, " %s\n", split_name);
+ fprintf(mesg, "is located\n");
+ */
+ for (;;) {
+ if (is_readable) {
+ fprintf(mesg, "\nHit c (change path to where this split file is)");
+ fprintf(mesg, "\n q (abort archive - quit)");
+ fprintf(mesg, "\n or ENTER (continue with this split): ");
+ } else {
+ if (fix == 1) {
+ fprintf(mesg, "\nHit c (change path to where this split file is)");
+ fprintf(mesg, "\n s (skip this split)");
+ fprintf(mesg, "\n q (abort archive - quit)");
+ fprintf(mesg, "\n or ENTER (try reading this split again): ");
+ } else if (fix == 2) {
+ fprintf(mesg, "\nHit c (change path to where this split file is)");
+ fprintf(mesg, "\n s (skip this split)");
+ fprintf(mesg, "\n q (abort archive - quit)");
+ fprintf(mesg, "\n e (end this archive - no more splits)");
+ fprintf(mesg, "\n z (look for .zip split - the last split)");
+ fprintf(mesg, "\n or ENTER (try reading this split again): ");
+ } else {
+ fprintf(mesg, "\nHit c (change path to where this split file is)");
+ fprintf(mesg, "\n q (abort archive - quit)");
+ fprintf(mesg, "\n or ENTER (try reading this split again): ");
+ }
+ }
+ fflush(mesg);
+ fgets(buf, SPLIT_MAXPATH, stdin);
+ /* remove any newline */
+ for (i = 0; buf[i]; i++) {
+ if (buf[i] == '\n') {
+ buf[i] = '\0';
+ break;
+ }
+ }
+ if (toupper(buf[0]) == 'Q') {
+ return ZE_ABORT;
+ } else if ((fix == 1 || fix == 2) && toupper(buf[0]) == 'S') {
+ /*
+ fprintf(mesg, "\nSkip this split/disk? (files in this split will not be recovered) [n/y] ");
+ fflush(mesg);
+ fgets(buf, SPLIT_MAXPATH, stdin);
+ if (buf[0] == 'y' || buf[0] == 'Y') {
+ */
+ skip_this_disk = current_in_disk + 1;
+ return ZE_FORM;
+ } else if (toupper(buf[0]) == 'C') {
+ fprintf(mesg, "\nEnter path where this split is (ENTER = same dir, . = current dir)");
+ fprintf(mesg, "\n: ");
+ fflush(mesg);
+ fgets(buf, SPLIT_MAXPATH, stdin);
+ is_readable = 0;
+ /* remove any newline */
+ for (i = 0; buf[i]; i++) {
+ if (buf[i] == '\n') {
+ buf[i] = '\0';
+ break;
+ }
+ }
+ if (buf[0] == '\0') {
+ /* Hit ENTER so try old path again - could be removable media was changed */
+ strcpy(buf, split_path);
+ }
+ } else if (fix == 2 && toupper(buf[0]) == 'E') {
+ /* no more splits to read */
+ return ZE_EOF;
+ } else if (fix == 2 && toupper(buf[0]) == 'Z') {
+ total_disks = current_disk + 1;
+ free(split_path);
+ split_path = get_in_split_path(in_path, current_disk);
+ buf[0] = '\0';
+ strncat(buf, split_path, SPLIT_MAXPATH);
+ }
+ if (strlen(buf) > 0) {
+ /* changing path */
+
+ /* check if user wants current directory */
+ if (buf[0] == '.' && buf[1] == '\0') {
+ buf[0] = '\0';
+ }
+ /* remove any name at end */
+ for (i = strlen(buf); i >= 0; i--) {
+ if (buf[i] == '/' || buf[i] == '\\'
+ || buf[i] == ':') {
+ buf[i + 1] = '\0';
+ break;
+ }
+ }
+ /* update base_path to newdir/split_name - in_path is the .zip file path */
+ free(in_path);
+ if (i < 0) {
+ /* just name so current directory */
+ strcpy(buf, "(current directory)");
+ if (archive_name == NULL) {
+ i = 0;
+ } else {
+ i = strlen(archive_name);
+ }
+ if ((in_path = malloc(strlen(archive_name) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(in_path, archive_name);
+ } else {
+ /* not the current directory */
+ /* remove any name at end */
+ for (i = strlen(buf); i >= 0; i--) {
+ if (buf[i] == '/') {
+ buf[i + 1] = '\0';
+ break;
+ }
+ }
+ if (i < 0) {
+ buf[0] = '\0';
+ }
+ if ((in_path = malloc(strlen(buf) + strlen(archive_name) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(in_path, buf);
+ strcat(in_path, archive_name);
+ }
+
+ free(split_path);
+
+ /* get split path */
+ split_path = get_in_split_path(in_path, current_disk);
+
+ free(split_dir);
+ if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(split_dir, in_path);
+ /* remove any name at end */
+ for (i = strlen(split_dir); i >= 0; i--) {
+ if (split_dir[i] == '/') {
+ split_dir[i + 1] = '\0';
+ break;
+ }
+ }
+
+ /* try to open it */
+ if ((f = fopen(split_path, "r")) == NULL) {
+ fprintf(mesg, "\nCould not find or open\n");
+ fprintf(mesg, " %s\n", split_path);
+ /*
+ fprintf(mesg, "Please enter the path (. for cur dir) where\n");
+ fprintf(mesg, " %s\n", split_name);
+ fprintf(mesg, "is located\n");
+ */
+ continue;
+ }
+ fclose(f);
+ is_readable = 1;
+ fprintf(mesg, "Found: %s\n", split_path);
+ } else {
+ /* try to open it */
+ if ((f = fopen(split_path, "r")) == NULL) {
+ fprintf(mesg, "\nCould not find or open\n");
+ fprintf(mesg, " %s\n", split_path);
+ /*
+ fprintf(mesg, "Please enter the path (. for cur dir) where\n");
+ fprintf(mesg, " %s\n", split_name);
+ fprintf(mesg, "is located\n");
+ */
+ continue;
+ }
+ fclose(f);
+ is_readable = 1;
+ fprintf(mesg, "\nFound: %s\n", split_path);
+ break;
+ }
+ }
+ free(archive_name);
+ free(split_dir);
+ free(split_name);
+
+ return ZE_OK;
+}
+
+
+/* ask_for_split_write_path
+ *
+ * Verify the directory for the next split. Called
+ * when -sp is used to pause between writing splits.
+ *
+ * Updates out_path and return 1 if OK or 0 if cancel
+ */
+int ask_for_split_write_path(current_disk)
+ ulg current_disk;
+{
+ unsigned int num = (unsigned int)current_disk + 1;
+ int i;
+ char *split_dir = NULL;
+ char *split_name = NULL;
+ char buf[FNMAX + 40];
+
+ /* get the directory */
+ if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(split_dir, out_path);
+
+ /* remove any name at end */
+ for (i = strlen(split_dir); i >= 0; i--) {
+ if (split_dir[i] == '/' || split_dir[i] == '\\'
+ || split_dir[i] == ':') {
+ split_dir[i + 1] = '\0';
+ break;
+ }
+ }
+
+ /* get the name of the split */
+ if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ if (strlen(out_path) == strlen(split_dir)) {
+ split_name[0] = '\0';
+ } else {
+ strcpy(split_name, out_path + strlen(split_dir));
+ }
+ if (i < 0) {
+ strcpy(split_dir, "(current directory)");
+ }
+ if (mesg_line_started)
+ fprintf(mesg, "\n");
+ fprintf(mesg, "\nOpening disk %d\n", num);
+ fprintf(mesg, "Hit ENTER to write to default path of\n");
+ fprintf(mesg, " %s\n", split_dir);
+ fprintf(mesg, "or enter a new directory path (. for cur dir) and hit ENTER\n");
+ for (;;) {
+ fprintf(mesg, "\nPath (or hit ENTER to continue): ");
+ fflush(mesg);
+ fgets(buf, FNMAX, stdin);
+ /* remove any newline */
+ for (i = 0; buf[i]; i++) {
+ if (buf[i] == '\n') {
+ buf[i] = '\0';
+ break;
+ }
+ }
+ if (strlen(buf) > 0) {
+ /* changing path */
+
+ /* current directory */
+ if (buf[0] == '.' && buf[1] == '\0') {
+ buf[0] = '\0';
+ }
+ /* remove any name at end */
+ for (i = strlen(buf); i >= 0; i--) {
+ if (buf[i] == '/' || buf[i] == '\\'
+ || buf[i] == ':') {
+ buf[i + 1] = '\0';
+ break;
+ }
+ }
+ /* update out_path to newdir/split_name */
+ free(out_path);
+ if (i < 0) {
+ /* just name so current directory */
+ strcpy(buf, "(current directory)");
+ if (split_name == NULL) {
+ i = 0;
+ } else {
+ i = strlen(split_name);
+ }
+ if ((out_path = malloc(strlen(split_name) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(out_path, split_name);
+ } else {
+ /* not the current directory */
+ /* remove any name at end */
+ for (i = strlen(buf); i >= 0; i--) {
+ if (buf[i] == '/') {
+ buf[i + 1] = '\0';
+ break;
+ }
+ }
+ if (i < 0) {
+ buf[0] = '\0';
+ }
+ if ((out_path = malloc(strlen(buf) + strlen(split_name) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(out_path, buf);
+ strcat(out_path, split_name);
+ }
+ fprintf(mesg, "Writing to:\n %s\n", buf);
+ free(split_name);
+ free(split_dir);
+ if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(split_dir, out_path);
+ /* remove any name at end */
+ for (i = strlen(split_dir); i >= 0; i--) {
+ if (split_dir[i] == '/') {
+ split_dir[i + 1] = '\0';
+ break;
+ }
+ }
+ if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ strcpy(split_name, out_path + strlen(split_dir));
+ } else {
+ break;
+ }
+ }
+ free(split_dir);
+ free(split_name);
+
+ /* for now no way out except Ctrl C */
+ return 1;
+}
+
+
+/* split_name
+ *
+ * get name of split being read
+ */
+char *get_in_split_path(base_path, disk_number)
+ char *base_path;
+ ulg disk_number;
+{
+ char *split_path = NULL;
+ int base_len = 0;
+ int path_len = 0;
+ ulg num = disk_number + 1;
+ char ext[6];
+#ifdef VMS
+ int vers_len; /* File version length. */
+ char *vers_ptr; /* File version string. */
+#endif /* def VMS */
+
+ /*
+ * A split has extension z01, z02, ..., z99, z100, z101, ... z999
+ * We currently support up to .z99999
+ * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
+ * so use that. Means on DOS can only have 100 splits.
+ */
+
+ if (num == total_disks) {
+ /* last disk is base path */
+ if ((split_path = malloc(strlen(base_path) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "base path");
+ }
+ strcpy(split_path, base_path);
+
+ return split_path;
+ } else {
+ if (num > 99999) {
+ ZIPERR(ZE_BIG, "More than 99999 splits needed");
+ }
+ sprintf(ext, "z%02lu", num);
+ }
+
+ /* create path for this split - zip.c checked for .zip extension */
+ base_len = strlen(base_path) - 3;
+ path_len = base_len + strlen(ext);
+
+#ifdef VMS
+ /* On VMS, locate the file version, and adjust base_len accordingly.
+ Note that path_len is correct, as-is.
+ */
+ vers_ptr = vms_file_version( base_path);
+ vers_len = strlen( vers_ptr);
+ base_len -= vers_len;
+#endif /* def VMS */
+
+ if ((split_path = malloc(path_len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ /* copy base_path except for end zip */
+ strcpy(split_path, base_path);
+ split_path[base_len] = '\0';
+ /* add extension */
+ strcat(split_path, ext);
+
+#ifdef VMS
+ /* On VMS, append (preserve) the file version. */
+ strcat(split_path, vers_ptr);
+#endif /* def VMS */
+
+ return split_path;
+}
+
+
+/* split_name
+ *
+ * get name of split being written
+ */
+char *get_out_split_path(base_path, disk_number)
+ char *base_path;
+ ulg disk_number;
+{
+ char *split_path = NULL;
+ int base_len = 0;
+ int path_len = 0;
+ ulg num = disk_number + 1;
+ char ext[6];
+#ifdef VMS
+ int vers_len; /* File version length. */
+ char *vers_ptr; /* File version string. */
+#endif /* def VMS */
+
+ /*
+ * A split has extension z01, z02, ..., z99, z100, z101, ... z999
+ * We currently support up to .z99999
+ * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
+ * so use that. Means on DOS can only have 100 splits.
+ */
+
+ if (num > 99999) {
+ ZIPERR(ZE_BIG, "More than 99999 splits needed");
+ }
+ sprintf(ext, "z%02lu", num);
+
+ /* create path for this split - zip.c checked for .zip extension */
+ base_len = strlen(base_path) - 3;
+ path_len = base_len + strlen(ext);
+
+#ifdef VMS
+ /* On VMS, locate the file version, and adjust base_len accordingly.
+ Note that path_len is correct, as-is.
+ */
+ vers_ptr = vms_file_version( base_path);
+ vers_len = strlen( vers_ptr);
+ base_len -= vers_len;
+#endif /* def VMS */
+
+ if ((split_path = malloc(path_len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "split path");
+ }
+ /* copy base_path except for end zip */
+ strcpy(split_path, base_path);
+ split_path[base_len] = '\0';
+ /* add extension */
+ strcat(split_path, ext);
+
+#ifdef VMS
+ /* On VMS, append (preserve) the file version. */
+ strcat(split_path, vers_ptr);
+#endif /* def VMS */
+
+ return split_path;
+}
+
+/* close_split
+ *
+ * close a split - assume that the paths needed for the splits are
+ * available.
+ */
+int close_split(disk_number, tempfile, temp_name)
+ ulg disk_number;
+ FILE *tempfile;
+ char *temp_name;
+{
+ char *split_path = NULL;
+
+ split_path = get_out_split_path(out_path, disk_number);
+
+ if (noisy_splits) {
+ zipmessage("\tClosing split ", split_path);
+ }
+
+ fclose(tempfile);
+
+ rename_split(temp_name, split_path);
+ set_filetype(split_path);
+
+ return ZE_OK;
+}
+
+/* bfwrite
+ Does the fwrite but also counts bytes and does splits */
+size_t bfwrite(buffer, size, count, mode)
+ ZCONST void *buffer;
+ size_t size;
+ size_t count;
+ int mode;
+{
+ size_t bytes_written = 0;
+ size_t r;
+ size_t b = size * count;
+ uzoff_t bytes_left_in_split = 0;
+ size_t bytes_to_write = b;
+
+
+ /* -------------------------------- */
+ /* local header */
+ if (mode == BFWRITE_LOCALHEADER) {
+ /* writing local header - reset entry data count */
+ bytes_this_entry = 0;
+ /* save start of local header so we can rewrite later */
+ current_local_file = y;
+ current_local_disk = current_disk;
+ current_local_offset = bytes_this_split;
+ }
+
+ if (split_size == 0)
+ bytes_left_in_split = bytes_to_write;
+ else
+ bytes_left_in_split = split_size - bytes_this_split;
+
+ if (bytes_to_write > bytes_left_in_split) {
+ if (mode == BFWRITE_HEADER ||
+ mode == BFWRITE_LOCALHEADER ||
+ mode == BFWRITE_CENTRALHEADER) {
+ /* if can't write entire header save for next split */
+ bytes_to_write = 0;
+ } else {
+ /* normal data so fill the split */
+ bytes_to_write = (size_t)bytes_left_in_split;
+ }
+ }
+
+ /* -------------------------------- */
+ /* central header */
+ if (mode == BFWRITE_CENTRALHEADER) {
+ /* set start disk for CD */
+ if (cd_start_disk == (ulg)-1) {
+ cd_start_disk = current_disk;
+ cd_start_offset = bytes_this_split;
+ }
+ cd_entries_this_disk++;
+ total_cd_entries++;
+ }
+
+ /* -------------------------------- */
+ if (bytes_to_write > 0) {
+ /* write out the bytes for this split */
+ r = fwrite(buffer, size, bytes_to_write, y);
+ bytes_written += r;
+ bytes_to_write = b - r;
+ bytes_this_split += r;
+ if (mode == BFWRITE_DATA)
+ /* if data descriptor do not include in count */
+ bytes_this_entry += r;
+ } else {
+ bytes_to_write = b;
+ }
+
+ if (bytes_to_write > 0) {
+ if (split_method) {
+ /* still bytes to write so close split and open next split */
+ bytes_prev_splits += bytes_this_split;
+
+ if (split_method == 1 && ferror(y)) {
+ /* if writing all splits to same place and have problem then bad */
+ ZIPERR(ZE_WRITE, "Could not write split");
+ }
+
+ if (split_method == 2 && ferror(y)) {
+ /* A split must be at least 64K except last .zip split */
+ if (bytes_this_split < 64 * (uzoff_t)0x400) {
+ ZIPERR(ZE_WRITE, "Not enough space to write split");
+ }
+ }
+
+ /* close this split */
+ if (split_method == 1 && current_local_disk == current_disk) {
+ /* keep split open so can update it */
+ current_local_tempname = tempzip;
+ } else {
+ /* close split */
+ close_split(current_disk, y, tempzip);
+ y = NULL;
+ free(tempzip);
+ tempzip = NULL;
+ }
+ cd_entries_this_disk = 0;
+ bytes_this_split = 0;
+
+ /* increment disk - disks are numbered 0, 1, 2, ... and
+ splits are 01, 02, ... */
+ current_disk++;
+
+ if (split_method == 2 && split_bell) {
+ /* bell when pause to ask for next split */
+ putc('\007', mesg);
+ fflush(mesg);
+ }
+
+ for (;;) {
+ /* if method 2 pause and allow changing path */
+ if (split_method == 2) {
+ if (ask_for_split_write_path(current_disk) == 0) {
+ ZIPERR(ZE_ABORT, "could not write split");
+ }
+ }
+
+ /* open next split */
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+ {
+ int yd;
+ int i;
+
+ /* use mkstemp to avoid race condition and compiler warning */
+
+ if (tempath != NULL)
+ {
+ /* if -b used to set temp file dir use that for split temp */
+ if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, tempath);
+ if (lastchar(tempzip) != '/')
+ strcat(tempzip, "/");
+ }
+ else
+ {
+ /* create path by stripping name and appending template */
+ if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, zipfile);
+ for(i = strlen(tempzip); i > 0; i--) {
+ if (tempzip[i - 1] == '/')
+ break;
+ }
+ tempzip[i] = '\0';
+ }
+ strcat(tempzip, "ziXXXXXX");
+
+ if ((yd = mkstemp(tempzip)) == EOF) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ }
+#else
+ if ((tempzip = tempname(zipfile)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+#endif
+
+ r = fwrite((char *)buffer + bytes_written, 1, bytes_to_write, y);
+ bytes_written += r;
+ bytes_this_split += r;
+ if (!(mode == BFWRITE_HEADER ||
+ mode == BFWRITE_LOCALHEADER ||
+ mode == BFWRITE_CENTRALHEADER)) {
+ bytes_this_entry += r;
+ }
+ if (bytes_to_write > r) {
+ /* buffer bigger than split */
+ if (split_method == 2) {
+ /* let user choose another disk */
+ zipwarn("Not enough room on disk", "");
+ continue;
+ } else {
+ ZIPERR(ZE_WRITE, "Not enough room on disk");
+ }
+ }
+ if (mode == BFWRITE_LOCALHEADER ||
+ mode == BFWRITE_HEADER ||
+ mode == BFWRITE_CENTRALHEADER) {
+ if (split_method == 1 && current_local_file &&
+ current_local_disk != current_disk) {
+ /* We're opening a new split because the next header
+ did not fit on the last split. We need to now close
+ the last split and update the pointers for
+ the current split. */
+ close_split(current_local_disk, current_local_file,
+ current_local_tempname);
+ free(current_local_tempname);
+ }
+ current_local_tempname = tempzip;
+ current_local_file = y;
+ current_local_offset = 0;
+ current_local_disk = current_disk;
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* likely have more than fits but no splits */
+
+ /* probably already have error "no space left on device" */
+ /* could let flush_outbuf() handle error but bfwrite() is called for
+ headers also */
+ if (ferror(y))
+ ziperr(ZE_WRITE, "write error on zip file");
+ }
+ }
+
+
+ /* display dots for archive instead of for each file */
+ if (display_globaldots) {
+ if (dot_size > 0) {
+ /* initial space */
+ if (dot_count == -1) {
+#ifndef WINDLL
+ putc(' ', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",' ');
+#endif
+ /* assume a header will be written first, so avoid 0 */
+ dot_count = 1;
+ }
+ /* skip incrementing dot count for small buffers like for headers */
+ if (size * count > 1000) {
+ dot_count++;
+ if (dot_size <= dot_count * (zoff_t)size * (zoff_t)count) dot_count = 0;
+ }
+ }
+ if (dot_size && !dot_count) {
+ dot_count++;
+#ifndef WINDLL
+ putc('.', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",'.');
+#endif
+ mesg_line_started = 1;
+ }
+ }
+
+
+ return bytes_written;
+}
+
+
+#ifdef UNICODE_SUPPORT
+
+/*---------------------------------------------
+ * Unicode conversion functions
+ *
+ * Provided by Paul Kienitz
+ *
+ * Some modifications to work with Zip
+ *
+ *---------------------------------------------
+ */
+
+/*
+ NOTES APPLICABLE TO ALL STRING FUNCTIONS:
+
+ All of the x_to_y functions take parameters for an output buffer and
+ its available length, and return an int. The value returned is the
+ length of the string that the input produces, which may be larger than
+ the provided buffer length. If the returned value is less than the
+ buffer length, then the contents of the buffer will be null-terminated;
+ otherwise, it will not be terminated and may be invalid, possibly
+ stopping in the middle of a multibyte sequence.
+
+ In all cases you may pass NULL as the buffer and/or 0 as the length, if
+ you just want to learn how much space the string is going to require.
+
+ The functions will return -1 if the input is invalid UTF-8 or cannot be
+ encoded as UTF-8.
+*/
+
+/* utility functions for managing UTF-8 and UCS-4 strings */
+
+
+/* utf8_char_bytes
+ *
+ * Returns the number of bytes used by the first character in a UTF-8
+ * string, or -1 if the UTF-8 is invalid or null.
+ */
+local int utf8_char_bytes(utf8)
+ ZCONST char *utf8;
+{
+ int t, r;
+ unsigned lead;
+
+ if (!utf8)
+ return -1; /* no input */
+ lead = (unsigned char) *utf8;
+ if (lead < 0x80)
+ r = 1; /* an ascii-7 character */
+ else if (lead < 0xC0)
+ return -1; /* error: trailing byte without lead byte */
+ else if (lead < 0xE0)
+ r = 2; /* an 11 bit character */
+ else if (lead < 0xF0)
+ r = 3; /* a 16 bit character */
+ else if (lead < 0xF8)
+ r = 4; /* a 21 bit character (the most currently used) */
+ else if (lead < 0xFC)
+ r = 5; /* a 26 bit character (shouldn't happen) */
+ else if (lead < 0xFE)
+ r = 6; /* a 31 bit character (shouldn't happen) */
+ else
+ return -1; /* error: invalid lead byte */
+ for (t = 1; t < r; t++)
+ if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0)
+ return -1; /* error: not enough valid trailing bytes */
+ return r;
+}
+
+
+/* ucs4_char_from_utf8
+ *
+ * Given a reference to a pointer into a UTF-8 string, returns the next
+ * UCS-4 character and advances the pointer to the next character sequence.
+ * Returns ~0 and does not advance the pointer when input is ill-formed.
+ *
+ * Since the Unicode standard says 32-bit values won't be used (just
+ * up to the current 21-bit mappings) changed this to signed to allow -1 to
+ * be returned.
+ */
+long ucs4_char_from_utf8(utf8)
+ ZCONST char **utf8;
+{
+ ulg ret;
+ int t, bytes;
+
+ if (!utf8)
+ return -1; /* no input */
+ bytes = utf8_char_bytes(*utf8);
+ if (bytes <= 0)
+ return -1; /* invalid input */
+ if (bytes == 1)
+ ret = **utf8; /* ascii-7 */
+ else
+ ret = **utf8 & (0x7F >> bytes); /* lead byte of a multibyte sequence */
+ (*utf8)++;
+ for (t = 1; t < bytes; t++) /* consume trailing bytes */
+ ret = (ret << 6) | (*((*utf8)++) & 0x3F);
+ return (long) ret;
+}
+
+
+/* utf8_from_ucs4_char - Convert UCS char to UTF-8
+ *
+ * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6,
+ * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes.
+ */
+local int utf8_from_ucs4_char(utf8buf, ch)
+ char *utf8buf;
+ ulg ch;
+{
+ int trailing = 0;
+ int leadmask = 0x80;
+ int leadbits = 0x3F;
+ ulg tch = ch;
+ int ret;
+
+ if (ch > 0x7FFFFFFF)
+ return -1; /* UTF-8 can represent 31 bits */
+ if (ch < 0x7F)
+ {
+ *utf8buf++ = (char) ch; /* ascii-7 */
+ return 1;
+ }
+ do {
+ trailing++;
+ leadmask = (leadmask >> 1) | 0x80;
+ leadbits >>= 1;
+ tch >>= 6;
+ } while (tch & ~leadbits);
+ ret = trailing + 1;
+ /* produce lead byte */
+ *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing)));
+ /* produce trailing bytes */
+ while (--trailing >= 0)
+ *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F));
+ return ret;
+}
+
+
+/*===================================================================*/
+
+/* utf8_to_ucs4_string - convert UTF-8 string to UCS string
+ *
+ * Return UCS count. Now returns int so can return -1.
+ */
+local int utf8_to_ucs4_string(utf8, ucs4buf, buflen)
+ ZCONST char *utf8;
+ ulg *ucs4buf;
+ int buflen;
+{
+ int count = 0;
+
+ for (;;)
+ {
+ long ch = ucs4_char_from_utf8(&utf8);
+ if (ch == -1)
+ return -1;
+ else
+ {
+ if (ucs4buf && count < buflen)
+ ucs4buf[count] = ch;
+ if (ch == 0)
+ return count;
+ count++;
+ }
+ }
+}
+
+
+/* ucs4_string_to_utf8
+ *
+ *
+ */
+local int ucs4_string_to_utf8(ucs4, utf8buf, buflen)
+ ZCONST ulg *ucs4;
+ char *utf8buf;
+ int buflen;
+{
+ char mb[6];
+ int count = 0;
+
+ if (!ucs4)
+ return -1;
+ for (;;)
+ {
+ int mbl = utf8_from_ucs4_char(mb, *ucs4++);
+ int c;
+ if (mbl <= 0)
+ return -1;
+ /* We could optimize this a bit by passing utf8buf + count */
+ /* directly to utf8_from_ucs4_char when buflen >= count + 6... */
+ c = buflen - count;
+ if (mbl < c)
+ c = mbl;
+ if (utf8buf && count < buflen)
+ strncpy(utf8buf + count, mb, c);
+ if (mbl == 1 && !mb[0])
+ return count; /* terminating nul */
+ count += mbl;
+ }
+}
+
+
+#if 0 /* currently unused */
+/* utf8_chars
+ *
+ * Wrapper: counts the actual unicode characters in a UTF-8 string.
+ */
+local int utf8_chars(utf8)
+ ZCONST char *utf8;
+{
+ return utf8_to_ucs4_string(utf8, NULL, 0);
+}
+#endif
+
+
+/* --------------------------------------------------- */
+/* Unicode Support
+ *
+ * These functions common for all Unicode ports.
+ *
+ * These functions should allocate and return strings that can be
+ * freed with free().
+ *
+ * 8/27/05 EG
+ *
+ * Use zwchar for wide char which is unsigned long
+ * in zip.h and 32 bits. This avoids problems with
+ * different sizes of wchar_t.
+ */
+
+#ifdef WIN32
+
+zwchar *wchar_to_wide_string(wchar_string)
+ wchar_t *wchar_string;
+{
+ int i;
+ int wchar_len;
+ zwchar *wide_string;
+
+ wchar_len = wcslen(wchar_string);
+
+ if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) {
+ ZIPERR(ZE_MEM, "wchar to wide conversion");
+ }
+ for (i = 0; i <= wchar_len; i++) {
+ wide_string[i] = wchar_string[i];
+ }
+
+ return wide_string;
+}
+
+/* is_ascii_stringw
+ * Checks if a wide string is all ascii
+ */
+int is_ascii_stringw(wstring)
+ wchar_t *wstring;
+{
+ wchar_t *pw;
+ wchar_t cw;
+
+ if (wstring == NULL)
+ return 0;
+
+ for (pw = wstring; (cw = *pw) != '\0'; pw++) {
+ if (cw > 0x7F) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#endif
+
+/* is_ascii_string
+ * Checks if a string is all ascii
+ */
+int is_ascii_string(mbstring)
+ char *mbstring;
+{
+ char *p;
+ uch c;
+
+ if (mbstring == NULL)
+ return 0;
+
+ for (p = mbstring; (c = (uch)*p) != '\0'; p++) {
+ if (c > 0x7F) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* local to UTF-8 */
+char *local_to_utf8_string(local_string)
+ char *local_string;
+{
+ zwchar *wide_string = local_to_wide_string(local_string);
+ char *utf8_string = wide_to_utf8_string(wide_string);
+
+ free(wide_string);
+ return utf8_string;
+}
+
+/* wide_char_to_escape_string
+ provides a string that represents a wide char not in local char set
+
+ An initial try at an algorithm. Suggestions welcome.
+
+ If not an ASCII char, probably need 2 bytes at least. So if
+ a 2-byte wide encode it as 4 hex digits with a leading #U.
+ Since the Unicode standard has been frozen, it looks like 3 bytes
+ should be enough for any large Unicode character. In these cases
+ prefix the string with #L.
+ So
+ #U1234
+ is a 2-byte wide character with bytes 0x12 and 0x34 while
+ #L123456
+ is a 3-byte wide with bytes 0x12, 0x34, and 0x56.
+ On Windows, wide that need two wide characters as a surrogate pair
+ to represent them need to be converted to a single number.
+ */
+
+ /* set this to the max bytes an escape can be */
+#define MAX_ESCAPE_BYTES 8
+
+char *wide_char_to_escape_string(wide_char)
+ zwchar wide_char;
+{
+ int i;
+ zwchar w = wide_char;
+ uch b[9];
+ char e[7];
+ int len;
+ char *r;
+
+ /* fill byte array with zeros */
+ for (len = 0; len < sizeof(zwchar); len++) {
+ b[len] = 0;
+ }
+ /* get bytes in right to left order */
+ for (len = 0; w; len++) {
+ b[len] = (char)(w % 0x100);
+ w /= 0x100;
+ }
+
+ if ((r = malloc(MAX_ESCAPE_BYTES + 8)) == NULL) {
+ ZIPERR(ZE_MEM, "wide_char_to_escape_string");
+ }
+ strcpy(r, "#");
+ /* either 2 bytes or 4 bytes */
+ if (len < 3) {
+ len = 2;
+ strcat(r, "U");
+ } else {
+ len = 3;
+ strcat(r, "L");
+ }
+ for (i = len - 1; i >= 0; i--) {
+ sprintf(e, "%02x", b[i]);
+ strcat(r, e);
+ }
+ return r;
+}
+
+#if 0
+/* returns the wide character represented by the escape string */
+zwchar escape_string_to_wide(escape_string)
+ char *escape_string;
+{
+ int i;
+ zwchar w;
+ char c;
+ char u;
+ int len;
+ char *e = escape_string;
+
+ if (e == NULL) {
+ return 0;
+ }
+ if (e[0] != '#') {
+ /* no leading # */
+ return 0;
+ }
+ len = strlen(e);
+ /* either #U1234 or #L123456 format */
+ if (len != 6 && len != 8) {
+ return 0;
+ }
+ w = 0;
+ if (e[1] == 'L') {
+ if (len != 8) {
+ return 0;
+ }
+ /* 3 bytes */
+ for (i = 2; i < 8; i++) {
+ c = e[i];
+ u = toupper(c);
+ if (u >= 'A' && u <= 'F') {
+ w = w * 0x10 + (zwchar)(u + 10 - 'A');
+ } else if (c >= '0' && c <= '9') {
+ w = w * 0x10 + (zwchar)(c - '0');
+ } else {
+ return 0;
+ }
+ }
+ } else if (e[1] == 'U') {
+ /* 2 bytes */
+ for (i = 2; i < 6; i++) {
+ c = e[i];
+ u = toupper(c);
+ if (u >= 'A' && u <= 'F') {
+ w = w * 0x10 + (zwchar)(u + 10 - 'A');
+ } else if (c >= '0' && c <= '9') {
+ w = w * 0x10 + (zwchar)(c - '0');
+ } else {
+ return 0;
+ }
+ }
+ }
+ return w;
+}
+#endif
+
+
+char *local_to_escape_string(local_string)
+ char *local_string;
+{
+ zwchar *wide_string = local_to_wide_string(local_string);
+ char *escape_string = wide_to_escape_string(wide_string);
+
+ free(wide_string);
+ return escape_string;
+}
+
+#ifdef WIN32
+char *wchar_to_local_string(wstring)
+ wchar_t *wstring;
+{
+ zwchar *wide_string = wchar_to_wide_string(wstring);
+ char *local_string = wide_to_local_string(wide_string);
+
+ free(wide_string);
+
+ return local_string;
+}
+#endif
+
+
+#ifndef WIN32 /* The Win32 port uses a system-specific variant. */
+/* convert wide character string to multi-byte character string */
+char *wide_to_local_string(wide_string)
+ zwchar *wide_string;
+{
+ int i;
+ wchar_t wc;
+ int b;
+ int state_dependent;
+ int wsize = 0;
+ int max_bytes = MB_CUR_MAX;
+ char buf[9];
+ char *buffer = NULL;
+ char *local_string = NULL;
+
+ for (wsize = 0; wide_string[wsize]; wsize++) ;
+
+ if (MAX_ESCAPE_BYTES > max_bytes)
+ max_bytes = MAX_ESCAPE_BYTES;
+
+ if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wide_to_local_string");
+ }
+
+ /* convert it */
+ buffer[0] = '\0';
+ /* set initial state if state-dependent encoding */
+ wc = (wchar_t)'a';
+ b = wctomb(NULL, wc);
+ if (b == 0)
+ state_dependent = 0;
+ else
+ state_dependent = 1;
+ for (i = 0; i < wsize; i++) {
+ if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
+ /* wchar_t probably 2 bytes */
+ /* could do surrogates if state_dependent and wctomb can do */
+ wc = zwchar_to_wchar_t_default_char;
+ } else {
+ wc = (wchar_t)wide_string[i];
+ }
+ b = wctomb(buf, wc);
+ if (unicode_escape_all) {
+ if (b == 1 && (uch)buf[0] <= 0x7f) {
+ /* ASCII */
+ strncat(buffer, buf, b);
+ } else {
+ /* use escape for wide character */
+ char *e = wide_char_to_escape_string(wide_string[i]);
+ strcat(buffer, e);
+ free(e);
+ }
+ } else if (b > 0) {
+ /* multi-byte char */
+ strncat(buffer, buf, b);
+ } else {
+ /* no MB for this wide */
+ if (use_wide_to_mb_default) {
+ /* default character */
+ strcat(buffer, wide_to_mb_default_string);
+ } else {
+ /* use escape for wide character */
+ char *e = wide_char_to_escape_string(wide_string[i]);
+ strcat(buffer, e);
+ free(e);
+ }
+ }
+ }
+ if ((local_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
+ free(buffer);
+ ZIPERR(ZE_MEM, "wide_to_local_string");
+ }
+ strcpy(local_string, buffer);
+ free(buffer);
+
+ return local_string;
+}
+#endif /* !WIN32 */
+
+
+/* convert wide character string to escaped string */
+char *wide_to_escape_string(wide_string)
+ zwchar *wide_string;
+{
+ int i;
+ int wsize = 0;
+ char buf[9];
+ char *buffer = NULL;
+ char *escape_string = NULL;
+
+ for (wsize = 0; wide_string[wsize]; wsize++) ;
+
+ if ((buffer = (char *)malloc(wsize * MAX_ESCAPE_BYTES + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wide_to_escape_string");
+ }
+
+ /* convert it */
+ buffer[0] = '\0';
+ for (i = 0; i < wsize; i++) {
+ if (wide_string[i] <= 0x7f && isprint((char)wide_string[i])) {
+ /* ASCII */
+ buf[0] = (char)wide_string[i];
+ buf[1] = '\0';
+ strcat(buffer, buf);
+ } else {
+ /* use escape for wide character */
+ char *e = wide_char_to_escape_string(wide_string[i]);
+ strcat(buffer, e);
+ free(e);
+ }
+ }
+ if ((escape_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wide_to_escape_string");
+ }
+ strcpy(escape_string, buffer);
+ free(buffer);
+
+ return escape_string;
+}
+
+
+/* convert local string to display character set string */
+char *local_to_display_string(local_string)
+ char *local_string;
+{
+ char *temp_string;
+ char *display_string;
+
+ /* For Windows, OEM string should never be bigger than ANSI string, says
+ CharToOem description.
+ On UNIX, non-printable characters (0x00 - 0xFF) will be replaced by
+ "^x", so more space may be needed. Note that "^" itself is a valid
+ name character, so this leaves an ambiguity, but UnZip displays
+ names this way, too. (0x00 is not possible, I hope.)
+ For all other ports, just make a copy of local_string.
+ */
+
+#ifdef UNIX
+ char *cp_dst; /* Character pointers used in the */
+ char *cp_src; /* copying/changing procedure. */
+#endif
+
+ if ((temp_string = (char *)malloc(2 * strlen(local_string) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "local_to_display_string");
+ }
+
+#ifdef WIN32
+ /* convert to OEM display character set */
+ local_to_oem_string(temp_string, local_string);
+#else
+# ifdef UNIX
+ /* Copy source string, expanding non-printable characters to "^x". */
+ cp_dst = temp_string;
+ cp_src = local_string;
+ while (*cp_src != '\0') {
+ if ((unsigned char)*cp_src < ' ') {
+ *cp_dst++ = '^';
+ *cp_dst++ = '@'+ *cp_src++;
+ }
+ else {
+ *cp_dst++ = *cp_src++;
+ }
+ }
+ *cp_dst = '\0';
+# else /* not UNIX */
+ strcpy(temp_string, local_string);
+# endif /* UNIX */
+#endif
+
+#ifdef EBCDIC
+ {
+ char *ebc;
+
+ if ((ebc = malloc(strlen(display_string) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "local_to_display_string");
+ }
+ strtoebc(ebc, display_string);
+ free(display_string);
+ display_string = ebc;
+ }
+#endif
+
+ if ((display_string = (char *)malloc(strlen(temp_string) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "local_to_display_string");
+ }
+ strcpy(display_string, temp_string);
+ free(temp_string);
+
+ return display_string;
+}
+
+/* UTF-8 to local */
+char *utf8_to_local_string(utf8_string)
+ char *utf8_string;
+{
+ zwchar *wide_string = utf8_to_wide_string(utf8_string);
+ char *loc = wide_to_local_string(wide_string);
+ if (wide_string)
+ free(wide_string);
+ return loc;
+}
+
+/* UTF-8 to local */
+char *utf8_to_escape_string(utf8_string)
+ char *utf8_string;
+{
+ zwchar *wide_string = utf8_to_wide_string(utf8_string);
+ char *escape_string = wide_to_escape_string(wide_string);
+ free(wide_string);
+ return escape_string;
+}
+
+#ifndef WIN32 /* The Win32 port uses a system-specific variant. */
+/* convert multi-byte character string to wide character string */
+zwchar *local_to_wide_string(local_string)
+ char *local_string;
+{
+ int wsize;
+ wchar_t *wc_string;
+ zwchar *wide_string;
+
+ /* for now try to convert as string - fails if a bad char in string */
+ wsize = mbstowcs(NULL, local_string, MB_CUR_MAX );
+ if (wsize == (size_t)-1) {
+ /* could not convert */
+ return NULL;
+ }
+
+ /* convert it */
+ if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
+ ZIPERR(ZE_MEM, "local_to_wide_string");
+ }
+ wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1);
+ wc_string[wsize] = (wchar_t) 0;
+
+ /* in case wchar_t is not zwchar */
+ if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
+ ZIPERR(ZE_MEM, "local_to_wide_string");
+ }
+ for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ;
+ wide_string[wsize] = (zwchar)0;
+ free(wc_string);
+
+ return wide_string;
+}
+#endif /* !WIN32 */
+
+
+#if 0
+/* All wchar functions are only used by Windows and are
+ now in win32zip.c so that the Windows functions can
+ be used and multiple character wide characters can
+ be handled easily. */
+# ifndef WIN32
+char *wchar_to_utf8_string(wstring)
+ wchar_t *wstring;
+{
+ zwchar *wide_string = wchar_to_wide_string(wstring);
+ char *local_string = wide_to_utf8_string(wide_string);
+
+ free(wide_string);
+
+ return local_string;
+}
+# endif
+#endif
+
+
+/* convert wide string to UTF-8 */
+char *wide_to_utf8_string(wide_string)
+ zwchar *wide_string;
+{
+ int mbcount;
+ char *utf8_string;
+
+ /* get size of utf8 string */
+ mbcount = ucs4_string_to_utf8(wide_string, NULL, 0);
+ if (mbcount == -1)
+ return NULL;
+ if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wide_to_utf8_string");
+ }
+ mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1);
+ if (mbcount == -1)
+ return NULL;
+
+ return utf8_string;
+}
+
+/* convert UTF-8 string to wide string */
+zwchar *utf8_to_wide_string(utf8_string)
+ char *utf8_string;
+{
+ int wcount;
+ zwchar *wide_string;
+
+ wcount = utf8_to_ucs4_string(utf8_string, NULL, 0);
+ if (wcount == -1)
+ return NULL;
+ if ((wide_string = (zwchar *) malloc((wcount + 2) * sizeof(zwchar))) == NULL) {
+ ZIPERR(ZE_MEM, "utf8_to_wide_string");
+ }
+ wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1);
+
+ return wide_string;
+}
+
+
+#endif /* UNICODE_SUPPORT */
+
+
+/*---------------------------------------------------------------
+ * Long option support
+ * 8/23/2003
+ *
+ * Defines function get_option() to get and process the command
+ * line options and arguments from argv[]. The caller calls
+ * get_option() in a loop to get either one option and possible
+ * value or a non-option argument each loop.
+ *
+ * This version does not include argument file support and can
+ * work directly on argv. The argument file code complicates things and
+ * it seemed best to leave it out for now. If argument file support (reading
+ * in command line arguments stored in a file and inserting into
+ * command line where @filename is found) is added later the arguments
+ * can change and a freeable copy of argv will be needed and can be
+ * created using copy_args in the left out code.
+ *
+ * Supports short and long options as defined in the array options[]
+ * in zip.c, multiple short options in an argument (like -jlv), long
+ * option abbreviation (like --te for --temp-file if --te unique),
+ * short and long option values (like -b filename or --temp-file filename
+ * or --temp-file=filename), optional and required values, option negation
+ * by trailing - (like -S- to not include hidden and system files in MSDOS),
+ * value lists (like -x a b c), argument permuting (returning all options
+ * and values before any non-option arguments), and argument files (where any
+ * non-option non-value argument in form @path gets substituted with the
+ * white space separated arguments in the text file at path). In this
+ * version argument file support has been removed to simplify development but
+ * may be added later.
+ *
+ * E. Gordon
+ */
+
+
+/* message output - char casts are needed to handle constants */
+#define oWARN(message) zipwarn((char *) message, "")
+#define oERR(err,message) ZIPERR(err, (char *) message)
+
+
+/* Although the below provides some support for multibyte characters
+ the proper thing to do may be to use wide characters and support
+ Unicode. May get to it soon. EG
+ */
+
+/* For now stay with muti-byte characters. May support wide characters
+ in Zip 3.1.
+ */
+
+/* multibyte character set support
+ Multibyte characters use typically two or more sequential bytes
+ to represent additional characters than can fit in a single byte
+ character set. The code used here is based on the ANSI mblen function. */
+#ifdef MULTIBYTE_GETOPTNS
+ int mb_clen(ptr)
+ ZCONST char *ptr;
+ {
+ /* return the number of bytes that the char pointed to is. Return 1 if
+ null character or error like not start of valid multibyte character. */
+ int cl;
+
+ cl = mblen(ptr, MB_CUR_MAX);
+ return (cl > 0) ? cl : 1;
+ }
+#endif
+
+
+ /* moved to zip.h */
+#if 0
+#ifdef UNICODE_SUPPORT
+# define MB_CLEN(ptr) (1)
+# define MB_NEXTCHAR(ptr) ((ptr)++)
+# ifdef MULTIBYTE_GETOPTNS
+# undef MULTIBYTE_GETOPTNS
+# endif
+#else
+# ifdef _MBCS
+# ifndef MULTIBYTE_GETOPTNS
+# define MULTIBYTE_GETOPTNS
+# endif
+# endif
+/* multibyte character set support
+ Multibyte characters use typically two or more sequential bytes
+ to represent additional characters than can fit in a single byte
+ character set. The code used here is based on the ANSI mblen function. */
+# ifdef MULTIBYTE_GETOPTNS
+ local int mb_clen OF((ZCONST char *)); /* declare proto first */
+ local int mb_clen(ptr)
+ ZCONST char *ptr;
+ {
+ /* return the number of bytes that the char pointed to is. Return 1 if
+ null character or error like not start of valid multibyte character. */
+ int cl;
+
+ cl = mblen(ptr, MB_CUR_MAX);
+ return (cl > 0) ? cl : 1;
+ }
+# define MB_CLEN(ptr) mb_clen(ptr)
+# define MB_NEXTCHAR(ptr) ((ptr) += MB_CLEN(ptr))
+# else
+# define MB_CLEN(ptr) (1)
+# define MB_NEXTCHAR(ptr) ((ptr)++)
+# endif
+#endif
+#endif
+
+
+/* constants */
+
+/* function get_args_from_arg_file() can return this in depth parameter */
+#define ARG_FILE_ERR -1
+
+/* internal settings for optchar */
+#define SKIP_VALUE_ARG -1
+#define THIS_ARG_DONE -2
+#define START_VALUE_LIST -3
+#define IN_VALUE_LIST -4
+#define NON_OPTION_ARG -5
+#define STOP_VALUE_LIST -6
+/* 7/25/04 EG */
+#define READ_REST_ARGS_VERBATIM -7
+
+
+/* global veriables */
+
+int enable_permute = 1; /* yes - return options first */
+/* 7/25/04 EG */
+int doubledash_ends_options = 1; /* when -- what follows are not options */
+
+/* buffer for error messages (this sizing is a guess but must hold 2 paths) */
+#define OPTIONERR_BUF_SIZE (FNMAX * 2 + 4000)
+local char Far optionerrbuf[OPTIONERR_BUF_SIZE + 1];
+
+/* error messages */
+static ZCONST char Far op_not_neg_err[] = "option %s not negatable";
+static ZCONST char Far op_req_val_err[] = "option %s requires a value";
+static ZCONST char Far op_no_allow_val_err[] = "option %s does not allow a value";
+static ZCONST char Far sh_op_not_sup_err[] = "short option '%c' not supported";
+static ZCONST char Far oco_req_val_err[] = "option %s requires one character value";
+static ZCONST char Far oco_no_mbc_err[] = "option %s does not support multibyte values";
+static ZCONST char Far num_req_val_err[] = "option %s requires number value";
+static ZCONST char Far long_op_ambig_err[] = "long option '%s' ambiguous";
+static ZCONST char Far long_op_not_sup_err[] = "long option '%s' not supported";
+
+static ZCONST char Far no_arg_files_err[] = "argument files not enabled\n";
+
+
+/* below removed as only used for processing argument files */
+
+/* get_nextarg */
+/* get_args_from_string */
+/* insert_args */
+/* get_args_from_arg_file */
+
+
+/* copy error, option name, and option description if any to buf */
+local int optionerr(buf, err, optind, islong)
+ char *buf;
+ ZCONST char *err;
+ int optind;
+ int islong;
+{
+ char optname[50];
+
+ if (options[optind].name && options[optind].name[0] != '\0') {
+ if (islong)
+ sprintf(optname, "'%s' (%s)", options[optind].longopt, options[optind].name);
+ else
+ sprintf(optname, "'%s' (%s)", options[optind].shortopt, options[optind].name);
+ } else {
+ if (islong)
+ sprintf(optname, "'%s'", options[optind].longopt);
+ else
+ sprintf(optname, "'%s'", options[optind].shortopt);
+ }
+ sprintf(buf, err, optname);
+ return 0;
+}
+
+
+/* copy_args
+ *
+ * Copy arguments in args, allocating storage with malloc.
+ * Copies until a NULL argument is found or until max_args args
+ * including args[0] are copied. Set max_args to 0 to copy
+ * until NULL. Always terminates returned args[] with NULL arg.
+ *
+ * Any argument in the returned args can be freed with free(). Any
+ * freed argument should be replaced with either another string
+ * allocated with malloc or by NULL if last argument so that free_args
+ * will properly work.
+ */
+char **copy_args(args, max_args)
+ char **args;
+ int max_args;
+{
+ int j;
+ char **new_args;
+
+ if (args == NULL) {
+ return NULL;
+ }
+
+ /* count args */
+ for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) ;
+
+ if ((new_args = (char **) malloc((j + 1) * sizeof(char *))) == NULL) {
+ oERR(ZE_MEM, "ca");
+ }
+
+ for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) {
+ if (args[j] == NULL) {
+ /* null argument is end of args */
+ new_args[j] = NULL;
+ break;
+ }
+ if ((new_args[j] = malloc(strlen(args[j]) + 1)) == NULL) {
+ free_args(new_args);
+ oERR(ZE_MEM, "ca");
+ }
+ strcpy(new_args[j], args[j]);
+ }
+ new_args[j] = NULL;
+
+ return new_args;
+}
+
+
+/* free args - free args created with one of these functions */
+int free_args(args)
+ char **args;
+{
+ int i;
+
+ if (args == NULL) {
+ return 0;
+ }
+
+ for (i = 0; args[i]; i++) {
+ free(args[i]);
+ }
+ free(args);
+ return i;
+}
+
+
+/* insert_arg
+ *
+ * Insert the argument arg into the array args before argument at_arg.
+ * Return the new count of arguments (argc).
+ *
+ * If free_args is true, this function frees the old args array
+ * (but not the component strings). DO NOT set free_args on original
+ * argv but only on args allocated with malloc.
+ */
+
+int insert_arg(pargs, arg, at_arg, free_args)
+ char ***pargs;
+ ZCONST char *arg;
+ int at_arg;
+ int free_args;
+{
+ char *newarg = NULL;
+ char **args;
+ char **newargs = NULL;
+ int argnum;
+ int newargnum;
+ int argcnt;
+ int newargcnt;
+
+ if (pargs == NULL) {
+ return 0;
+ }
+ args = *pargs;
+
+ /* count args */
+ if (args == NULL) {
+ argcnt = 0;
+ } else {
+ for (argcnt = 0; args[argcnt]; argcnt++) ;
+ }
+ if (arg == NULL) {
+ /* done */
+ return argcnt;
+ }
+ newargcnt = argcnt + 1;
+
+ /* get storage for new args */
+ if ((newargs = (char **) malloc((newargcnt + 1) * sizeof(char *))) == NULL) {
+ oERR(ZE_MEM, "ia");
+ }
+
+ /* copy argument pointers from args to position at_arg, copy arg, then rest args */
+ argnum = 0;
+ newargnum = 0;
+ if (args) {
+ for (; args[argnum] && argnum < at_arg; argnum++) {
+ newargs[newargnum++] = args[argnum];
+ }
+ }
+ /* copy new arg */
+ if ((newarg = (char *) malloc(strlen(arg) + 1)) == NULL) {
+ oERR(ZE_MEM, "ia");
+ }
+ strcpy(newarg, arg);
+
+ newargs[newargnum++] = newarg;
+ if (args) {
+ for ( ; args[argnum]; argnum++) {
+ newargs[newargnum++] = args[argnum];
+ }
+ }
+ newargs[newargnum] = NULL;
+
+ /* free old args array but not component strings - this assumes that
+ args was allocated with malloc as copy_args does. DO NOT DO THIS
+ on the original argv.
+ */
+ if (free_args)
+ free(args);
+
+ *pargs = newargs;
+
+ return newargnum;
+}
+
+/* ------------------------------------- */
+
+
+
+
+/* get_shortopt
+ *
+ * Get next short option from arg. The state is stored in argnum, optchar, and
+ * option_num so no static storage is used. Returns the option_ID.
+ *
+ * parameters:
+ * args - argv array of arguments
+ * argnum - index of current arg in args
+ * optchar - pointer to index of next char to process. Can be 0 or
+ * const defined at top of this file like THIS_ARG_DONE
+ * negated - on return pointer to int set to 1 if option negated or 0 otherwise
+ * value - on return pointer to string set to value of option if any or NULL
+ * if none. If value is returned then the caller should free()
+ * it when not needed anymore.
+ * option_num - pointer to index in options[] of returned option or
+ * o_NO_OPTION_MATCH if none. Do not change as used by
+ * value lists.
+ * depth - recursion depth (0 at top level, 1 or more in arg files)
+ */
+local unsigned long get_shortopt(args, argnum, optchar, negated, value,
+ option_num, depth)
+ char **args;
+ int argnum;
+ int *optchar;
+ int *negated;
+ char **value;
+ int *option_num;
+ int depth;
+{
+ char *shortopt;
+ int clen;
+ char *nextchar;
+ char *s;
+ char *start;
+ int op;
+ char *arg;
+ int match = -1;
+
+
+ /* get arg */
+ arg = args[argnum];
+ /* current char in arg */
+ nextchar = arg + (*optchar);
+ clen = MB_CLEN(nextchar);
+ /* next char in arg */
+ (*optchar) += clen;
+ /* get first char of short option */
+ shortopt = arg + (*optchar);
+ /* no value */
+ *value = NULL;
+
+ if (*shortopt == '\0') {
+ /* no more options in arg */
+ *optchar = 0;
+ *option_num = o_NO_OPTION_MATCH;
+ return 0;
+ }
+
+ /* look for match in options */
+ clen = MB_CLEN(shortopt);
+ for (op = 0; options[op].option_ID; op++) {
+ s = options[op].shortopt;
+ if (s && s[0] == shortopt[0]) {
+ if (s[1] == '\0' && clen == 1) {
+ /* single char match */
+ match = op;
+ } else {
+ /* 2 wide short opt. Could support more chars but should use long opts instead */
+ if (s[1] == shortopt[1]) {
+ /* match 2 char short opt or 2 byte char */
+ match = op;
+ if (clen == 1) (*optchar)++;
+ break;
+ }
+ }
+ }
+ }
+
+ if (match > -1) {
+ /* match */
+ clen = MB_CLEN(shortopt);
+ nextchar = arg + (*optchar) + clen;
+ /* check for trailing dash negating option */
+ if (*nextchar == '-') {
+ /* negated */
+ if (options[match].negatable == o_NOT_NEGATABLE) {
+ if (options[match].value_type == o_NO_VALUE) {
+ optionerr(optionerrbuf, op_not_neg_err, match, 0);
+ if (depth > 0) {
+ /* unwind */
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ } else {
+ *negated = 1;
+ /* set up to skip negating dash */
+ (*optchar) += clen;
+ clen = 1;
+ }
+ }
+
+ /* value */
+ clen = MB_CLEN(arg + (*optchar));
+ /* optional value, one char value, and number value must follow option */
+ if (options[match].value_type == o_ONE_CHAR_VALUE) {
+ /* one char value */
+ if (arg[(*optchar) + clen]) {
+ /* has value */
+ if (MB_CLEN(arg + (*optchar) + clen) > 1) {
+ /* multibyte value not allowed for now */
+ optionerr(optionerrbuf, oco_no_mbc_err, match, 0);
+ if (depth > 0) {
+ /* unwind */
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ if ((*value = (char *) malloc(2)) == NULL) {
+ oERR(ZE_MEM, "gso");
+ }
+ (*value)[0] = *(arg + (*optchar) + clen);
+ (*value)[1] = '\0';
+ *optchar += clen;
+ clen = 1;
+ } else {
+ /* one char values require a value */
+ optionerr(optionerrbuf, oco_req_val_err, match, 0);
+ if (depth > 0) {
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ } else if (options[match].value_type == o_NUMBER_VALUE) {
+ /* read chars until end of number */
+ start = arg + (*optchar) + clen;
+ if (*start == '+' || *start == '-') {
+ start++;
+ }
+ s = start;
+ for (; isdigit(*s); MB_NEXTCHAR(s)) ;
+ if (s == start) {
+ /* no digits */
+ optionerr(optionerrbuf, num_req_val_err, match, 0);
+ if (depth > 0) {
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ start = arg + (*optchar) + clen;
+ if ((*value = (char *) malloc((int)(s - start) + 1)) == NULL) {
+ oERR(ZE_MEM, "gso");
+ }
+ *optchar += (int)(s - start);
+ strncpy(*value, start, (int)(s - start));
+ (*value)[(int)(s - start)] = '\0';
+ clen = MB_CLEN(s);
+ } else if (options[match].value_type == o_OPTIONAL_VALUE) {
+ /* optional value */
+ /* This seemed inconsistent so now if no value attached to argument look
+ to the next argument if that argument is not an option for option
+ value - 11/12/04 EG */
+ if (arg[(*optchar) + clen]) {
+ /* has value */
+ /* add support for optional = - 2/6/05 EG */
+ if (arg[(*optchar) + clen] == '=') {
+ /* skip = */
+ clen++;
+ }
+ if (arg[(*optchar) + clen]) {
+ if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
+ == NULL) {
+ oERR(ZE_MEM, "gso");
+ }
+ strcpy(*value, arg + (*optchar) + clen);
+ }
+ *optchar = THIS_ARG_DONE;
+ } else if (args[argnum + 1] && args[argnum + 1][0] != '-') {
+ /* use next arg for value */
+ if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+ oERR(ZE_MEM, "gso");
+ }
+ /* using next arg as value */
+ strcpy(*value, args[argnum + 1]);
+ *optchar = SKIP_VALUE_ARG;
+ }
+ } else if (options[match].value_type == o_REQUIRED_VALUE ||
+ options[match].value_type == o_VALUE_LIST) {
+ /* see if follows option */
+ if (arg[(*optchar) + clen]) {
+ /* has value following option as -ovalue */
+ /* add support for optional = - 6/5/05 EG */
+ if (arg[(*optchar) + clen] == '=') {
+ /* skip = */
+ clen++;
+ }
+ if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
+ == NULL) {
+ oERR(ZE_MEM, "gso");
+ }
+ strcpy(*value, arg + (*optchar) + clen);
+ *optchar = THIS_ARG_DONE;
+ } else {
+ /* use next arg for value */
+ if (args[argnum + 1]) {
+ if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+ oERR(ZE_MEM, "gso");
+ }
+ strcpy(*value, args[argnum + 1]);
+ if (options[match].value_type == o_VALUE_LIST) {
+ *optchar = START_VALUE_LIST;
+ } else {
+ *optchar = SKIP_VALUE_ARG;
+ }
+ } else {
+ /* no value found */
+ optionerr(optionerrbuf, op_req_val_err, match, 0);
+ if (depth > 0) {
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ }
+ }
+
+ *option_num = match;
+ return options[match].option_ID;
+ }
+ sprintf(optionerrbuf, sh_op_not_sup_err, *shortopt);
+ if (depth > 0) {
+ /* unwind */
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ return 0;
+}
+
+
+/* get_longopt
+ *
+ * Get the long option in args array at argnum.
+ * Parameters same as for get_shortopt.
+ */
+
+local unsigned long get_longopt(args, argnum, optchar, negated, value,
+ option_num, depth)
+ char **args;
+ int argnum;
+ int *optchar;
+ int *negated;
+ char **value;
+ int *option_num;
+ int depth;
+{
+ char *longopt;
+ char *lastchr;
+ char *valuestart;
+ int op;
+ char *arg;
+ int match = -1;
+ *value = NULL;
+
+ if (args == NULL) {
+ *option_num = o_NO_OPTION_MATCH;
+ return 0;
+ }
+ if (args[argnum] == NULL) {
+ *option_num = o_NO_OPTION_MATCH;
+ return 0;
+ }
+ /* copy arg so can chop end if value */
+ if ((arg = (char *)malloc(strlen(args[argnum]) + 1)) == NULL) {
+ oERR(ZE_MEM, "glo");
+ }
+ strcpy(arg, args[argnum]);
+
+ /* get option */
+ longopt = arg + 2;
+ /* no value */
+ *value = NULL;
+
+ /* find = */
+ for (lastchr = longopt, valuestart = longopt;
+ *valuestart && *valuestart != '=';
+ lastchr = valuestart, MB_NEXTCHAR(valuestart)) ;
+ if (*valuestart) {
+ /* found =value */
+ *valuestart = '\0';
+ valuestart++;
+ } else {
+ valuestart = NULL;
+ }
+
+ if (*lastchr == '-') {
+ /* option negated */
+ *negated = 1;
+ *lastchr = '\0';
+ } else {
+ *negated = 0;
+ }
+
+ /* look for long option match */
+ for (op = 0; options[op].option_ID; op++) {
+ if (options[op].longopt && strcmp(options[op].longopt, longopt) == 0) {
+ /* exact match */
+ match = op;
+ break;
+ }
+ if (options[op].longopt && strncmp(options[op].longopt, longopt, strlen(longopt)) == 0) {
+ if (match > -1) {
+ sprintf(optionerrbuf, long_op_ambig_err, longopt);
+ free(arg);
+ if (depth > 0) {
+ /* unwind */
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ match = op;
+ }
+ }
+
+ if (match == -1) {
+ sprintf(optionerrbuf, long_op_not_sup_err, longopt);
+ free(arg);
+ if (depth > 0) {
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+
+ /* one long option an arg */
+ *optchar = THIS_ARG_DONE;
+
+ /* if negated then see if allowed */
+ if (*negated && options[match].negatable == o_NOT_NEGATABLE) {
+ optionerr(optionerrbuf, op_not_neg_err, match, 1);
+ free(arg);
+ if (depth > 0) {
+ /* unwind */
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ /* get value */
+ if (options[match].value_type == o_OPTIONAL_VALUE) {
+ /* optional value in form option=value */
+ if (valuestart) {
+ /* option=value */
+ if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
+ free(arg);
+ oERR(ZE_MEM, "glo");
+ }
+ strcpy(*value, valuestart);
+ }
+ } else if (options[match].value_type == o_REQUIRED_VALUE ||
+ options[match].value_type == o_NUMBER_VALUE ||
+ options[match].value_type == o_ONE_CHAR_VALUE ||
+ options[match].value_type == o_VALUE_LIST) {
+ /* handle long option one char and number value as required value */
+ if (valuestart) {
+ /* option=value */
+ if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
+ free(arg);
+ oERR(ZE_MEM, "glo");
+ }
+ strcpy(*value, valuestart);
+ } else {
+ /* use next arg */
+ if (args[argnum + 1]) {
+ if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
+ free(arg);
+ oERR(ZE_MEM, "glo");
+ }
+ /* using next arg as value */
+ strcpy(*value, args[argnum + 1]);
+ if (options[match].value_type == o_VALUE_LIST) {
+ *optchar = START_VALUE_LIST;
+ } else {
+ *optchar = SKIP_VALUE_ARG;
+ }
+ } else {
+ /* no value found */
+ optionerr(optionerrbuf, op_req_val_err, match, 1);
+ free(arg);
+ if (depth > 0) {
+ /* unwind */
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ }
+ } else if (options[match].value_type == o_NO_VALUE) {
+ /* this option does not accept a value */
+ if (valuestart) {
+ /* --option=value */
+ optionerr(optionerrbuf, op_no_allow_val_err, match, 1);
+ free(arg);
+ if (depth > 0) {
+ oWARN(optionerrbuf);
+ return o_ARG_FILE_ERR;
+ } else {
+ oERR(ZE_PARMS, optionerrbuf);
+ }
+ }
+ }
+ free(arg);
+
+ *option_num = match;
+ return options[match].option_ID;
+}
+
+
+
+/* get_option
+ *
+ * Main interface for user. Use this function to get options, values and
+ * non-option arguments from a command line provided in argv form.
+ *
+ * To use get_option() first define valid options by setting
+ * the global variable options[] to an array of option_struct. Also
+ * either change defaults below or make variables global and set elsewhere.
+ * Zip uses below defaults.
+ *
+ * Call get_option() to get an option (like -b or --temp-file) and any
+ * value for that option (like filename for -b) or a non-option argument
+ * (like archive name) each call. If *value* is not NULL after calling
+ * get_option() it is a returned value and the caller should either store
+ * the char pointer or free() it before calling get_option() again to avoid
+ * leaking memory. If a non-option non-value argument is returned get_option()
+ * returns o_NON_OPTION_ARG and value is set to the entire argument.
+ * When there are no more arguments get_option() returns 0.
+ *
+ * The parameters argnum (after set to 0 on initial call),
+ * optchar, first_nonopt_arg, option_num, and depth (after initial
+ * call) are set and maintained by get_option() and should not be
+ * changed. The parameters argc, negated, and value are outputs and
+ * can be used by the calling program. get_option() returns either the
+ * option_ID for the current option, a special value defined in
+ * zip.h, or 0 when no more arguments.
+ *
+ * The value returned by get_option() is the ID value in the options
+ * table. This value can be duplicated in the table if different
+ * options are really the same option. The index into the options[]
+ * table is given by option_num, though the ID should be used as
+ * option numbers change when the table is changed. The ID must
+ * not be 0 for any option as this ends the table. If get_option()
+ * finds an option not in the table it calls oERR to post an
+ * error and exit. Errors also result if the option requires a
+ * value that is missing, a value is present but the option does
+ * not take one, and an option is negated but is not
+ * negatable. Non-option arguments return o_NON_OPTION_ARG
+ * with the entire argument in value.
+ *
+ * For Zip, permuting is on and all options and their values are
+ * returned before any non-option arguments like archive name.
+ *
+ * The arguments "-" alone and "--" alone return as non-option arguments.
+ * Note that "-" should not be used as part of a short option
+ * entry in the table but can be used in the middle of long
+ * options such as in the long option "a-long-option". Now "--" alone
+ * stops option processing, returning any arguments following "--" as
+ * non-option arguments instead of options.
+ *
+ * Argument file support is removed from this version. It may be added later.
+ *
+ * After each call:
+ * argc is set to the current size of args[] but should not change
+ * with argument file support removed,
+ * argnum is the index of the current arg,
+ * value is either the value of the returned option or non-option
+ * argument or NULL if option with no value,
+ * negated is set if the option was negated by a trailing dash (-)
+ * option_num is set to either the index in options[] for the option or
+ * o_NO_OPTION_MATCH if no match.
+ * Negation is checked before the value is read if the option is negatable so
+ * that the - is not included in the value. If the option is not negatable
+ * but takes a value then the - will start the value. If permuting then
+ * argnum and first_nonopt_arg are unreliable and should not be used.
+ *
+ * Command line is read from left to right. As get_option() finds non-option
+ * arguments (arguments not starting with - and that are not values to options)
+ * it moves later options and values in front of the non-option arguments.
+ * This permuting is turned off by setting enable_permute to 0. Then
+ * get_option() will return options and non-option arguments in the order
+ * found. Currently permuting is only done after an argument is completely
+ * processed so that any value can be moved with options they go with. All
+ * state information is stored in the parameters argnum, optchar,
+ * first_nonopt_arg and option_num. You should not change these after the
+ * first call to get_option(). If you need to back up to a previous arg then
+ * set argnum to that arg (remembering that args may have been permuted) and
+ * set optchar = 0 and first_nonopt_arg to the first non-option argument if
+ * permuting. After all arguments are returned the next call to get_option()
+ * returns 0. The caller can then call free_args(args) if appropriate.
+ *
+ * get_option() accepts arguments in the following forms:
+ * short options
+ * of 1 and 2 characters, e.g. a, b, cc, d, and ba, after a single
+ * leading -, as in -abccdba. In this example if 'b' is followed by 'a'
+ * it matches short option 'ba' else it is interpreted as short option
+ * b followed by another option. The character - is not legal as a
+ * short option or as part of a 2 character short option.
+ *
+ * If a short option has a value it immediately follows the option or
+ * if that option is the end of the arg then the next arg is used as
+ * the value. So if short option e has a value, it can be given as
+ * -evalue
+ * or
+ * -e value
+ * and now
+ * -e=value
+ * but now that = is optional a leading = is stripped for the first.
+ * This change allows optional short option values to be defaulted as
+ * -e=
+ * Either optional or required values can be specified. Optional values
+ * now use both forms as ignoring the later got confusing. Any
+ * non-value short options can preceed a valued short option as in
+ * -abevalue
+ * Some value types (one_char and number) allow options after the value
+ * so if oc is an option that takes a character and n takes a number
+ * then
+ * -abocVccn42evalue
+ * returns value V for oc and value 42 for n. All values are strings
+ * so programs may have to convert the "42" to a number. See long
+ * options below for how value lists are handled.
+ *
+ * Any short option can be negated by following it with -. Any - is
+ * handled and skipped over before any value is read unless the option
+ * is not negatable but takes a value and then - starts the value.
+ *
+ * If the value for an optional value is just =, then treated as no
+ * value.
+ *
+ * long options
+ * of arbitrary length are assumed if an arg starts with -- but is not
+ * exactly --. Long options are given one per arg and can be abbreviated
+ * if the abbreviation uniquely matches one of the long options.
+ * Exact matches always match before partial matches. If ambiguous an
+ * error is generated.
+ *
+ * Values are specified either in the form
+ * --longoption=value
+ * or can be the following arg if the value is required as in
+ * --longoption value
+ * Optional values to long options must be in the first form.
+ *
+ * Value lists are specified by o_VALUE_LIST and consist of an option
+ * that takes a value followed by one or more value arguments.
+ * The two forms are
+ * --option=value
+ * or
+ * -ovalue
+ * for a single value or
+ * --option value1 value2 value3 ... --option2
+ * or
+ * -o value1 value2 value3 ...
+ * for a list of values. The list ends at the next option, the
+ * end of the command line, or at a single "@" argument.
+ * Each value is treated as if it was preceeded by the option, so
+ * --option1 val1 val2
+ * with option1 value_type set to o_VALUE_LIST is the same as
+ * --option1=val1 --option1=val2
+ *
+ * Long options can be negated by following the option with - as in
+ * --longoption-
+ * Long options with values can also be negated if this makes sense for
+ * the caller as:
+ * --longoption-=value
+ * If = is not followed by anything it is treated as no value.
+ *
+ * @path
+ * When an argument in the form @path is encountered, the file at path
+ * is opened and white space separated arguments read from the file
+ * and inserted into the command line at that point as if the contents
+ * of the file were directly typed at that location. The file can
+ * have options, files to zip, or anything appropriate at that location
+ * in the command line. Since Zip has permuting enabled, options and
+ * files will propagate to the appropriate locations in the command
+ * line.
+ *
+ * Argument files support has been removed from this version. It may
+ * be added back later.
+ *
+ * non-option argument
+ * is any argument not given above. If enable_permute is 1 then
+ * these are returned after all options, otherwise all options and
+ * args are returned in order. Returns option ID o_NON_OPTION_ARG
+ * and sets value to the argument.
+ *
+ *
+ * Arguments to get_option:
+ * char ***pargs - pointer to arg array in the argv form
+ * int *argc - returns the current argc for args incl. args[0]
+ * int *argnum - the index of the current argument (caller
+ * should set = 0 on first call and not change
+ * after that)
+ * int *optchar - index of next short opt in arg or special
+ * int *first_nonopt_arg - used by get_option to permute args
+ * int *negated - option was negated (had trailing -)
+ * char *value - value of option if any (free when done with it) or NULL
+ * int *option_num - the index in options of the last option returned
+ * (can be o_NO_OPTION_MATCH)
+ * int recursion_depth - current depth of recursion
+ * (always set to 0 by caller)
+ * (always 0 with argument files support removed)
+ *
+ * Caller should only read the returned option ID and the value, negated,
+ * and option_num (if required) parameters after each call.
+ *
+ * Ed Gordon
+ * 24 August 2003 (last updated 2 April 2008 EG)
+ *
+ */
+
+unsigned long get_option(pargs, argc, argnum, optchar, value,
+ negated, first_nonopt_arg, option_num, recursion_depth)
+ char ***pargs;
+ int *argc;
+ int *argnum;
+ int *optchar;
+ char **value;
+ int *negated;
+ int *first_nonopt_arg;
+ int *option_num;
+ int recursion_depth;
+{
+ char **args;
+ unsigned long option_ID;
+
+ int argcnt;
+ int first_nonoption_arg;
+ char *arg = NULL;
+ int h;
+ int optc;
+ int argn;
+ int j;
+ int v;
+ int read_rest_args_verbatim = 0; /* 7/25/04 - ignore options and arg files for rest args */
+
+ /* value is outdated. The caller should free value before
+ calling get_option again. */
+ *value = NULL;
+
+ /* if args is NULL then done */
+ if (pargs == NULL) {
+ *argc = 0;
+ return 0;
+ }
+ args = *pargs;
+ if (args == NULL) {
+ *argc = 0;
+ return 0;
+ }
+
+ /* count args */
+ for (argcnt = 0; args[argcnt]; argcnt++) ;
+
+ /* if no provided args then nothing to do */
+ if (argcnt < 1 || (recursion_depth == 0 && argcnt < 2)) {
+ *argc = argcnt;
+ /* return 0 to note that no args are left */
+ return 0;
+ }
+
+ *negated = 0;
+ first_nonoption_arg = *first_nonopt_arg;
+ argn = *argnum;
+ optc = *optchar;
+
+ if (optc == READ_REST_ARGS_VERBATIM) {
+ read_rest_args_verbatim = 1;
+ }
+
+ if (argn == -1 || (recursion_depth == 0 && argn == 0)) {
+ /* first call */
+ /* if depth = 0 then args[0] is argv[0] so skip */
+ *option_num = o_NO_OPTION_MATCH;
+ optc = THIS_ARG_DONE;
+ first_nonoption_arg = -1;
+ }
+
+ /* if option_num is set then restore last option_ID in case continuing value list */
+ option_ID = 0;
+ if (*option_num != o_NO_OPTION_MATCH) {
+ option_ID = options[*option_num].option_ID;
+ }
+
+ /* get next option if any */
+ for (;;) {
+ if (read_rest_args_verbatim) {
+ /* rest of args after "--" are non-option args if doubledash_ends_options set */
+ argn++;
+ if (argn > argcnt || args[argn] == NULL) {
+ /* done */
+ option_ID = 0;
+ break;
+ }
+ arg = args[argn];
+ if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+ oERR(ZE_MEM, "go");
+ }
+ strcpy(*value, arg);
+ *option_num = o_NO_OPTION_MATCH;
+ option_ID = o_NON_OPTION_ARG;
+ break;
+
+ /* permute non-option args after option args so options are returned first */
+ } else if (enable_permute) {
+ if (optc == SKIP_VALUE_ARG || optc == THIS_ARG_DONE ||
+ optc == START_VALUE_LIST || optc == IN_VALUE_LIST ||
+ optc == STOP_VALUE_LIST) {
+ /* moved to new arg */
+ if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
+ /* do the permuting - move non-options after this option */
+ /* if option and value separate args or starting list skip option */
+ if (optc == SKIP_VALUE_ARG || optc == START_VALUE_LIST) {
+ v = 1;
+ } else {
+ v = 0;
+ }
+ for (h = first_nonoption_arg; h < argn; h++) {
+ arg = args[first_nonoption_arg];
+ for (j = first_nonoption_arg; j < argn + v; j++) {
+ args[j] = args[j + 1];
+ }
+ args[j] = arg;
+ }
+ first_nonoption_arg += 1 + v;
+ }
+ }
+ } else if (optc == NON_OPTION_ARG) {
+ /* if not permuting then already returned arg */
+ optc = THIS_ARG_DONE;
+ }
+
+ /* value lists */
+ if (optc == STOP_VALUE_LIST) {
+ optc = THIS_ARG_DONE;
+ }
+
+ if (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) {
+ if (optc == START_VALUE_LIST) {
+ /* already returned first value */
+ argn++;
+ optc = IN_VALUE_LIST;
+ }
+ argn++;
+ arg = args[argn];
+ /* if end of args and still in list and there are non-option args then
+ terminate list */
+ if (arg == NULL && (optc == START_VALUE_LIST || optc == IN_VALUE_LIST)
+ && first_nonoption_arg > -1) {
+ /* terminate value list with @ */
+ /* this is only needed for argument files */
+ /* but is also good for show command line so command lines with lists
+ can always be read back in */
+ argcnt = insert_arg(&args, "@", first_nonoption_arg, 1);
+ argn++;
+ if (first_nonoption_arg > -1) {
+ first_nonoption_arg++;
+ }
+ }
+
+ arg = args[argn];
+ if (arg && arg[0] == '@' && arg[1] == '\0') {
+ /* inserted arguments terminator */
+ optc = STOP_VALUE_LIST;
+ continue;
+ } else if (arg && arg[0] != '-') { /* not option */
+ /* - and -- are not allowed in value lists unless escaped */
+ /* another value in value list */
+ if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
+ oERR(ZE_MEM, "go");
+ }
+ strcpy(*value, args[argn]);
+ break;
+
+ } else {
+ argn--;
+ optc = THIS_ARG_DONE;
+ }
+ }
+
+ /* move to next arg */
+ if (optc == SKIP_VALUE_ARG) {
+ argn += 2;
+ optc = 0;
+ } else if (optc == THIS_ARG_DONE) {
+ argn++;
+ optc = 0;
+ }
+ if (argn > argcnt) {
+ break;
+ }
+ if (args[argn] == NULL) {
+ /* done unless permuting and non-option args */
+ if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
+ /* return non-option arguments at end */
+ if (optc == NON_OPTION_ARG) {
+ first_nonoption_arg++;
+ }
+ /* after first pass args are permuted but skipped over non-option args */
+ /* swap so argn points to first non-option arg */
+ j = argn;
+ argn = first_nonoption_arg;
+ first_nonoption_arg = j;
+ }
+ if (argn > argcnt || args[argn] == NULL) {
+ /* done */
+ option_ID = 0;
+ break;
+ }
+ }
+
+ /* after swap first_nonoption_arg points to end which is NULL */
+ if (first_nonoption_arg > -1 && (args[first_nonoption_arg] == NULL)) {
+ /* only non-option args left */
+ if (optc == NON_OPTION_ARG) {
+ argn++;
+ }
+ if (argn > argcnt || args[argn] == NULL) {
+ /* done */
+ option_ID = 0;
+ break;
+ }
+ if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
+ oERR(ZE_MEM, "go");
+ }
+ strcpy(*value, args[argn]);
+ optc = NON_OPTION_ARG;
+ option_ID = o_NON_OPTION_ARG;
+ break;
+ }
+
+ arg = args[argn];
+
+ /* is it an option */
+ if (arg[0] == '-') {
+ /* option */
+ if (arg[1] == '\0') {
+ /* arg = - */
+ /* treat like non-option arg */
+ *option_num = o_NO_OPTION_MATCH;
+ if (enable_permute) {
+ /* permute args to move all non-option args to end */
+ if (first_nonoption_arg < 0) {
+ first_nonoption_arg = argn;
+ }
+ argn++;
+ } else {
+ /* not permute args so return non-option args when found */
+ if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+ oERR(ZE_MEM, "go");
+ }
+ strcpy(*value, arg);
+ optc = NON_OPTION_ARG;
+ option_ID = o_NON_OPTION_ARG;
+ break;
+ }
+
+ } else if (arg[1] == '-') {
+ /* long option */
+ if (arg[2] == '\0') {
+ /* arg = -- */
+ if (doubledash_ends_options) {
+ /* Now -- stops permuting and forces the rest of
+ the command line to be read verbatim - 7/25/04 EG */
+
+ /* never permute args after -- and return as non-option args */
+ if (first_nonoption_arg < 1) {
+ /* -- is first non-option argument - 8/7/04 EG */
+ argn--;
+ } else {
+ /* go back to start of non-option args - 8/7/04 EG */
+ argn = first_nonoption_arg - 1;
+ }
+
+ /* disable permuting and treat remaining arguments as not
+ options */
+ read_rest_args_verbatim = 1;
+ optc = READ_REST_ARGS_VERBATIM;
+
+ } else {
+ /* treat like non-option arg */
+ *option_num = o_NO_OPTION_MATCH;
+ if (enable_permute) {
+ /* permute args to move all non-option args to end */
+ if (first_nonoption_arg < 0) {
+ first_nonoption_arg = argn;
+ }
+ argn++;
+ } else {
+ /* not permute args so return non-option args when found */
+ if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+ oERR(ZE_MEM, "go");
+ }
+ strcpy(*value, arg);
+ optc = NON_OPTION_ARG;
+ option_ID = o_NON_OPTION_ARG;
+ break;
+ }
+ }
+
+ } else {
+ option_ID = get_longopt(args, argn, &optc, negated, value, option_num, recursion_depth);
+ if (option_ID == o_ARG_FILE_ERR) {
+ /* unwind as only get this if recursion_depth > 0 */
+ return option_ID;
+ }
+ break;
+ }
+
+ } else {
+ /* short option */
+ option_ID = get_shortopt(args, argn, &optc, negated, value, option_num, recursion_depth);
+
+ if (option_ID == o_ARG_FILE_ERR) {
+ /* unwind as only get this if recursion_depth > 0 */
+ return option_ID;
+ }
+
+ if (optc == 0) {
+ /* if optc = 0 then ran out of short opts this arg */
+ optc = THIS_ARG_DONE;
+ } else {
+ break;
+ }
+ }
+
+#if 0
+ /* argument file code left out
+ so for now let filenames start with @
+ */
+
+ } else if (allow_arg_files && arg[0] == '@') {
+ /* arg file */
+ oERR(ZE_PARMS, no_arg_files_err);
+#endif
+
+ } else {
+ /* non-option */
+ if (enable_permute) {
+ /* permute args to move all non-option args to end */
+ if (first_nonoption_arg < 0) {
+ first_nonoption_arg = argn;
+ }
+ argn++;
+ } else {
+ /* no permute args so return non-option args when found */
+ if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
+ oERR(ZE_MEM, "go");
+ }
+ strcpy(*value, arg);
+ *option_num = o_NO_OPTION_MATCH;
+ optc = NON_OPTION_ARG;
+ option_ID = o_NON_OPTION_ARG;
+ break;
+ }
+
+ }
+ }
+
+ *pargs = args;
+ *argc = argcnt;
+ *first_nonopt_arg = first_nonoption_arg;
+ *argnum = argn;
+ *optchar = optc;
+
+ return option_ID;
+}
diff --git a/globals.c b/globals.c
new file mode 100644
index 0000000..e73392a
--- /dev/null
+++ b/globals.c
@@ -0,0 +1,253 @@
+/*
+ globals.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * globals.c by Mark Adler
+ */
+#define __GLOBALS_C
+
+#define GLOBALS /* include definition of errors[] in zip.h */
+#ifndef UTIL
+#define UTIL /* do not declare the read_buf variable */
+#endif
+
+#include "zip.h"
+
+
+/* Handy place to build error messages */
+char errbuf[FNMAX+4081];
+
+/* Argument processing globals */
+int recurse = 0; /* 1=recurse into directories encountered */
+int dispose = 0; /* 1=remove files after put in zip file */
+int pathput = 1; /* 1=store path with name */
+#ifdef RISCOS
+int scanimage = 1; /* 1=scan through image files */
+#endif
+int method = BEST; /* one of BEST, DEFLATE (only), or STORE (only) */
+int dosify = 0; /* 1=make new entries look like MSDOS */
+int verbose = 0; /* 1=report oddities in zip file structure */
+int fix = 0; /* 1=fix the zip file, 2=FF, 3=ZipNote */
+int filesync = 0; /* 1=file sync, delete entries not on file system */
+int adjust = 0; /* 1=adjust offsets for sfx'd file (keep preamble) */
+int level = 6; /* 0=fastest compression, 9=best compression */
+int translate_eol = 0; /* Translate end-of-line LF -> CR LF */
+#ifdef VMS
+ int vmsver = 0; /* 1=append VMS version number to file names */
+ int vms_native = 0; /* 1=store in VMS format */
+ int vms_case_2 = 0; /* ODS2 file name case in VMS. -1: down. */
+ int vms_case_5 = 0; /* ODS5 file name case in VMS. +1: preserve. */
+#endif /* VMS */
+#if defined(OS2) || defined(WIN32)
+ int use_longname_ea = 0; /* 1=use the .LONGNAME EA as the file's name */
+#endif
+/* 9/26/04 */
+int no_wild = 0; /* 1 = wildcards are disabled */
+int allow_regex = 0; /* 1 = allow [list] matching */
+#ifdef WILD_STOP_AT_DIR
+ int wild_stop_at_dir = 1; /* default wildcards do not include / in matches */
+#else
+ int wild_stop_at_dir = 0; /* default wildcards do include / in matches */
+#endif
+
+#ifdef UNICODE_SUPPORT
+ int using_utf8 = 0; /* 1 if current character set UTF-8 */
+# ifdef WIN32
+ int no_win32_wide = -1; /* 1 = no wide functions, like GetFileAttributesW() */
+# endif
+#endif
+
+ulg skip_this_disk = 0;
+int des_good = 0; /* Good data descriptor found */
+ulg des_crc = 0; /* Data descriptor CRC */
+uzoff_t des_csize = 0; /* Data descriptor csize */
+uzoff_t des_usize = 0; /* Data descriptor usize */
+
+/* dots 10/20/04 */
+zoff_t dot_size = 0; /* bytes processed in deflate per dot, 0 = no dots */
+zoff_t dot_count = 0; /* buffers seen, recyles at dot_size */
+/* status 10/30/04 */
+int display_counts = 0; /* display running file count */
+int display_bytes = 0; /* display running bytes remaining */
+int display_globaldots = 0; /* display dots for archive instead of each file */
+int display_volume = 0; /* display current input and output volume (disk) numbers */
+int display_usize = 0; /* display uncompressed bytes */
+ulg files_so_far = 0; /* files processed so far */
+ulg bad_files_so_far = 0; /* bad files skipped so far */
+ulg files_total = 0; /* files total to process */
+uzoff_t bytes_so_far = 0; /* bytes processed so far (from initial scan) */
+uzoff_t good_bytes_so_far = 0;/* good bytes read so far */
+uzoff_t bad_bytes_so_far = 0; /* bad bytes skipped so far */
+uzoff_t bytes_total = 0; /* total bytes to process (from initial scan) */
+
+/* logfile 6/5/05 */
+int logall = 0; /* 0 = warnings/errors, 1 = all */
+FILE *logfile = NULL; /* pointer to open logfile or NULL */
+int logfile_append = 0; /* append to existing logfile */
+char *logfile_path = NULL; /* pointer to path of logfile */
+
+int hidden_files = 0; /* process hidden and system files */
+int volume_label = 0; /* add volume label */
+int dirnames = 1; /* include directory entries by default */
+int filter_match_case = 1; /* 1=match case when filter() */
+int diff_mode = 0; /* 1=require --out and only store changed and add */
+#if defined(WIN32)
+int only_archive_set = 0; /* include only files with DOS archive bit set */
+int clear_archive_bits = 0; /* clear DOS archive bit of included files */
+#endif
+int linkput = 0; /* 1=store symbolic links as such */
+int noisy = 1; /* 0=quiet operation */
+int extra_fields = 1; /* 0=create minimum, 1=don't copy old, 2=keep old */
+int use_descriptors = 0; /* 1=use data descriptors 12/29/04 */
+int zip_to_stdout = 0; /* output zipfile to stdout 12/30/04 */
+int allow_empty_archive = 0; /* if no files, create empty archive anyway 12/28/05 */
+int copy_only = 0; /* 1=copying archive entries only */
+int allow_fifo = 0; /* 1=allow reading Unix FIFOs, waiting if pipe open */
+int show_files = 0; /* show files to operate on and exit (=2 log only) */
+
+int output_seekable = 1; /* 1 = output seekable 3/13/05 EG */
+
+#ifdef ZIP64_SUPPORT /* zip64 support 10/4/03 */
+ int force_zip64 = -1; /* if 1 force entries to be zip64, 0 force not zip64 */
+ /* mainly for streaming from stdin */
+ int zip64_entry = 0; /* current entry needs Zip64 */
+ int zip64_archive = 0; /* if 1 then at least 1 entry needs zip64 */
+#endif
+
+#ifdef NTSD_EAS
+ int use_privileges = 0; /* 1=use security privilege overrides */
+#endif
+#ifndef RISCOS
+#ifndef QDOS
+#ifndef TANDEM
+char *special = ".Z:.zip:.zoo:.arc:.lzh:.arj"; /* List of special suffixes */
+#else /* TANDEM */
+char *special = " Z: zip: zoo: arc: lzh: arj"; /* List of special suffixes */
+#endif
+#else /* QDOS */
+char *special = "_Z:_zip:_zoo:_arc:_lzh:_arj"; /* List of special suffixes */
+#endif
+#else /* RISCOS */
+char *special = "DDC:D96:68E";
+#endif /* ?RISCOS */
+char *key = NULL; /* Scramble password if scrambling */
+char *tempath = NULL; /* Path for temporary files */
+FILE *mesg; /* stdout by default, stderr for piping */
+
+#ifdef UNICODE_SUPPORT
+ int utf8_force = 0; /* 1=force storing UTF-8 as standard per AppNote bit 11 */
+#endif
+int unicode_escape_all = 0; /* 1=escape all non-ASCII characters in paths */
+int unicode_mismatch = 1; /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+
+time_t scan_delay = 5; /* seconds before display Scanning files message */
+time_t scan_dot_time = 2; /* time in seconds between Scanning files dots */
+time_t scan_start = 0; /* start of scan */
+time_t scan_last = 0; /* time of last message */
+int scan_started = 0; /* scan has started */
+uzoff_t scan_count = 0; /* Used for Scanning files ... message */
+
+ulg before = 0; /* 0=ignore, else exclude files before this time */
+ulg after = 0; /* 0=ignore, else exclude files newer than this time */
+
+/* Zip file globals */
+char *zipfile; /* New or existing zip archive (zip file) */
+
+/* zip64 support 08/31/2003 R.Nausedat */
+/* all are across splits - subtract bytes_prev_splits to get offsets for current disk */
+uzoff_t zipbeg; /* Starting offset of zip structures */
+uzoff_t cenbeg; /* Starting offset of central dir */
+uzoff_t tempzn; /* Count of bytes written to output zip files */
+
+/* 10/28/05 */
+char *tempzip = NULL; /* name of temp file */
+FILE *y = NULL; /* output file now global so can change in splits */
+FILE *in_file = NULL; /* current input file for splits */
+char *in_path = NULL; /* base name of input archive file */
+char *in_split_path = NULL; /* in split path */
+char *out_path = NULL; /* base name of output file, usually same as zipfile */
+int zip_attributes = 0;
+
+/* in split globals */
+
+ulg total_disks = 0; /* total disks in archive */
+ulg current_in_disk = 0; /* current read split disk */
+uzoff_t current_in_offset = 0; /* current offset in current read disk */
+ulg skip_current_disk = 0; /* if != 0 and fix then skip entries on this disk */
+
+
+/* out split globals */
+
+ulg current_local_disk = 0; /* disk with current local header */
+
+ulg current_disk = 0; /* current disk number */
+ulg cd_start_disk = (ulg)-1; /* central directory start disk */
+uzoff_t cd_start_offset = 0; /* offset of start of cd on cd start disk */
+uzoff_t cd_entries_this_disk = 0; /* cd entries this disk */
+uzoff_t total_cd_entries = 0; /* total cd entries in new/updated archive */
+ulg zip64_eocd_disk = 0; /* disk with Zip64 End Of Central Directory Record */
+uzoff_t zip64_eocd_offset = 0; /* offset for Zip64 EOCD Record */
+
+/* for split method 1 (keep split with local header open and update) */
+char *current_local_tempname = NULL; /* name of temp file */
+FILE *current_local_file = NULL; /* file pointer for current local header */
+uzoff_t current_local_offset = 0; /* offset to start of current local header */
+
+/* global */
+uzoff_t bytes_this_split = 0; /* bytes written to the current split */
+int read_split_archive = 0; /* 1=scanzipf_reg detected spanning signature */
+int split_method = 0; /* 0=no splits, 1=seekable, 2=data desc, -1=no */
+uzoff_t split_size = 0; /* how big each split should be */
+int split_bell = 0; /* when pause for next split ring bell */
+uzoff_t bytes_prev_splits = 0; /* total bytes written to all splits before this */
+uzoff_t bytes_this_entry = 0; /* bytes written for this entry across all splits */
+int noisy_splits = 0; /* note when splits are being created */
+int mesg_line_started = 0; /* 1=started writing a line to mesg */
+int logfile_line_started = 0; /* 1=started writing a line to logfile */
+
+#ifdef WIN32
+ int nonlocal_name = 0; /* Name has non-local characters */
+ int nonlocal_path = 0; /* Path has non-local characters */
+#endif
+#ifdef UNICODE_SUPPORT
+ int use_wide_to_mb_default = 0;
+#endif
+
+struct zlist far *zfiles = NULL; /* Pointer to list of files in zip file */
+/* The limit for number of files using the Zip64 format is 2^64 - 1 (8 bytes)
+ but extent is used for many internal sorts and other tasks and is generally
+ long on 32-bit systems. Because of that, but more because of various memory
+ utilization issues limiting the practical number of central directory entries
+ that can be sorted, the number of actual entries that can be stored probably
+ can't exceed roughly 2^30 on 32-bit systems so extent is probably sufficient. */
+extent zcount; /* Number of files in zip file */
+int zipfile_exists = 0; /* 1 if zipfile exists */
+ush zcomlen; /* Length of zip file comment */
+char *zcomment = NULL; /* Zip file comment (not zero-terminated) */
+struct zlist far **zsort; /* List of files sorted by name */
+#ifdef UNICODE_SUPPORT
+ struct zlist far **zusort; /* List of files sorted by zuname */
+#endif
+
+/* Files to operate on that are not in zip file */
+struct flist far *found = NULL; /* List of names found */
+struct flist far * far *fnxt = &found;
+ /* Where to put next name in found list */
+extent fcount; /* Count of files in list */
+
+/* Patterns to be matched */
+struct plist *patterns = NULL; /* List of patterns to be matched */
+unsigned pcount = 0; /* number of patterns */
+unsigned icount = 0; /* number of include only patterns */
+unsigned Rcount = 0; /* number of -R include patterns */
+
+#ifdef IZ_CHECK_TZ
+int zp_tz_is_valid; /* signals "timezone info is available" */
+#endif
diff --git a/human68k/Makefile b/human68k/Makefile
new file mode 100644
index 0000000..be1a8b7
--- /dev/null
+++ b/human68k/Makefile
@@ -0,0 +1,95 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for human68k
+# Written by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+#
+# 1999/09/23: Modified by Shimazaki Ryo.
+
+ifeq "$(TARGET)" "X68030"
+COPT = -m68020-40
+AOPT = -m68020 -sCPU020
+LDFLAGS = -L/usr/local/lib/lib060
+endif
+
+VPATH = human68k
+
+CC = gcc2
+CFLAGS = $(COPT) -I. -Wall -O2 -fomit-frame-pointer -fstrength-reduce \
+ -DASM_CRC -D__DOS_INLINE__
+#LDFLAGS = -Wl,-x
+LIBS = -lhmem -lttyi -lsignal
+
+AS = g2as
+ASFLAGS = $(AOPT) -1 -c4 -y -w2
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+ crc32.o human68k.o crc_68.o
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o human68k_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h human68k/osdep.h
+
+all: zips
+
+.SUFFIXES: _.o .o .c
+.c_.o:
+ $(CC) $(CFLAGS) -DUTIL -c $< -o $@
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $@
+
+ZIPS = zip.x zipnote.x zipsplit.x zipcloak.x
+
+zips: $(ZIPS)
+
+zip.x: $(OBJZ) $(OBJI) $(OBJA)
+ $(CC) $(LDFLAGS) -o $@ $(OBJZ) $(OBJI) $(OBJA) $(LIBS)
+zipnote.x: $(OBJN)
+ $(CC) $(LDFLAGS) -o $@ $(OBJN) $(LIBS)
+zipcloak.x: $(OBJC)
+ $(CC) $(LDFLAGS) -o $@ $(OBJC) $(LIBS)
+zipsplit.x: $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+
+human68k.o: human68k/human68k.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+human68k_.o: human68k/human68k.c
+ $(CC) $(CFLAGS) -c -o $@ $< -DUTIL
+
+#match.o: human68k/match.s
+# $(AS) $(ASFLAGS) -o $@ $<
+
+deflate.o: human68k/deflate.s
+ $(AS) $(ASFLAGS) -o $@ $<
+
+crc_68.o: human68k/crc_68.s
+ $(AS) $(ASFLAGS) -o $@ $<
+
+
+clean:
+ rm -f *.o $(ZIPS)
+
+zip.bfd: $(ZIPS)
+ rm -f $@
+ for file in $(ZIPS); do \
+ bdif -A -R uploaded/$$file $$file $@; \
+ done
+
+# rules for zip, zipnote, zipcloak, zipsplit.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: human68k/zipup.h
+
+# EOF
diff --git a/human68k/Makefile.gcc b/human68k/Makefile.gcc
new file mode 100644
index 0000000..edf2989
--- /dev/null
+++ b/human68k/Makefile.gcc
@@ -0,0 +1,78 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for human68k
+# Written by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+
+VPATH = human68k
+
+CC = gcc
+AS = as
+
+# if you are using mc68030 (or higher) based X68000,
+# uncomment following defines
+#CC = gcc -DUNALIGNED_OK
+#AS = as -s UNALIGNED_OK
+
+CFLAGS = -Wall -O -fomit-frame-pointer -fstrength-reduce -DASMV
+LDFLAGS = -s
+LIBS = -lsignal -lmb -ldos
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o crc32.o globals.o \
+ crypt.o ttyio.o
+
+OBJI = deflate.o trees.o
+OBJA = match.o human68k.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o human68_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h human68k/osdep.h
+
+all: zips
+
+.SUFFIXES: _.o .o .c
+.c_.o:
+ $(CC) $(CFLAGS) -DUTIL -c $< -o $@
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $@
+
+ZIPS = zip.x zipnote.x zipsplit.x zipcloak.x
+
+zips: $(ZIPS)
+
+zip.x: $(OBJZ) $(OBJI) $(OBJA)
+ $(CC) -o zip.x $(LDFLAGS) $(OBJZ) $(OBJI) $(OBJA) $(LIBS)
+zipnote.x: $(OBJN)
+ $(CC) -o zipnote.x $(LDFLAGS) $(OBJN) $(LIBS)
+zipcloak.x: $(OBJC)
+ $(CC) -o zipcloak.x $(LDFLAGS) $(OBJC) $(LIBS)
+zipsplit.x: $(OBJS)
+ $(CC) -o zipsplit.x $(LDFLAGS) $(OBJS) $(LIBS)
+
+match.o: human68k/match.s
+ $(AS) -o $@ $<
+
+human68_.o: human68k/human68k.c
+ $(CC) $(CFLAGS) -DUTIL -c -o $@ $<
+
+clean:
+ rm -f *.o $(ZIPS)
+
+zip.bfd: $(ZIPS)
+ rm -f $@
+ for file in $(ZIPS); do \
+ bdif -A -R uploaded/$$file $$file $@; \
+ done
+
+# rules for zip, zipnote, zipcloak, zipsplit.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: human68k/zipup.h
diff --git a/human68k/crc_68.s b/human68k/crc_68.s
new file mode 100644
index 0000000..9ce78d8
--- /dev/null
+++ b/human68k/crc_68.s
@@ -0,0 +1,144 @@
+;===========================================================================
+; Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_68 created by Paul Kienitz, last modified 04 Jan 96.
+;
+; Return an updated 32 bit CRC value, given the old value and a block of data.
+; The CRC table used to compute the value is gotten by calling get_crc_table().
+; This replaces the older updcrc() function used in Zip and fUnZip. The
+; prototype of the function is:
+;
+; ulg crc32(ulg crcval, uch *text, extent textlen);
+;
+; On the Amiga, type extent is always unsigned long, not unsigned int, because
+; int can be short or long at whim, but size_t is long.
+;
+; If using this source on a non-Amiga 680x0 system, note that we treat
+; a0/a1/d0/d1 as scratch registers not preserved across function calls.
+; We do not bother to support registerized arguments for crc32() -- the
+; textlen parm is usually large enough so that savings outside the loop
+; are pointless.
+;
+; Define NO_UNROLLED_LOOPS to use a simple short loop which might be more
+; efficient on certain machines with dinky instruction caches ('020?), or for
+; processing short strings. If loops are unrolled, the textlen parm must be
+; less than 512K; if not unrolled, it must be less than 64K.
+;
+; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
+
+ xdef _crc32 ; (ulg val, uch *buf, extent bufsize)
+
+DO_CRC0 MACRO
+ moveq #0,ltemp
+ move.b (textbuf)+,ltemp
+ eor.b crcval,ltemp
+ lsl.w #2,ltemp
+ move.l (crc_table,ltemp.w),ltemp
+ lsr.l #8,crcval
+ eor.l ltemp,crcval
+ ENDM
+
+
+DO_CRC2 MACRO
+ move.b (textbuf)+,btemp
+ eor.b crcval,btemp
+ lsr.l #8,crcval
+ move.l (crc_table,btemp.w*4),ltemp
+ eor.l ltemp,crcval
+ ENDM
+
+crc_table reg a0 array of unsigned long
+crcval reg d0 unsigned long initial value
+textbuf reg a1 array of unsigned char
+textbufsize reg d1 unsigned long (count of bytes in textbuf)
+btemp reg d2
+ltemp reg d3
+
+
+ xref _get_crc_table ; ulg *get_crc_table(void)
+
+
+
+ quad
+_crc32:
+ move.l 8(sp),d0
+ bne.s valid
+;;;;; moveq #0,d0
+ rts
+valid: movem.l btemp/ltemp,-(sp)
+ jsr _get_crc_table
+ movea.l d0,crc_table
+ move.l 12(sp),crcval
+ move.l 16(sp),textbuf
+ move.l 20(sp),textbufsize
+ not.l crcval
+
+ ifdef NO_UNROLLED_LOOPS
+
+ if CPU==68000
+ bra.s decr
+loop: DO_CRC0
+decr: dbra textbufsize,loop
+ bra.s done
+
+ else
+twenty: moveq #0,btemp
+ bra.s decr2
+loop2: DO_CRC2
+decr2: dbra textbufsize,loop2
+ endif
+
+ ELSE ; !NO_UNROLLED_LOOPS
+
+ if CPU==68000
+ moveq #7,btemp
+ and textbufsize,btemp
+ lsr.l #3,textbufsize
+ bra decr8
+loop8: DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+decr8: dbra textbufsize,loop8
+ bra.s decr1
+loop1: DO_CRC0
+decr1: dbra btemp,loop1
+ bra done
+
+ else
+twenty: moveq #0,btemp
+ move.l textbufsize,-(sp)
+ lsr.l #3,textbufsize
+ bra decr82
+ quad
+loop82: DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+decr82: dbra textbufsize,loop82
+ moveq #7,textbufsize
+ and.l (sp)+,textbufsize
+ bra.s decr12
+loop12: DO_CRC2
+decr12: dbra textbufsize,loop12
+ endif
+
+ ENDC ; ?NO_UNROLLED_LOOPS
+
+done: movem.l (sp)+,btemp/ltemp
+ not.l crcval
+;;;;; move.l crcval,d0 ; crcval already is d0
+ rts
diff --git a/human68k/deflate.s b/human68k/deflate.s
new file mode 100644
index 0000000..246962c
--- /dev/null
+++ b/human68k/deflate.s
@@ -0,0 +1,1076 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; This is a 680x0 assembly language translation of the Info-ZIP source file
+; deflate.c, by Paul Kienitz. No rights reserved. The function longest_match
+; is based in part on match.a by Carsten Steger, which in turn is partly based
+; on match.s for 386 by Jean-loup Gailly and Kai Uwe Rommel. Mostly, however,
+; this material is based on deflate.c, by Gailly, Rommel, and Igor Mandrichenko.
+; This code is not commented very much; see deflate.c for comments that explain
+; what the functions are doing.
+;
+; The symbols that can be used to select different versions are as follows:
+;
+; CPU020 if defined, use 68020 instructions always.
+;
+; CPUTEST if defined, check at runtime for CPU type. Another symbol
+; specifying the platform-specific test must be used with this.
+; If neither of these is defined, use 68000 instructions only.
+; Runtime test is nonportable; it is different for each OS.
+;
+; AMIGA use Amiga-specific test for 68020, if CPUTEST defined. Also
+; tells it that registers d0/a0/d1/a1 are not preserved by
+; function calls. At present, if AMIGA is not defined, it
+; causes functions to preserve all registers. ALL OF THIS CODE
+; CURRENTLY ASSUMES THAT REGISTERS D2-D7/A2-A6 WILL BE PRESERVED
+; BY ANY FUNCTIONS THAT IT CALLS.
+;
+; DYN_ALLOC should be defined here if it is defined for C source; tells us
+; that big arrays are allocated instead of static.
+;
+; WSIZE must be defined as the same number used for WSIZE in the C
+; source, and must be a power of two <= 32768. As elsewhere,
+; the default value is 32768.
+;
+; INT16 define this if ints are 16 bits; otherwise 32 bit ints assumed.
+;
+; SMALL_MEM define this if it is defined in the C source; otherwise it uses
+; the MEDIUM_MEM model. BIG_MEM and MMAP are *not* supported.
+; The FULL_SEARCH option in deflate.c is also not supported.
+;
+; DEBUG activates some tracing output, as in the C source.
+;
+; QUADLONG this selects a different version of the innermost longest_match
+; loop code for 68020 operations, comparing bytes four at a time
+; instead of two at a time. It seems to be a tiny bit faster on
+; average, but it's slower often enough that one can't generalize.
+;
+; This code currently assumes that function results are returned in D0 for
+; all platforms. It assumes that args to functions are pushed onto the stack,
+; last arg first. It also currently assumes that all C symbols have an
+; underscore prepended when referenced from assembly.
+;
+; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
+
+ IFNDEF CPU020
+ IFNDEF CPUTEST
+CPU000 equ 1
+ ENDC
+ ENDC
+
+; Use these macros for accessing variables of type int:
+ IFDEF INT16
+MOVINT MACRO _1,_2
+ move.w _1,_2
+ ENDM
+CLRINT MACRO _1
+ clr.w _1
+ ENDM
+INTSIZE equ 2
+ ELSE ; !INT16
+MOVINT MACRO _1,_2
+ move.l _1,_2
+ ENDM
+CLRINT MACRO _1
+ clr.l _1
+ ENDM
+INTSIZE equ 4
+ ENDC
+
+ IFDEF DYN_ALLOC
+BASEPTR MACRO _1,_2
+ move.l _1,_2
+ ENDM
+ ELSE
+BASEPTR MACRO _1,_2
+ lea _1,_2
+ ENDM
+ ENDC
+
+; constants we use, many of them adjustable:
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+TOO_FAR equ 4096
+ IFNDEF WSIZE
+WSIZE equ 32768
+ ENDC
+WMASK equ WSIZE-1
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+MIN_LOOKAHEAD equ MAX_MATCH+MIN_MATCH+1
+; IFD BIG_MEM ; NOT supported -- type Pos needs to be 32 bits
+;HASH_BITS equ 15
+; ELSE
+ IFDEF SMALL_MEM
+HASH_BITS equ 13
+ ELSE
+HASH_BITS equ 14 ; default -- MEDIUM_MEM
+ ENDC
+; ENDC ; BIG_MEM
+HASH_SIZE equ 1<<HASH_BITS
+HASH_MASK equ HASH_SIZE-1
+H_SHIFT equ (HASH_BITS+MIN_MATCH-1)/MIN_MATCH
+B_SLOW equ 1
+B_FAST equ 2
+ZE_MEM equ 4
+EOF equ -1
+
+; struct config is defined by these offsets:
+Good_length equ 0
+Max_lazy equ 2
+Nice_length equ 4
+Max_chain equ 6
+Sizeof_config equ 8
+
+
+; external functions we call:
+ xref _ct_tally ; int ct_tally(int, int)
+ xref _flush_block ; unsigned long F(char *, unsigned long, int)
+ xref _ziperr ; void ziperr(int, char *)
+ xref _error ; void error(char *)
+ xref _calloc ; stdlib function: void *calloc(size_t, size_t)
+ xref _free ; stdlib function: void free(void *)
+ IFDEF DEBUG
+ xref _fputc ; stdio function: int fputc(int, FILE *)
+ xref _stderr ; pointer to FILE, which we pass to fputc
+ ENDC
+
+; our entry points:
+ xdef _lm_init ; void lm_init(int level, unsigned short *flags)
+ xdef _lm_free ; void lm_free(void)
+ xdef _deflate ; void deflate(void) ...the big one
+ xdef _fill_window ; this line is just for debugging
+
+
+; ============================================================================
+; Here is where we have our global variables.
+
+;;; section deflatevars,data
+
+; external global variables we reference:
+ xref _verbose ; signed int
+ xref _level ; signed int
+ xref _read_buf ; int (*read_buf)(char *, unsigned int)
+
+; global variables we make available:
+
+ xdef _window
+ xdef _prev
+ xdef _head
+ xdef _window_size
+ xdef _block_start
+ xdef _strstart
+
+ bss
+ quad
+
+ IFDEF DYN_ALLOC
+_prev: ds.l 1 ; pointer to calloc()'d unsigned short array
+_head: ds.l 1 ; pointer to calloc()'d unsigned short array
+_window: ds.l 1 ; pointer to calloc()'d unsigned char array
+ ELSE ; !DYN_ALLOC
+_prev: ds.w WSIZE ; array of unsigned short
+_head: ds.w HASH_SIZE ; array of unsigned short
+_window: ds.b 2*WSIZE ; array of unsigned char
+ ENDC ; ?DYN_ALLOC
+
+ text
+ quad
+_window_size: ds.l 1 ; unsigned long
+_block_start: ds.l 1 ; unsigned long
+_strstart: ds.w INTSIZE/2 ; unsigned int
+
+; Now here are our private variables:
+
+ IFDEF CPUTEST
+is020: ds.w 1 ; bool: CPU type is '020 or higher
+ ENDC
+ins_h: ds.w 1 ; unsigned short
+sliding: ds.w 1 ; bool: the file is read a piece at a time
+eofile: ds.w 1 ; bool: we have read in the end of the file
+max_lazy_match: ds.w 1 ; unsigned short
+lookahead: ds.w 1 ; unsigned short
+
+; These are NOT DECLARED AS STATIC in deflate.c, but currently could be:
+max_chain_len: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+prev_length: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+good_match: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+nice_match: ds.w 1 ; unsigned short (signed int in deflate.c)
+match_start: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+
+; This array of struct config is a constant and could be in the code section:
+config_table: dc.w 0,0,0,0 ; level 0: store uncompressed
+ dc.w 4,4,8,4 ; level 1: fastest, loosest compression
+ dc.w 4,5,16,8 ; level 2
+ dc.w 4,6,32,32 ; level 3: highest to use deflate_fast
+ dc.w 4,4,16,16 ; level 4: lowest to use lazy matches
+ dc.w 8,16,32,32 ; level 5
+ dc.w 8,16,128,128 ; level 6: the default level
+ dc.w 8,32,128,256 ; level 7
+ dc.w 32,128,258,1024 ; level 8
+ dc.w 32,258,258,4096 ; level 9: maximum compression, slow
+
+
+;;CAL_SH MACRO ; macro for calling zcalloc()
+;; IFD INT16
+;; move.w #2,-(sp)
+;; move.w #\1,-(sp)
+;; jsr _zcalloc
+;; addq #4,sp
+;; ELSE
+;; pea 2
+;; pea \1
+;; jsr _zcalloc
+;; addq #8,sp
+;; ENDC
+;; ENDM
+
+CAL_SH MACRO _1 ; Okay, we're back to using regular calloc()...
+ movem.l d2/a2,-(sp)
+ pea 2
+ pea _1
+ jsr _calloc
+ addq #8,sp
+ movem.l (sp)+,d2/a2
+ ENDM
+
+; ============================================================================
+; And here we begin our functions. match_init is for internal use only:
+
+;; section deflate,code
+
+match_init:
+ IFDEF CPUTEST ; now check for platform type
+ IFDEF AMIGA ; Amiga specific test for '020 CPU:
+ xref _SysBase
+ NOLIST
+ INCLUDE 'exec/execbase.i'
+ LIST
+
+ clr.w is020 ; default value is 68000
+ move.l _SysBase,a0
+ btst #AFB_68020,AttnFlags+1(a0)
+ beq.s cheap
+ move.w #1,is020
+cheap:
+ ELSE ; !AMIGA
+
+ FAIL Write an '020-detector for your system here!
+; On the Macintosh, I believe GetEnvironment() provides the information.
+
+ ENDC ; AMIGA
+ ENDC ; CPUTEST
+ rts ; match_init consists only of rts if CPUTEST unset
+
+
+; ============================================================================
+; Here is longest_match(), the function that the rest of this was built up
+; from, the hottest hot spot in the program and therefore the most heavily
+; optimized. It has two different versions, one for '020 and higher CPUs, and
+; one for 68000/68010. It can test at runtime which version to use if you
+; create a test function in match_init for your platform. Currently such a
+; test is implemented for the Amiga. It can also be assembled to use '000 or
+; '020 code only.
+
+Cur_Match reg d0 ; unsigned int, kept valid as long
+Best_Len reg d1 ; unsigned int, kept valid as long
+Scan_Start reg d3 ; pair of bytes
+Scan_End reg d4 ; pair of bytes
+Limit reg d5 ; unsigned int
+Chain_Length reg d6 ; unsigned int
+Scan_Test reg d7 ; counter, pair of bytes sometimes
+Scan reg a0 ; pointer to unsigned char
+Match reg a1 ; pointer to unsigned char
+Prev_Address reg a2 ; pointer to unsigned short
+Scan_Ini reg a3 ; pointer to unsigned char
+Match_Ini reg a5 ; pointer to unsigned char
+; Note: "pair of bytes" means the two low order bytes of the register in
+; 68020 code, but means the lowest and third lowest bytes on the 68000.
+SAVEREGS reg d3-d7/a2/a3/a5 ; don't protect d0/d1/a0/a1
+; d2, a4, a6 not used... on Amiga, a4 is used by small-data memory model
+
+
+longest_match:
+ movem.l SAVEREGS,-(sp)
+
+; setup steps common to byte and word versions:
+ IFDEF INT16
+ and.l #$0000FFFF,Cur_Match ; upper half must be zero!
+; we use an and.l down here for the sake of ATSIGN/REGARGS.
+ moveq #0,Limit ; so adding to Scan_Ini works
+ ENDC
+ move.w (max_chain_len,pc),Chain_Length
+ move.w (prev_length,pc),Best_Len
+ MOVINT (_strstart,pc),Limit
+ BASEPTR _prev,Prev_Address
+ BASEPTR _window,Match_Ini
+ move.l Match_Ini,Scan_Ini
+ addq #MIN_MATCH,Match_Ini ; optimizes inner loop
+ add.l Limit,Scan_Ini
+ sub.w #MAX_DIST,Limit
+ bhi.s limit_ok
+ moveq #0,Limit
+limit_ok:
+ cmp.w (good_match,pc),Best_Len
+ blo.s length_ok
+ lsr.w #2,Chain_Length
+length_ok:
+ subq.w #1,Chain_Length
+
+ IFDEF CPUTEST
+ tst.w is020 ; can we use '020 stuff today?
+ bne WORD_match
+ ENDC
+
+ IFNDEF CPU020
+
+; for 68000 or 68010, use byte operations:
+ moveq #0,Scan_Start ; clear 2nd & 4th bytes, use 1st & 3rd
+ moveq #0,Scan_End ; likewise
+ moveq #0,Scan_Test ; likewise
+ move.b (Scan_Ini),Scan_Start
+ swap Scan_Start ; swap is faster than 8 bit shift
+ move.b 1(Scan_Ini),Scan_Start
+ move.b -1(Scan_Ini,Best_Len.w),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len.w),Scan_End
+ bra.s bdo_scan
+
+blong_loop:
+ move.b -1(Scan_Ini,Best_Len.w),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len.w),Scan_End
+
+bshort_loop:
+ add.w Cur_Match,Cur_Match ; assert value before doubling < 32K
+ IFNE 32768-WSIZE
+ and.w #(WMASK*2),Cur_Match
+ ENDC
+ move.w (Prev_Address,Cur_Match.l),Cur_Match
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,bdo_scan
+ bra return
+
+bdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ move.b -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH(Match,Best_Len.w),Scan_Test
+ cmp.l Scan_Test,Scan_End
+ bne.s bshort_loop
+ move.b -MIN_MATCH(Match),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.l Scan_Test,Scan_Start
+ bne.s bshort_loop
+ move.w #(MAX_MATCH-3),Scan_Test
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+bscan_loop:
+ cmp.b (Match)+,(Scan)+
+ dbne Scan_Test,bscan_loop
+ subq #1,Scan
+
+ sub.l Scan_Ini,Scan ; assert difference is 16 bits
+ cmp.w Best_Len,Scan
+ bls.s bshort_loop
+ MOVINT Scan,Best_Len
+ move.w Cur_Match,match_start
+ cmp.w (nice_match,pc),Best_Len
+ blo.s blong_loop
+ IFDEF CPUTEST
+ bra return
+ ENDC
+
+ ENDC ; !CPU020
+
+ IFNDEF CPU000
+;;; MACHINE MC68020
+
+; for 68020 or higher, use word operations even on odd addresses:
+WORD_match:
+ move.w (Scan_Ini),Scan_Start
+ move.w -1(Scan_Ini,Best_Len.w),Scan_End
+ bra.s wdo_scan
+
+wlong_loop:
+ move.w -1(Scan_Ini,Best_Len.w),Scan_End
+
+wshort_loop:
+ and.w #WMASK,Cur_Match
+ move.w (Prev_Address,Cur_Match.w*2),Cur_Match ; '020 addressing mode
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,wdo_scan
+ bra.s return
+
+wdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ cmp.w -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+ bne.s wshort_loop
+ cmp.w -MIN_MATCH(Match),Scan_Start
+ bne.s wshort_loop
+ IFDEF QUADLONG
+; By some measurements, this version of the code is a little tiny bit faster.
+; But on some files it's slower. It probably pays off only when there are
+; long match strings, and costs in the most common case of three-byte matches.
+ moveq #((MAX_MATCH-MIN_MATCH)/16),Scan_Test ; value = 15
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+wscan_loop:
+ cmp.l (Match)+,(Scan)+ ; test four bytes at a time
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ dbne Scan_Test,wscan_loop ; '020 can cache a bigger loop
+odd:
+ subq #4,Scan
+ subq #4,Match
+ cmp.b (Match)+,(Scan)+ ; find good bytes in bad longword
+ bne.s even
+ cmp.b (Match)+,(Scan)+
+ bne.s even
+ cmp.b (Match)+,(Scan)+
+ beq.s steven
+even: subq #1,Scan
+ ELSE ; !QUADLONG
+ moveq #((MAX_MATCH-MIN_MATCH)/2),Scan_Test ; value = 127
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+wscan_loop:
+ cmp.w (Match)+,(Scan)+
+ dbne Scan_Test,wscan_loop
+ subq #2,Scan
+ move.b -2(Match),Scan_Test
+ cmp.b (Scan),Scan_Test
+ bne.s steven
+ addq #1,Scan
+ ENDC ; ?QUADLONG
+steven:
+ sub.l Scan_Ini,Scan ; assert: difference is 16 bits
+ cmp.w Best_Len,Scan
+ bls.s wshort_loop
+ MOVINT Scan,Best_Len
+ move.w Cur_Match,match_start
+ cmp.w (nice_match,pc),Best_Len
+ blo.s wlong_loop
+
+;;; MACHINE MC68000
+ ENDC ; !CPU000
+
+return:
+ MOVINT Best_Len,d0 ; return value (upper half should be clear)
+ movem.l (sp)+,SAVEREGS
+ rts
+
+
+; =============================================================================
+; This is the deflate() function itself, our main entry point. It calls
+; longest_match, above, and some outside functions. It is a hot spot, but not
+; as hot as longest_match. It uses no special '020 code.
+
+; ================== Several macros used in deflate() and later functions:
+
+; Arg 1 is D-reg that new ins_h value is to be left in,
+; arg 2 is the byte value to be hashed into it, which must not be the same reg
+UP_HASH MACRO _1,_2
+ move.w (ins_h,pc),_1
+ asl.w #H_SHIFT,_1
+ eor.b _2,_1
+ and.w #HASH_MASK,_1 ; ((ins_h << H_SHIFT) ^ c) & HASH_MASK
+ move.w _1,ins_h ; ins_h = that
+ ENDM
+
+; Arg 1 is scratch A, arg 2 is scratch D
+IN_STR MACRO _1,_2
+ move.l Strst,_2
+ addq.w #MIN_MATCH-1,_2
+ move.b (Window,_2.l),_2 ; window[strstart + MIN_MATCH - 1]
+ UP_HASH Head,_2
+ add.l Head,Head ; assert upper word is zero before add
+ BASEPTR _head,_1
+ add.l Head,_1
+ move.w (_1),Head ; hash_head = head[ins_h]
+ move.w Strst,(_1) ; head[ins_h] = strstart
+ move.l Strst,_2
+ IFNE WSIZE-32768
+ and.w #WMASK,_2
+ ENDC
+ add.w _2,_2 ; masks implicitly when WSIZE == 32768
+ move.w Head,(Prev,_2.l) ; prev[str_start & WMASK] = hash_head
+ ENDM
+
+; Arg 1 is bool (int) EOF flag, flush_block result is in d0, trashes d1/a0/a1
+FLUSH_B MACRO _1
+ local nenu,nun
+ movem.l d2/a2,-(sp)
+ IF _1==0
+ CLRINT -(sp)
+ ELSEIF (INTSIZE==4).and.(_1<$8000)
+ pea (_1).w
+ ELSE
+ MOVINT #_1,-(sp)
+ ENDC
+ move.l (_block_start,pc),d0
+ blt.s nenu
+ move.l Window,a0
+ add.l d0,a0
+ bra.s nun
+nenu: sub.l a0,a0 ; if block_start < 0, push NULL
+nun: sub.l Strst,d0
+ neg.l d0
+ move.l d0,-(sp)
+ move.l a0,-(sp)
+ jsr _flush_block
+ lea 8+INTSIZE(sp),sp
+ movem.l (sp)+,d2/a2
+ ENDM
+
+; This expands to nothing unless DEBUG is defined.
+; Arg 1 is a byte to be trace-outputted -- if it is d0 it must be a valid int
+TRACE_C MACRO _1
+ local qui
+ IFDEF DEBUG
+ cmp.w #1,_verbose+INTSIZE-2 ; test lower word only
+ ble.s qui
+ moveq #0,d0
+ move.b ea,d0
+ movem.l d2/a2,-(sp)
+ move.l _stderr,-(sp)
+ MOVINT d0,-(sp)
+ jsr _fputc
+ addq.l #4+INTSIZE,sp
+ movem.l (sp)+,d2/a2
+qui:
+ ENDC ; DEBUG
+ ENDM
+
+; ================== Here are the register vars we use, and deflate() itself:
+
+Window reg a2 ; cached address of window[]
+Prev reg a3 ; cached address of prev[]
+Strst reg d7 ; strstart cached as a longword
+Look reg d6 ; lookahead cached as short
+Head reg d5 ; local variable hash_head, short
+PrevL reg d4 ; prev_length cached as short
+MatchL reg d3 ; local variable match_length, unsigned short
+Avail reg d2 ; local variable available_match, bool
+PrevM reg a5 ; local variable prev_match, int in an A-reg
+
+DEFREGS reg d3-d7/a3/a5
+
+
+_deflate: ; first, setup steps common to deflate and deflate_fast:
+ movem.l DEFREGS,-(sp)
+ IFDEF INT16
+ moveq #0,Strst ; make sure strstart is valid as a long
+ ENDC
+ moveq #0,Head ; ditto for hash_head
+ MOVINT (_strstart,pc),Strst
+ move.w (lookahead,pc),Look
+ move.w (prev_length,pc),PrevL
+ BASEPTR _window,Window
+ BASEPTR _prev,Prev
+ MOVINT _level,d0
+ cmp.w #3,d0
+ ble deflate_fast
+ moveq #MIN_MATCH-1,MatchL
+ moveq #0,Avail
+
+look_loop:
+ tst.w Look
+ beq last_tally
+ IN_STR a0,d0
+ move.w MatchL,PrevL
+ move.w (match_start,pc),PrevM
+ move.w #MIN_MATCH-1,MatchL
+
+ tst.w Head
+ beq.s no_new_match
+ cmp.w (max_lazy_match,pc),PrevL
+ bhs.s no_new_match
+ move.w Strst,d0
+ sub.w Head,d0
+ cmp.w #MAX_DIST,d0
+ bhi.s no_new_match
+ move.w PrevL,prev_length ; longest_match reads these variables
+ MOVINT Strst,_strstart
+ MOVINT Head,d0 ; parm for longest_match
+ bsr longest_match ; sets match_start
+ cmp.w Look,d0 ; does length exceed valid data?
+ bls.s stml
+ move.w Look,d0
+stml: move.w d0,MatchL ; valid length of match
+ cmp.w #MIN_MATCH,MatchL ; is the match only three bytes?
+ bne.s no_new_match
+ move.w (match_start,pc),d0
+ sub.w Strst,d0
+ cmp.w #-TOO_FAR,d0
+ bge.s no_new_match
+ moveq #MIN_MATCH-1,MatchL ; mark the current match as no good
+
+no_new_match:
+ cmp.w #MIN_MATCH,PrevL
+ blo literal
+ cmp.w MatchL,PrevL
+ blo literal
+ ; CHECK_MATCH Strst-1,PrevM,PrevL
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ move.l PrevL,d0
+ subq.w #MIN_MATCH,d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ move.l Strst,d0
+ sub.w PrevM,d0
+ subq.w #1,d0
+ MOVINT d0,-(sp)
+ jsr _ct_tally ; sets d0 true if we have to flush
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ subq.w #3,PrevL ; convert for dbra (prev_length - 2)
+ sub.w PrevL,Look
+ subq.w #2,Look
+insertmatch:
+ addq.w #1,Strst
+ IN_STR a0,d1 ; don't clobber d0
+ dbra PrevL,insertmatch
+ moveq #0,Avail
+ moveq #0,PrevL ; not needed?
+ moveq #MIN_MATCH-1,MatchL
+ addq.w #1,Strst
+ tst.w d0
+ beq refill
+ FLUSH_B 0
+ move.l Strst,_block_start
+ bra.s refill
+
+literal:
+ tst.w Avail
+ bne.s yeslit
+ moveq #1,Avail
+ bra.s skipliteral
+yeslit: TRACE_C <-1(Window,Strst.l)>
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b -1(Window,Strst.l),d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ tst.w d0
+ beq.s skipliteral
+ FLUSH_B 0
+ move.l Strst,_block_start
+skipliteral:
+ addq.w #1,Strst
+ subq.w #1,Look
+
+refill:
+ cmp.w #MIN_LOOKAHEAD,Look
+ bhs look_loop
+ bsr fill_window
+ bra look_loop
+
+last_tally:
+ tst.w Avail
+ beq last_flush
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b -1(Window,Strst.l),d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+last_flush:
+ FLUSH_B 1
+ bra deflate_exit
+
+; ================== This is another version used for low compression levels:
+
+deflate_fast:
+ moveq #0,MatchL
+ moveq #MIN_MATCH-1,PrevL
+flook_loop:
+ tst.w Look
+ beq flast_flush
+
+ IN_STR a0,d0
+ tst.w Head
+ beq.s fno_new_match
+ move.w Strst,d0
+ sub.w Head,d0
+ cmp.w #MAX_DIST,d0
+ bhi.s fno_new_match
+ move.w PrevL,prev_length ; longest_match reads these variables
+ MOVINT Strst,_strstart
+ MOVINT Head,d0 ; parm for longest_match
+ bsr longest_match ; sets match_start
+ cmp.w Look,d0 ; does length exceed valid data?
+ bls.s fstml
+ move.w Look,d0
+fstml: move.w d0,MatchL ; valid length of match
+
+fno_new_match:
+ cmp.w #MIN_MATCH,MatchL
+ blo fliteral
+ ; CHECK_MATCH Strst,match_start,MatchL
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ move.l MatchL,d0
+ subq.w #MIN_MATCH,d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ move.l Strst,d0
+ sub.w (match_start,pc),d0
+ MOVINT d0,-(sp)
+ jsr _ct_tally ; sets d0 true if we have to flush
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ sub.w MatchL,Look
+ cmp.w (max_lazy_match,pc),MatchL
+ bhi ftoolong
+ subq.w #2,MatchL
+finsertmatch:
+ addq.w #1,Strst
+ IN_STR a0,d1 ; preserve d0
+ dbra MatchL,finsertmatch
+ moveq #0,MatchL ; not needed?
+ addq.w #1,Strst
+ bra.s flushfill
+
+ftoolong:
+ add.w MatchL,Strst
+ moveq #0,MatchL
+ moveq #0,d1 ; preserve d0
+ move.b (Window,Strst.l),d1
+ move.w d1,ins_h
+; My assembler objects to passing <1(Window,Strst.l)> directly to UP_HASH...
+ move.b 1(Window,Strst.l),Avail ; Avail is not used in deflate_fast
+ UP_HASH d1,Avail ; preserve d0
+ IFNE MIN_MATCH-3
+ FAIL needs to UP_HASH another MIN_MATCH-3 times, but with what arg?
+ ENDC
+ bra.s flushfill
+
+fliteral:
+ TRACE_C <(Window,Strst.l)>
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b (Window,Strst.l),d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally ; d0 set if we need to flush
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ addq.w #1,Strst
+ subq.w #1,Look
+
+flushfill:
+ tst.w d0
+ beq.s frefill
+ FLUSH_B 0
+ move.l Strst,_block_start
+frefill:
+ cmp.w #MIN_LOOKAHEAD,Look
+ bhs flook_loop
+ bsr fill_window
+ bra flook_loop
+
+flast_flush:
+ FLUSH_B 1 ; sets our return value
+
+deflate_exit:
+ MOVINT Strst,_strstart ; save back cached values
+ move.w PrevL,prev_length
+ move.w Look,lookahead
+ movem.l (sp)+,DEFREGS
+ rts
+
+
+; =========================================================================
+; void fill_window(void) calls the input function to refill the sliding
+; window that we use to find substring matches in.
+
+More reg Head ; local variable in fill_window
+WindTop reg Prev ; local variable used for sliding
+SlidIx reg PrevL ; local variable used for sliding
+
+FWREGS reg d2-d5/a2-a6 ; does NOT include Look and Strst
+; all registers available to be clobbered by the sliding operation:
+; we exclude More, WindTop, SlidIx, Look, Strst, Window, a4 and a7.
+SPAREGS reg d0-d3/a0-a1/a5-a6
+SPCOUNT equ 8 ; number of registers in SPAREGS
+
+
+_fill_window: ; C-callable entry point
+ movem.l Look/Strst,-(sp)
+ IFDEF INT16
+ moveq #0,Strst ; Strst must be valid as a long
+ ENDC
+ MOVINT (_strstart,pc),Strst
+ move.w (lookahead,pc),Look
+ BASEPTR _window,Window
+ bsr.s fill_window
+ MOVINT Strst,_strstart
+ move.w Look,lookahead
+ movem.l (sp)+,Look/Strst
+ rts
+
+; strstart, lookahead, and window must be cached in Strst, Look, and Window:
+fill_window: ; asm-callable entry point
+ movem.l FWREGS,-(sp)
+ move.w (eofile,pc),d0 ; we put this up here for speed
+ bne fwdone
+ and.l #$FFFF,Look ; make sure Look is valid as long
+fw_refill:
+ move.l (_window_size,pc),More ; <= 64K
+ sub.l Look,More
+ sub.l Strst,More ; Strst is already valid as long
+ cmp.w #EOF,More
+ bne.s notboundary
+ subq.w #1,More
+ bra checkend
+
+notboundary:
+ move.w (sliding,pc),d0
+ beq checkend
+ cmp.w #WSIZE+MAX_DIST,Strst
+ blo checkend
+ IF (32768-WSIZE)>0
+ lea WSIZE(Window),WindTop ; WindTop is aligned when Window is
+ ELSE
+ move.l Window,WindTop
+ add.l #WSIZE,WindTop
+ ENDC
+ move.l Window,d0
+ and.w #3,d0
+ beq.s isaligned
+ subq.w #1,d0
+align: move.b (WindTop)+,(Window)+ ; copy up to a longword boundary
+ dbra d0,align
+isaligned:
+; This is faster than a simple move.l (WindTop)+,(Window)+ / dbra loop:
+ move.w #(WSIZE-1)/(4*SPCOUNT),SlidIx
+slide: movem.l (WindTop)+,SPAREGS ; copy, 32 bytes at a time!
+ movem.l SPAREGS,(Window) ; a slight overshoot doesn't matter.
+ lea 4*SPCOUNT(Window),Window ; can't use (aN)+ as movem.l dest
+ dbra SlidIx,slide
+ BASEPTR _window,Window ; restore cached value
+ sub.w #WSIZE,match_start
+ sub.w #WSIZE,Strst
+ sub.l #WSIZE,_block_start
+ add.w #WSIZE,More
+ BASEPTR _head,a0
+ move.w #HASH_SIZE-1,d0
+fixhead:
+ move.w (a0),d1
+ sub.w #WSIZE,d1
+ bpl.s headok
+ moveq #0,d1
+headok: move.w d1,(a0)+
+ dbra d0,fixhead
+ BASEPTR _prev,a0
+ move.w #WSIZE-1,d0
+fixprev:
+ move.w (a0),d1
+ sub.w #WSIZE,d1
+ bpl.s prevok
+ moveq #0,d1
+prevok: move.w d1,(a0)+
+ dbra d0,fixprev
+ TRACE_C #'.'
+
+ move _verbose+INTSIZE-2,d0
+ beq checkend
+ movem.l d2/a2,-(sp)
+ xref _print_period
+ jsr _print_period
+ movem.l (sp)+,d2/a2
+
+checkend: ; assert eofile is false
+ movem.l d2/a2,-(sp)
+ MOVINT More,-(sp) ; assert More's upper word is zero
+ move.l Strst,d0
+ add.w Look,d0
+ add.l Window,d0
+ move.l d0,-(sp)
+ move.l _read_buf,a0
+ jsr (a0) ; refill the upper part of the window
+ addq #4+INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ tst.w d0
+ beq.s iseof
+ cmp.w #EOF,d0
+ beq.s iseof
+ add.w d0,Look
+ cmp.w #MIN_LOOKAHEAD,Look
+ blo fw_refill ; eofile is still false
+
+ bra.s fwdone
+iseof: move.w #1,eofile
+fwdone: movem.l (sp)+,FWREGS
+ rts
+
+
+; =========================================================================
+; void lm_free(void) frees dynamic arrays in the DYN_ALLOC version.
+
+;;; xdef _lm_free ; the entry point
+
+_lm_free:
+ IFDEF DYN_ALLOC
+ move.l _window,d0
+ beq.s lf_no_window
+ movem.l d2/a2,-(sp)
+ move.l d0,-(sp)
+ jsr _free
+ addq #4,sp
+ movem.l (sp)+,d2/a2
+ clr.l _window
+lf_no_window:
+ move.l _prev,d0
+ beq.s lf_no_prev
+ movem.l d2/a2,-(sp)
+ move.l d0,-(sp)
+ jsr _free
+ move.l _head,(sp) ; reuse the same stack arg slot
+ jsr _free
+ addq #4,sp
+ movem.l (sp)+,d2/a2
+ clr.l _prev
+ clr.l _head
+lf_no_prev:
+ ENDC
+ rts
+
+; ============================================================================
+; void lm_init(int pack_level, unsigned short *flags) allocates dynamic arrays
+; if any, and initializes all variables so that deflate() is ready to go.
+
+;;; xdef _lm_init ; the entry point
+
+Level reg d2
+;Window reg a2 ; as in deflate()
+
+_lm_init:
+ MOVINT 4(sp),d0
+ move.l 4+INTSIZE(sp),a0
+ move.w d0,Level
+ cmp.w #1,Level
+ blt.s levelerr
+ bgt.s try9
+ bset.b #B_FAST,1(a0)
+try9: cmp.w #9,Level
+ bgt.s levelerr
+ blt.s levelok
+ bset.b #B_SLOW,1(a0)
+ bra.s levelok
+levelerr:
+ pea (level_message,pc)
+ jsr _error ; never returns
+levelok:
+ clr.w sliding
+ move.l (_window_size,pc),d0
+ bne.s gotawindowsize
+ move.w #1,sliding
+ move.l #2*WSIZE,_window_size
+gotawindowsize:
+
+ BASEPTR _window,Window
+ IFDEF DYN_ALLOC
+ move.l Window,d0 ; fake tst.l
+ bne.s gotsomewind
+ CAL_SH WSIZE
+ move.l d0,Window
+ move.l d0,_window
+ bne.s gotsomewind
+ pea (window_message,pc)
+ bra error
+gotsomewind:
+ tst.l _prev
+ bne.s gotsomehead
+ CAL_SH WSIZE
+ move.l d0,_prev
+ beq.s nohead
+ CAL_SH HASH_SIZE
+ move.l d0,_head
+ bne.s gotfreshhead ; newly calloc'd memory is zeroed
+nohead: pea (hash_message,pc)
+error: MOVINT #ZE_MEM,-(sp)
+ jsr _ziperr ; never returns
+gotsomehead:
+ ENDC ; DYN_ALLOC
+
+ move.w #(HASH_SIZE/2)-1,d0 ; two shortwords per loop
+ BASEPTR _head,a0
+wipeh: clr.l (a0)+
+ dbra d0,wipeh
+gotfreshhead:
+ move.l Level,d0
+ IFEQ Sizeof_config-8
+ asl.l #3,d0
+ ELSE
+ mulu #Sizeof_config,d0
+ ENDC
+ lea (config_table,pc),a0
+ add.l d0,a0
+ move.w Max_lazy(a0),max_lazy_match
+ move.w Good_length(a0),good_match
+ move.w Nice_length(a0),nice_match
+ move.w Max_chain(a0),max_chain_len
+ CLRINT _strstart
+ clr.l _block_start
+ bsr match_init
+
+ clr.w eofile
+ movem.l d2/a2,-(sp)
+ MOVINT #WSIZE,-(sp) ; We read only 32K because lookahead is short
+ move.l Window,-(sp) ; even when int size is long, as if deflate.c
+ move.l _read_buf,a0 ; were compiled with MAXSEG_64K defined.
+ jsr (a0)
+ addq #4+INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ move.w d0,lookahead
+ beq.s noread
+ cmp.w #EOF,d0
+ bne.s irefill
+noread: move.w #1,eofile
+ clr.w lookahead
+ bra.s init_done
+
+irefill:
+ move.w (lookahead,pc),d0
+ cmp.w #MIN_LOOKAHEAD,d0
+ bhs.s hashify
+ bsr _fill_window ; use the C-callable version
+hashify:
+ clr.w ins_h
+ moveq #MIN_MATCH-2,d0
+hash1: move.b (Window)+,d1
+ UP_HASH Level,d1
+ dbra d0,hash1
+
+init_done:
+ rts
+
+; strings for error messages:
+ IFDEF DYN_ALLOC
+hash_message dc.b 'hash table allocation',0
+window_message dc.b 'window allocation',0
+ ENDC
+level_message dc.b 'bad pack level',0
+
+ end
diff --git a/human68k/human68k.c b/human68k/human68k.c
new file mode 100644
index 0000000..be47b57
--- /dev/null
+++ b/human68k/human68k.c
@@ -0,0 +1,371 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#include <time.h>
+#include <stdio.h>
+#include <dirent.h>
+#ifndef UTIL
+#include <sys/dos.h>
+#endif
+
+#define MATCH shmatch
+
+#define PAD 0
+
+
+#ifndef UTIL
+
+/* Library functions not in (most) header files */
+
+int utime OF((char *, ztimbuf *));
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+local char *readd(DIR* d)
+{
+ struct dirent* e = readdir(d);
+
+ return e == NULL ? NULL : e->d_name;
+}
+
+int wild(char* w)
+{
+ struct _filbuf inf;
+ /* convert FNAMX to malloc - 11/08/04 EG */
+ char *name;
+ char *p;
+
+ if (strcmp(w, "-") == 0) /* if compressing stdin */
+ return newname(w, 0, 0);
+ if ((name = malloc(strlen(w) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wild");
+ }
+ strcpy(name, w);
+ _toslash(name);
+
+ if ((p = strrchr(name, '/')) == NULL && (p = strrchr(name, ':')) == NULL)
+ p = name;
+ else
+ p++;
+ if (_dos_lfiles (&inf, w, 0xff) < 0) {
+ free(name);
+ return ZE_MISS;
+ }
+ do {
+ int r;
+
+ strcpy(p, inf.name);
+ r = procname(name, 0);
+ if (r != ZE_OK) {
+ free(name);
+ return r;
+ }
+ } while (_dos_nfiles(&inf) >= 0);
+ free(name);
+
+ return ZE_OK;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ _toslash(n);
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+
+ /* Find starting point in name before doing malloc */
+ t = (x[0] && x[1] == (char)':') ? x + 2 : x;
+ while (*t == (char)'/')
+ t++;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ _toslash(t);
+
+ if (!pathput)
+ t = last(t, '/');
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosify;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ return strcpy(x, n);
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ ztimbuf u; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ /* Set updated and accessed times of f */
+ utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+ isstdin = !strcmp(f, "-");
+
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (isstdin) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+
+ if (a != NULL) {
+ int atr = _dos_chmod(name, -1);
+
+ if (atr < 0)
+ atr = 0x20;
+ *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)atr);
+ }
+ free(name);
+ if (n != NULL)
+ *n = S_ISVOL(s.st_mode) ? -2L : S_ISREG(s.st_mode) ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+ if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME;
+ z->extra[5] = (char)(z_utim->mtime);
+ z->extra[6] = (char)(z_utim->mtime >> 8);
+ z->extra[7] = (char)(z_utim->mtime >> 16);
+ z->extra[8] = (char)(z_utim->mtime >> 24);
+
+ z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+ z->cextra = z->extra;
+
+ return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+ return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ return rmdir(d);
+}
+
+void print_period(void)
+{
+ fputc('.', stderr);
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if 0
+ char buf[40];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+# if 0
+ "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
+# else
+ "unknown compiler", "",
+# endif
+#endif
+
+ "Human68k",
+#ifdef __MC68020__
+ " (X68030)",
+#else
+ " (X680x0)",
+#endif
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
diff --git a/human68k/match.s b/human68k/match.s
new file mode 100644
index 0000000..4e6bc1c
--- /dev/null
+++ b/human68k/match.s
@@ -0,0 +1,163 @@
+*===========================================================================
+* Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+*
+* See the accompanying file LICENSE, version 1999-Oct-05 or later
+* (the contents of which are also included in zip.h) for terms of use.
+* If, for some reason, both of these files are missing, the Info-ZIP license
+* also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*===========================================================================
+*
+* match.s -- optional optimized asm version of longest match in deflate.c
+* Written by Jean-loup Gailly
+*
+* Adapted for X68000 by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+* Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+* using the code in match.S.
+* The major change in this code consists of removing all unaligned
+* word accesses, because they cause 68000-based machines to crash.
+* For maximum speed, UNALIGNED_OK can be defined.
+* The program will then only run on 68020-based machines, though.
+
+
+Cur_Match reg d0 ; Must be in d0!
+Best_Len reg d1
+Loop_Counter reg d2
+Scan_Start reg d3
+Scan_End reg d4
+Limit reg d5
+Chain_Length reg d6
+Scan_Test reg d7
+Scan reg a0
+Match reg a1
+Prev_Address reg a2
+Scan_Ini reg a3
+Match_Ini reg a4
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+WSIZE equ 32768
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+
+
+ .xref _max_chain_length
+ .xref _prev_length
+ .xref _prev
+ .xref _window
+ .xref _strstart
+ .xref _good_match
+ .xref _match_start
+ .xref _nice_match
+
+
+ .xdef _match_init
+ .xdef _longest_match
+
+ .text
+ .even
+
+
+_match_init:
+ rts
+
+
+_longest_match:
+ move.l 4(sp),Cur_Match
+.ifdef UNALIGNED_OK
+ movem.l d2-d6/a2-a4,-(sp)
+.else
+ movem.l d2-d7/a2-a4,-(sp)
+.endif
+ move.l _max_chain_length,Chain_Length
+ move.l _prev_length,Best_Len
+ lea _prev,Prev_Address
+ lea _window+MIN_MATCH,Match_Ini
+ move.l _strstart,Limit
+ move.l Match_Ini,Scan_Ini
+ add.l Limit,Scan_Ini
+ subi.w #MAX_DIST,Limit
+ bhi.b limit_ok
+ moveq #0,Limit
+limit_ok:
+ cmp.l _good_match,Best_Len
+ bcs.b length_ok
+ lsr.l #2,Chain_Length
+length_ok:
+ subq.l #1,Chain_Length
+
+.ifdef UNALIGNED_OK
+ move.w -MIN_MATCH(Scan_Ini),Scan_Start
+ move.w -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+.else
+ move.b -MIN_MATCH(Scan_Ini),Scan_Start
+ lsl.w #8,Scan_Start
+ move.b -MIN_MATCH+1(Scan_Ini),Scan_Start
+ move.b -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+ lsl.w #8,Scan_End
+ move.b -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
+.endif
+
+ bra.b do_scan
+
+long_loop:
+
+.ifdef UNALIGNED_OK
+ move.w -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+.else
+ move.b -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+ lsl.w #8,Scan_End
+ move.b -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
+.endif
+
+short_loop:
+ lsl.w #1,Cur_Match
+ move.w 0(Prev_Address,Cur_Match.l),Cur_Match
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,do_scan
+ bra.b return
+
+do_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+
+.ifdef UNALIGNED_OK
+ cmp.w -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+ bne.b short_loop
+ cmp.w -MIN_MATCH(Match),Scan_Start
+ bne.b short_loop
+.else
+ move.b -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+ lsl.w #8,Scan_Test
+ move.b -MIN_MATCH(Match,Best_Len.w),Scan_Test
+ cmp.w Scan_Test,Scan_End
+ bne.b short_loop
+ move.b -MIN_MATCH(Match),Scan_Test
+ lsl.w #8,Scan_Test
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.w Scan_Test,Scan_Start
+ bne.b short_loop
+.endif
+
+ move.w #(MAX_MATCH-MIN_MATCH),Loop_Counter
+ move.l Scan_Ini,Scan
+scan_loop:
+ cmpm.b (Match)+,(Scan)+
+ dbne Loop_Counter,scan_loop
+
+ sub.l Scan_Ini,Scan
+ addq.l #(MIN_MATCH-1),Scan
+ cmp.l Best_Len,Scan
+ bls.b short_loop
+ move.l Scan,Best_Len
+ move.l Cur_Match,_match_start
+ cmp.l _nice_match,Best_Len
+ bcs.b long_loop
+return:
+ move.l Best_Len,d0
+.ifdef UNALIGNED_OK
+ movem.l (sp)+,d2-d6/a2-a4
+.else
+ movem.l (sp)+,d2-d7/a2-a4
+.endif
+ rts
+
+ end
diff --git a/human68k/osdep.h b/human68k/osdep.h
new file mode 100644
index 0000000..088a9ac
--- /dev/null
+++ b/human68k/osdep.h
@@ -0,0 +1,28 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/xglob.h>
+
+#ifdef ZCRYPT_INTERNAL
+# include <process.h> /* getpid() declaration for srand seed */
+#endif
+
+#define USE_CASE_MAP
+
+#define ROUNDED_TIME(time) (((time) + 1) & (~1))
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#ifdef HAVE_MBCTYPE_H
+# include <mbctype.h>
+#else
+# define ismbblead(c) (0x80 <= (c) && ((c) < 0xa0 || 0xe0 <= (c)))
+#endif
diff --git a/human68k/zipup.h b/human68k/zipup.h
new file mode 100644
index 0000000..592cff8
--- /dev/null
+++ b/human68k/zipup.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/macos/Contents b/macos/Contents
new file mode 100644
index 0000000..3aec069
--- /dev/null
+++ b/macos/Contents
@@ -0,0 +1,63 @@
+Contents of the "macos" sub-archive for Zip 2.3 and later:
+
+
+MacOS:
+
+ Contents this file
+ readme.1st Instruction to unpack mac specific files
+ README.TXT Dirk Haase's infos on updated MacIntosh ports of Zip/UnZip
+ HISTORY.TXT Dirk Haase's MacOS specific ChangeLog
+
+ zipup.h MacOS
+ osdep.h MacOS specific configuration and declarations
+
+ ZipLib.h used to build a static library, global to the project
+ ZipSx.h used to build a standalone App with MW Sioux, global
+ to the project
+ ZpPrj.hqx Metrowerks CodeWarrior pro3 project file (BinHex)
+
+
+ source/ subdirectory containing all sources:
+ a) Zip specific code
+ extrafld.c contains all code related to the mac extra field
+ extrafld.h
+ macglob.h
+ macopen.c replaces fopen() and open()
+ macopen.h
+ macos.c Macintosh-specific routines for use with Info-ZIP's Zip
+ MatWild.c Pattern matching function
+ recurse.c Functions to go through the directories
+ recurse.h
+ unixlike.c This file provides a unix like file-stat routine
+ unixlike.h
+ VolWarn.h contains the warning message, about volumes with the
+ same name
+ zip_rc.hqx resource file for Macintosh unzip (BinHex)
+
+
+ b) general utilities shared between Zip and UnZip
+ charmap.h character mapping tables ISO 8859-1 <--> MacRoman
+ helpers.c some helper functions
+ helpers.h
+ macstuff.c Mac filemanager routines copied from MoreFiles 1.4.8
+ macstuff.h
+ mactime.c replacement for broken Metrowerks RTL time functions
+ pathname.c functions for handling MacOS HFS path- /filenames
+ pathname.h
+
+The new ZpPrj.hqx project file should be "un-BinHex'ed" into ZpPrj,
+which builds the following targets:
+ - Zip Lib (68K) -> static library 68k
+ - Zip Lib (PPC) -> static library PPC
+ - Zip Sioux (68K) -> MW Sioux standalone App, good for debugging
+ - Zip Sioux (PPC) -> MW Sioux standalone App, good for debugging
+
+
+The resource files and the compiler project files are in BinHex form because
+they contain Macintosh resource forks. The resource info cannot be
+maintained when handling (e.g. repacking) the master source collection on
+non-Macintosh systems. The BinHex form is the traditional way for
+transferring such files via non-Macintosh systems.
+It's also the safest since it uses only printable characters. The ".hqx"
+files must be converted with StuffitExpander or BinHex 4.0 (or equivalent)
+on a Macintosh system before using them.
diff --git a/macos/HISTORY.TXT b/macos/HISTORY.TXT
new file mode 100644
index 0000000..3a14a02
--- /dev/null
+++ b/macos/HISTORY.TXT
@@ -0,0 +1,600 @@
+A free Macintosh Port of Info-ZIP's
+Zip and UnZip
+By Dirk Haase, d_haase@sitec.net
+Home page: www.sitec.net/maczip
+Mirror page:
+www.haase-online.de/dirk/maczip
+================================
+
+
+
+
+
+Release MacZip ver1.07 beta 1
+22. Februray 2001
+-----------------
+
+1) CHG: {unzip} switch to latest final release
+ unzip 5.42
+
+2) CHG: {zip} switch to latest beta release
+ zip 2.40a
+
+
+
+
+
+Release MacZip ver1.06 final
+22. Februray 2001
+-----------------
+
+1) CHG: {unzip} switch to latest final release
+ unzip 5.42
+
+2) CHG: switch to latest release of Apples
+ Universal Interfaces 3.3.2
+
+3) CHG: switch to latest release of
+ Morefiles 1.5
+
+
+
+
+Release MacZip ver1.06 beta 2
+02. August 2000
+---------------
+
+1) CHG: {unzip} switch to latest beta release
+ unzip 5.42d
+
+
+
+
+
+Release MacZip ver1.06 beta 1
+27. July 2000
+-------------
+
+1) CHG: {zip} switch to latest beta release
+ unzip 2.30
+
+2) CHG: {unzip} switch to latest beta release
+ unzip 5.42c
+
+
+
+
+
+Release MacZip ver1.05 final
+27. July 2000
+-------------
+
+1) CHG: {unzip} switch to latest final release
+ unzip 5.41
+
+2) FIX: {unzip} Fixed "unique unzip folder" foldername handling
+
+3) FIX: {unzip} added prototype crc32() in macbin3.c
+
+4) CHG: {unzip/zip} added exported Codewarrior project-file in xml-format
+
+5) ADD: {unzip} added extra-field recognition for Mac SmartZip in
+ zipinfo.c and unzpriv.h.
+
+
+
+
+
+Release MacZip ver1.04 final
+25. January 2000
+----------------
+
+
+Final release of MacZip. All parts now
+in final release state !!
+
+1) Switch to MW Codewarrior pro 5.3
+
+2) CHG: {zip} switch (back) to latest final release
+ unzip 2.30
+
+3) CHG: {unzip} switch (back) to latest final release
+ unzip 5.40
+
+
+
+
+Release MacZip ver1.04 beta 3
+05. October 1999
+----------------
+
+1) CHG: {zip} switch to latest source level
+ unzip 2.30o beta release
+
+2) CHG: {unzip} switch to latest source level
+ unzip 5.41c beta release
+
+3) ADD: {console} added menu to print the license
+
+
+
+
+Release MacZip ver1.04 beta 2
+02. June 1999
+--------------
+
+1) FIX: {unzip} added one more criteria to make the recognition
+ of macbinary more save.
+
+2) FIX: {unzip} sometimes, archive entries without any extra field
+ caused problems; the default setting of the extra field
+ was not set back to 'unknown' properly.
+
+3) FIX: {zip} Archive filename with invalid characters like '/' gets
+ renamed. However, I do not check the complete path - needs
+ some more work here.
+
+4) FIX: {zip} Filename match was case sensitive.
+
+6) CHG: {zip} switch to latest source level
+ unzip 2.30m beta release
+
+7) CHG: {unzip} switch to latest source level
+ unzip 5.41b beta release
+
+8) FIX: {zip/unzip 68k only) I have found a wrong compiler setting
+ for the 68k version. Because of this wrong setting the 68k
+ version crashed.
+
+
+
+
+Release MacZip ver1.04 beta 1
+30. March 1999
+--------------
+
+1) CHG: {unzip) switch to latest source level
+ unzip 5.41a beta release
+
+2) ADD: {all} Added message logging support for Syslogd
+ by Brian Bergstrand. Syslogd can be found at
+ http://www.classicalguitar.net/brian/apps/syslogd/
+ This feature is 'under construction'.
+
+3) FIX: {all} many small fixes and code cleanups
+
+
+
+
+Release MacZip ver1.03
+27. March 1999
+--------------
+
+1) CHG: {console} Like Stuffit Expander MacZip quits automatically when
+ used with drag'n drop or as Helper App (Web-Browser).
+
+2) CHG: {console} Since Macintosh users are used to be guided by their
+ software in order not to do something stupid, I added a check
+ to post an extra warning if the options -m and data fork only
+ are both checked.
+ This behavior can be disabled: See Applescript example and
+ "maczip.env".
+
+3) CHG: {zip} switch from immediate deletion to moving to the
+ trash. Immediate deletion is now an option in "maczip.env".
+
+4) CHG: {zip} enhanced progress display.
+
+5) CHG: {zip) switch to latest source level
+ zip 2.3l beta release
+
+6) CHG: {unzip} The zip archive contains file names greater than
+ 31 characters. When MacZip tries to unzip the file, the
+ FSpCreate command fails because the filename length is to
+ long. MacZip correct this problem by trying to truncate
+ the file names to the 31 character limit.
+
+7) FIX: {zip/console} A couple of minor fixes
+
+8) CHG: {zip} Switched file-globbing to the Info-ZIP version.
+
+
+
+
+Release MacZip ver1.02
+14. February 1999
+-----------------
+
+1) CHG: {zip} Changed the rule of file inclusion if switch '-X'
+ is set. Following conditions are checked:
+ a) if length of resource-fork is equal zero *and* the
+ length of data-fork is equal zero include the file.
+ b) if length of resource-fork greater zero *and* the
+ length of data-fork is equal zero don't include the file.
+ c) if length of data-fork greater zero include the file.
+
+2) CHG: {Console} Some users are very confused by the buttons "START PATH"
+ and "ZIP ARCHIVE". Somehow, it wasn't clear what the intended
+ meaning was. I changed the buttons to more clear labels on
+ them like: "file or folder to compress" and "location of
+ compressed file"
+
+3) CHG: {Console} I changed the menu structure to be more intuitive.
+
+4) FIX: {Console} Found a nasty bug which sometimes caused crashes
+ when the Zip / Unzip Dialogbox was used.
+
+5) CHG: {Console} Handling of file dialog is now a bit more restricted:
+ e.g: it's not possible to select a file if you have to select
+ a folder.
+
+
+
+
+Release MacZip ver1.01
+30. January 1999
+----------------------
+
+1) CHG: {console} The use of the "Current App" mechanism was clumsy
+ and forces the user into the Zip or Unzip modes. This kind
+ of modality is not so good for the command line. It's now
+ neccessary to enter zip or unzip to choose the action.
+
+2) FIX: {console} When Applescript sends quit to MacZip the script
+ that is running shows a spinning cursor and MacZip
+ does not quit.
+
+3) FIX: {console} MacZip gots accidentally the wrong creator code
+ (from BBedit)
+
+
+
+
+Final Release MacZip ver1.0
+---------------------------
+
+Released 21. January 1999
+
+
+
+
+9. Beta release 06.December.1998
+---------------------------------
+
+1) CHG: {console} The checkbox of Filedialog (for extract path and file path)
+ "Show all files" is now selected by default.
+
+2) CHG: {unzip/standalone} changed prototypes of mac[f]printf() to return
+ an int number (better ANSI conformance);
+
+3) FIX: {unzip} repaired "stdout/stderr" mode of macwrite(). So func
+ MacMessagePrnt() is now obsolete and removed.
+
+4) ADD: {zip/unzip} Compressed Mac3 extra-fields are now supported
+ (Thanks to Christian Spieler)
+
+5) ADD: {unzip} Extraction of ZipIt archive are now supported. This support
+ is not complete: Filenames are correct but folder names are only
+ restored with the public directory names.
+
+6) ADD: {zip/unzip} Improved documentation.
+
+7) FIX: {unzip} Function isZipfile() is completely rewritten.
+
+8) CHG: {zip/unzip) switch to latest source level
+ zip 2.3i beta and unzip 5.4 final release
+
+9) ADD: Applescript event "do_cmd".
+
+Unless there are big bugs found, this release will be the last
+beta release. The final release will come out in January 1999.
+
+
+
+
+8. Beta release 20.November.1998
+---------------------------------
+
+1) CHG: {zip/unzip) switch to latest source level
+ zip 2.3h beta and unzip 5.4 final release
+
+2) ADD: {zip} Zip finds "namelocked" files also, if switch "-S"
+ is set.
+
+3) FIX: {unzip} Function isZipfile() fails if the zip archive
+ has a comment.
+
+4) CHG: {zip} added some small speed improvements to pattern matching and
+ isZipFile() function.
+
+5) FIX: {unzip} Display of comments is fixed.
+ UzpMessagePrnt() is replaced by MacMessagePrnt(). I do not care
+ about ansi-bombs. I'm not sure, so this fix may be changed later.
+
+6) RMV: {unzip} Buildin More capability is removed since it's already built
+ into the GUI-App.
+
+
+
+7. Beta release 09.November.1998
+---------------------------------
+
+1) CHG: {all} switched to Metrowerks Codewarrior Pro 4
+
+2) FIX: {unzip} Display of comments stored in the zip-file is
+ now fixed
+
+3) FIX: {zip} Fixed display of the zip help-screen.
+
+4) CHG: {zip/unzip} Changed special dir 'Re$0urce.Fk' to 'XtraStuf.mac'
+ (see entry at 13.June.1998 item 3). I found it more descriptive for
+ users outside the mac-community.
+
+5) CHG: {all} switched to MoreFiles 1.4.9.
+
+6) CHG: {console} changed behaivor of the file open dialog: The select
+ button is now always enabled.
+
+7) ADD: {all} Environment variables are now supported.
+ Basically, it is possible to add timezone (= TZ environment variable)
+ support here, but it's not yet implemented.
+ See "MacZip.Env" for further info.
+
+8) RMV: {console} Targets "zip only" and "unzip only" are removed.
+
+
+
+6. Beta release 09.September.1998
+---------------------------------
+
+
+1) CHG: {Zip/Unzip} Metrowerks Standardlibrary time funktions are
+ rather broken and incomplete so I was forced to rewrite the
+ funktions: mktime(), localtime(), gmtime() and time().
+
+2) ADD: {Console} Added Pause Funktion for screen output.
+ The Pause-Function is selfadjusting: Count of lines is depending
+ on the window size.
+
+3) CHG: Extra-Field layout is changed: All datas are now in little-endian
+ format (see appnote)
+
+4) ADD: {Console} Added an option to test the archive automatically
+ after zipping. This option is only via Zip-Dialogbox available
+ because it needs the unzip-module also.
+
+5) CHG: {Zip} code is now up to date with the latest beta 2.3f.
+
+6) ADD: {Console} Added (drag'n) drop support. Drop on the MacZip icon.
+ The following situations are supported:
+ 1. drop of one or more zipfiles (action = unzip)
+ each archive will be extracted in a separate folder
+ 2. drop of a folder (action = zip -r )
+ The complete folder (inclusive sub-folders)
+ will be zipped
+ Not (yet) supported is currently: dropping more than one file
+ to compress. Workaround: Put all your files in one folder and
+ drop that folder on MacZip.
+ MacZip recognize zip-archives automatically.
+
+
+5. Beta release 21.Aug.1998
+----------------------------
+
+
+1) ADD: {Console} Userinterface has now a Statusbar to show the
+ Progress.
+
+2) ADD: {Console} It's now possible to stop the run of Zip/Unzip
+ with the well known shortcut [Command] + [.]
+
+3) CHG: {Console} Improved user-entry routine.
+
+4) ADD: {Zip/Unzip} Crypt-code added. It's now possible to
+ encrypt/decrypt archives.
+
+5) RMV: {Unzip} Removed the warning of PKZip/Mac archive.
+ Unzip gets confused with the extra field of PKZip/Mac. So I assume
+ the extra field isn't compatible with Info-ZIP's definition.
+
+6) CHG: switched to Metrowerks Codewarrior Pro 3
+ this includes:
+ - new Universal Interfaces 3.1 Headers
+ - improved codegeneration
+
+7) CHG: {Zip} code is now up to date with the latest beta 2.3e.
+
+8) CHG: {Unzip} changed function names wprintf, wgets .. to macprintf, macgets ..
+ to avoid naming conflict standart library.
+
+9) ADD: {Zip/Unzip} FXinfo, Mac-Pathname, file-dates and Finder-Comments
+ are now stored in the extra-field. Extra-field layout is
+ changed accordingly. Unzip uses now the filename stored in the
+ extra-field when unzipping.
+
+10) CHG: {Unzip} code is now up to date with the latest beta 5.33g.
+
+11) CHG: {Unzip} code is (again) up to date with the latest beta 5.33h.
+
+12) ADD: {Unzip} following switches were added:
+ -J [MacOS only] ignore mac extra info. All macintosh
+ info are not restored. Datafork and resource-fork
+ are restored separatly.
+
+ -i [MacOS only] ignore filenames stored in mac extra
+ field. Use the most compatible filename stored in
+ the public field.
+
+ -E [MacOS only] show mac extra field during restoring
+
+13) ADD: {Zip/Unzip} Charset MacRoman to ISO8859 Latin and vice versa
+
+14) RMV: {Zip} -N option removed. This MacZip crashes using this option.
+ I will fix it later.
+
+
+I think I'm very close for a final release of "MacZip 1.0" :-)
+
+
+
+4. Beta release 27.June.1998
+----------------------------
+
+26.June.1998
+------------
+
+1) FIX: {Zip} extra field size value was wrong.
+
+
+
+25.June.1998
+------------
+
+1) CHG: {Zip} code is now up to date with the latest beta 2.3d.
+ So both modules, zip & unzip, uses now latest beta.
+
+2) ADD: {Zip} added a UT extra-field for better compatibility.
+
+3) CHG: {Unzip} changed the code to find the mac extra-field.
+ Unzip has to look for a mac extra-field because
+ mac-archives has now two extra-fields (UT + M3).
+
+4) CHG: {Unzip} changed the method to move extra-field data to
+ the internal extra-structure.
+ Old method was just BlockMove of the ef_structptr to ef_memptr.
+ This method was dangerous because not all members of the
+ structure seamless aligned. There are may be some fill
+ bytes in the structure depending on the compiler setting.
+
+5) ADD: {Unzip} added a warning if unzipping a ZipIt/PKZip archive.
+ ZipIt/PKZip archives are usually additionally coded somehow.
+ InfoZip's Unzip will *not* decode the files. So extracted
+ files are may be not decoded. (see also 6. and 7.)
+
+6) ADD: ZipIt (the Shareware Tool) has now a new extra-field signature:
+ 0x2705. Found in "ZipIt 1.3.8". I added a new macro: EF_ZIPIT2
+
+7) ADD: Added PKWare's extra-field signature: 0xCF77.
+ Found in "PKZIP v2.03". I added a new macro: EF_PKMAC
+
+8) ADD: {console} It's now possible to save all screen outputs
+ to the disk.
+
+9) RMV: {console} this is the first beta without expire-date.
+
+
+16.June.1998
+------------
+
+1) FIX: {Unzip/console} Extract path now defaults to current-dir if
+ no path is given.
+
+2> CHG: {Unzip} creates now a extract-folder by default. This behavior
+ differs to the commandline tool of Unzip on other platforms.
+ However, for a mac-user is this behavior more convenient.
+
+
+3. Beta release 15.June.1998
+----------------------------
+
+15.June.1998
+------------
+
+1) CHG: {unzip/zip} I changed the layout of the extra field
+ to support more data.
+
+
+14.June.1998
+------------
+
+1) FIX: {Unzip} adjusted time_t value with an correct offset value.
+
+2) FIX: {Unzip} removed all unused code based on unfinished ideas by
+ former porter(s).
+
+3) CHG: use of shared code izshr 032.
+
+13.June.1998
+------------
+
+1) FIX: {Unzip} Filenames are only converted when needed. When zipping
+ with the switch 'datafork only' the filenames are shorted which
+ was wrong.
+
+2) CHG: {Unzip} code is now up to date with the latest beta 5.33f.
+
+3) CHG: {Zip} Changed the naming rule of filenames from old Johnny Lee's
+ to my implementation. Johnny Lee's idea is based on change of the
+ filenames which cases several problems when unziping on a non mac
+ plattform. My idea is to add a special directory: 'Re$0urce.Fk'.
+ For the future: Zip will create archives according the new nameing
+ rule. However unzip will be compatible with old nameing rule.
+ See also 4.
+
+4} ADD: {Unzip} Added a new nameing rule for resource forks filename.
+ Resource forks are now stored in a special directory: 'Re$0urce.Fk'.
+ This naming rule make it easier to for other platforms to use
+ mac zip-files.
+
+
+
+11.June.1998
+------------
+1) FIX: {Zip} Internal file attribute is set to BINARY by default
+ when zipping resource forks otherwise Unzip will create
+ sometimes wrong resource-forks.
+
+2) CHG: {Unzip} code is now up to date with the latest beta 5.33e.
+
+
+
+
+2. Beta release 10.June.1998
+--------------------------
+
+1) FIX: {Unzip} Long pathname fix solved. Unzip is now able to extract
+ archives with path longer than 256 chars.
+
+2) CHG: {Unzip} removed all conversion from c-style string to
+ pascal-string (see fix 1)
+
+3) ADD: {Unzip} Finderinfo of folders are also restored.
+
+4) ADD: {Console} Added info about current path in the command-line box.
+
+5) FIX: {Console} Construction of the command-line of the unzip-dialog
+ box fixed.
+
+
+
+First beta release 06.June.1998
+-----------------------------
+
+no history.
+Just to many code was neccessary to build the first mac-port.
+
+
+Start of the port MacZip
+February 1998
+
+
+--------------------------------------------------------------------------------
+Legende:
+
+FIX: fixes a bug
+CHG: inform about changed items.
+ADD: added feature
+RMV: removed Item
+
+{Unzip} -> only related to the Unzip-module
+{Zip} -> only related to the Zip-module
+ These are just libraries and are linked into the console-app.
+
+{Console} -> only related to the Userinterface (not SIOUX)
+ MacOS has no tool like a command-line. So it's neccessary
+ to write wrapper around the command-line tools.
+
+
+
+
+Dirk Haase
diff --git a/macos/README.TXT b/macos/README.TXT
new file mode 100644
index 0000000..839658d
--- /dev/null
+++ b/macos/README.TXT
@@ -0,0 +1,569 @@
+A free Macintosh Port of Info-ZIP's
+Zip and UnZip
+By Dirk Haase, d_haase@sitec.net
+Home page: www.sitec.net/maczip
+Mirror page:
+www.haase-online.de/dirk/maczip
+================================
+
+
+
+Abstract:
+---------
+MacZip is a cross-platform compatible tool that includes
+both Zip (for compression) and UnZip (for extraction).
+
+Zip is a compression and file packaging utility for Unix,
+VMS, MSDOS, OS/2, Windows 9x, Windows NT, Atari, Macintosh,
+Amiga, Acorn RISC OS, and other systems.
+
+UnZip unpacks zip archives. The Zip and UnZip programs can
+process archives produced by PKZIP, and PKZIP and PKUNZIP
+can work with archives produced by zip. Zip version 2.2 is
+compatible with PKZIP 2.04.
+
+If you are new to MacZip please read first the file
+"ReadMe.1st".
+
+
+
+License:
+--------
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in unzip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+
+
+
+Requirements
+------------
+MacZip requires at least System 7 and a Macintosh with a
+minimum of a Motorola 68020 or PowerPC 601 processor. Other
+configurations may work but it is not tested at all.
+
+The application is distributed as a fat binary with both
+regular 68K and native PowerPC versions included.
+
+
+
+Installation
+------------
+Move the executable(s) somewhere--for example, drag it (or
+them) to your Applications folder. For easy access, make an
+alias in the Launcher Control Panel or directly on your
+desktop. The GUI is very simple. It was not my intention to
+make a full-blown GUI, however I think it is comfortable
+enough to use it as regular tool.
+
+This port supports also Apple-event. So you can install it
+in your WWW-Browser as a helper app.
+
+For more Info about the contents of this package, take a
+look into the "macos/Contents" (or :macos:Contents) file.
+Some notes on how to rebuild the Macintosh applications can
+be found in INSTALL.
+
+
+
+Usage:
+------
+
+Basically there are four ways to start MacZip:
+
+a) Drag'n Drop
+b) using the Dialog box (Menu: File -> Zip/Unzip):
+
+Please read the file "ReadMe.1st"
+for the description of the items a and b.
+
+c) Using the Command line (Menu: File->Command Line):
+ The Zip & UnZip tools are command line tools. So the
+ behavior is exactly the same like the Zip & UnZip tools on
+ Unix or Windows/DOS. This means, if you want to zip some
+ files, you have to write a command line like this: "zip
+ [switches] path_to_zip_archive path_to_files_folders"
+
+ - Go to "File", select "Command Line" and the
+ "MacZip Entry box" Dialog Box appears.
+
+ An example:
+
+ a: your zip may be created at
+ Macintosh HD:applications:archive.zip
+
+ b: your files may be found at
+ Macintosh HD:somewhere:my_folder_to_archive:*
+
+ Note: At the end of the path there must be a filename or
+ a wild card !
+ (see Footnotes: 1 wild card, 2 Mac path names)
+
+ So the command line should look like (one line!):
+
+ zip "Macintosh HD:applications:archive.zip" "Macintosh HD:somewhere:my_folder_to_archive:*"
+
+ - Click on "Enter" to start the task.
+
+ Since you can not set a default folder you have to enter
+ always a full qualified path names. Full-qualified path
+ names are path names including the Volume name ! (see
+ Footnote: 2 Mac path names)
+
+
+
+d) Using Applescript:
+
+There is only one additional event defined: "do_cmd". You
+can enter every valid command line. The first word must be
+"zip" or "unzip" to select the action (compress or
+extraction).
+
+See sample Applescript:
+
+ tell application "MacZip (PPC)"
+ activate
+ with timeout of 90000 seconds
+ do_cmd "zip -rjjN Volume:archive \"My Volume:*\" "
+ end timeout
+ end tell
+
+This script opens MacZip, brings it to the foreground on the
+Mac, starts the zip action with the command line: zip -rjjN
+Volume:archive "My Volume:*" .
+
+
+A short introduction is also available online:
+http://www.sitec.net/maczip/How-To-Do/
+
+It's possible to stop the run of Zip/Unzip with the well
+known shortcut [Command] + [.].
+
+
+---------------------------------------------------------------------------
+
+There are some Mac-specific switches available.
+Zip Module:
+ -df [MacOS] Include only data-fork of files zipped into
+ the archive. Good for exporting files to foreign
+ operating-systems. Resource-forks will be ignored
+ at all.
+
+ -jj [MacOS] record Fullpath (+ Volname). The complete
+ path including volume will be stored. By default
+ the relative path will be stored.
+
+ -S [MSDOS, OS/2, WIN32 and ATARI] Include system and
+ hidden files.
+ [MacOS] Includes finder invisible files, which are
+ ignored otherwise.
+
+Unzip Module:
+ -E [MacOS only] display contents of MacOS extra field
+ during restore operation.
+
+ -i [MacOS only] ignore filenames stored in MacOS extra
+ fields. Instead, the most compatible filename
+ stored in the generic part of the entry's header is
+ used.
+
+ -J [MacOS only] ignore MacOS extra fields. All Macin-
+ tosh specific info is skipped. Data-fork and
+ resource-fork are restored as separate files.
+
+
+Select [File]->[Get Help on Zip/Unzip] for a complete list
+of switches.
+
+
+
+Limitations / Problems:
+-----------------------
+
+ - Aliases are not supported. I tried, but I got broken
+ aliases. This port will silently ignore all aliases.
+ It's on my to-do list for future releases.
+
+ - Zip needs much memory to compress many files: You may need
+ to increase the 'Preferred Size' in 'Get Info'. Values of 12
+ Megabytes or more are possible
+
+ - Unzip needs about 500 Kbytes of memory to unzip no matter
+ how many files were compressed and expanded.
+
+ - and finally one big macintosh-related problem:
+ This port has one weak point: It's based on path names.
+ As you may be already know: Path names are not unique on a Mac !
+ The main reason is that an attempt to implement support exact
+ saving of the MacOS specific internal file structures would
+ require a throughout rewrite of major parts of shared code,
+ probably sacrifying compatibility with other systems. I have
+ no solution at the moment. The port will just warn you if you
+ try zip from / to a volume which has a duplicate name.
+ MacZip has problems to find the archive or the files. My
+ (Big) recommendation: Name all your volumes with a unique
+ name and MacZip will run without any problem.
+
+
+Known Bugs:
+
+ - crypted files in a zip archive are sometimes corrupt:
+ I get an error message: invalid compressed data to inflate.
+ Appearance of this error is purely be chance: I did a small
+ test: Unzipping an archive containing 3589 files 56 files
+ fails to unzip, so about 1.5%. Root cause is completely
+ unclear to me :(
+
+I strongly recommend to test your archive (e.g. unzip -t archive).
+
+
+
+
+
+Zip Programs / Macintosh Extra-Data:
+-----------------------------------------
+A brief overview:
+Currently, as far as I know, there are 6 Zip programs
+available for the Macintosh platform. These programs build
+(of course) different variants of Zip files:
+
+ - Info-ZIP's first Port of Zip. Ported by Johnny Lee
+ This port is rather outdated and no longer supported (since 1992).
+ 68K only. Only minimal Mac-info is stored
+ (Creator/Type, Finder attributes). Creator/Type: '????' / '????'
+ Until year 1998, only UnZip 5.32 survived.
+
+ - ZipIt by Tom Brown. This is Shareware and still supported I think.
+ ZipIt has a nice GUI, but I found it can't handle large Zip files
+ quite well. ZipIt compresses Macintosh files using the Mac Binary
+ format. So, transferring files to other platforms is not so easy.
+ Only minimal Mac-info is stored (Creator/Type, Finder attributes).
+ Mac filenames are changed to a most compatible filename.
+ Creator/Type: 'ZIP ' / 'ZIP '
+
+ - PKZIP/mac v2.03/210d. This is Shareware.
+ This Zip implementation for the Mac can be found on ASI's web site
+ (http://www.asizip.com/products/products.htm). The name of this
+ program is misleading, it is NOT a product from PKWARE. ASI's last
+ release version is v2.03, and they also offer a newer beta version
+ PKZIP/mac 210d. But even the Beta version is rather outdated (1995).
+ Only minimal Mac-info is stored (Creator/Type, Finder attributes).
+ The Zipfile format looks like incompatible to other platforms.
+ (More details about the compatibility issue can be found in
+ proginfo/3rdparty.bug!). Type: 'PKz1'
+ Mac filenames are restored without any change.
+
+ - Aladdin DropZip 1999, This is Shareware. Aladdin chose
+ the format of ZipIt. Therefore, it has the some drawbacks
+ like ZipIt.
+ Creator/Type: 'SITx' / 'ZIP '
+
+ - SmartZip 1.0 1999 - by Marco Bambini Vampire Software.
+ This is Shareware. SmartZip compresses Macintosh files using the
+ Mac Binary. Therefore, it has the same drawbacks like ZipIt.
+ Creator/Type: 'dZIP' / 'ZIP '
+
+and finally:
+ - Info-ZIP's latest Port of Zip. MacZip 1.0. Ported by me :-)
+ It is supported (of course) and up to date. Full set of macintosh
+ info is stored: Creator/Type, Finder attributes, Finder comments,
+ MacOS 8.0 Folder settings, Icon/Folder Positions ...
+ Mac filenames are restored without any change.
+ Creator/Type: 'IZip' / 'ZIP '
+
+
+Compatibility of my port; Extraction:
+ - Archives from Info-ZIP's first port (by Johnny Lee) are
+ still compatible.
+ - Extraction of ZipIt archives is supported. This support
+ is not complete: Filenames are correct but Directory names
+ are sometimes mangled to a DOS compatible form. Segmented
+ archives are not supported.
+ - PKZiP/mac archive files are extracted without resource-forks
+ and without any Finder info. I have no information about
+ that zip format.
+
+Compatibility of my port; Compression:
+ - My port supports only the new Info-ZIP format (introduced
+ with this port). Therefore archives created by MacZip 1.0
+ (March 1999) must be extracted with this version or later
+ releases of Info-ZIP's UnZip to restore the complete set of
+ Macintosh attributes.
+
+Note: This port is complete unrelated to the shareware ZipIt.
+Even more, handling of special Macintosh attributes is
+incompatible with ZipIt. This port (MacZip) may be used to
+extract archives created by ZipIt, but make sure that you
+get the result as you expected.
+
+
+
+Macintosh Files; File Forks:
+----------------------------
+
+All Macintosh files comprise two forks, known as the data
+fork and the resource fork. Unlike the bytes stored in the
+resource fork, the bytes in the data fork do not have to
+exhibit any particular internal structure. The application
+is responsible for interpreting the bytes in the data fork
+in whatever manner is appropriate. The bytes in the resource
+fork usually have a defined internal structure and contain
+data object like menus, dialog boxes, icons and pictures.
+Although all Macintosh files contain both a data fork and a
+resource fork, one or both of these forks may be empty.
+
+MacZip stores data-forks and resource-forks separately. The
+Zipfile format does not allow to store two archive entries
+using exactly the same name. My solution is to modify the
+Path name of the resource-fork. All resource-fork names are
+prepended with a leading special directory named
+"XtraStuf.mac". So, when extracting on a Mac, you should
+never see this directory "XtraStuf.mac" on your *disk*.
+
+On all foreign systems that support directories in filenames
+(e.g.: OS/2, Unix, DOS/Windows, VMS) you will get a
+directory "XtraStuf.mac" when extracting MacZip archives.
+You can delete the complete directory "XtraStuf.mac" since
+Mac resources do not make much sense outside the MacOS
+world.
+
+
+
+Text encoding; Charsets of the Filenames:
+-----------------------------------------
+
+The following information is only important if you plan to
+transfer archives across different platforms/language systems:
+
+A typical Zip archive does not support different charsets.
+All filenames stored in the public area (= accessible by
+foreign systems other than MacOS) must be coded in the
+charset ISO-8859-1 (CP1252 in the Microsoft Windows world)
+or CP850 (DOSLatin1). The latter should only be used by Zip
+programs that mark the archive entries as "created under
+DOS". Apart from Macs, the commonly used platforms either
+support ISO-8859-1 directly, or are compatible with it. To
+achieve maximum compatibility, MacZip convert filenames from
+the Mac OS Roman character set to ISO-8859-1 and vice versa.
+But not every char of the charset MacRoman has their
+equivalent in ISO-8859-1. To make the mapping in most cases
+possible, I chose most similar chars or at least the MIDDLE
+DOT.
+
+Mac OS Roman character set is used for at least the
+following Mac OS localizations: U.S., British, Canadian
+French, French, Swiss French, German, Swiss German, Italian,
+Swiss Italian, Dutch, Swedish, Norwegian, Danish, Finnish,
+Spanish, Catalan, Portuguese, Brazilian, and the default
+International system.
+
+In all Mac OS encodings, character codes 0x00-0x7F are
+identical to ASCII, except that
+ - in Mac OS Japanese, yen sign replaces reverse solidus
+ - in Mac OS Arabic, Farsi, and Hebrew, some of the
+ punctuation in this range is treated as having strong
+ left-right directionality, although the corresponding
+ Unicode characters have neutral directionality
+So, for best compatibility, confine filenames to the standard
+7-bit ASCII character set.
+
+If you generate a filename list of your archive (unzip -l),
+you will see the converted filenames. Your can also extract
+the archive with the switch '-i' (= ignore mac filenames),
+and test your result.
+
+This MacZip port uses its own filename stored in the
+archive. At the moment, the filename will be not converted.
+However, I'm planning to add support for Unicode.
+
+Currently, the following Mac OS encodings are NOT supported:
+Japanese, ChineseTrad, Korean, Arabic, Hebrew, Greek,
+Cyrillic, Devanagari, Gurmukhi, Gujarati, Oriya, Bengali,
+Tamil, Telugu Kannada, Malayalam, Sinhalese, Burmese, Khmer,
+Thai, Laotian, Georgian, Armenian, ChineseSimp, Tibetan,
+Mongolian, Ethiopic, Vietnamese, ExtArabic and finally:
+Symbol - this is the encoding for the font named "Symbol".
+Dingbats - this is the encoding for the font named "Zapf Dingbats".
+If you extract an archive coded with one of these
+charsets you will probably get filenames with funny
+characters.
+
+These problems apply only to filenames and NOT to the file
+content.
+of course: The content of the files will NEVER be converted !!
+
+
+
+File-/Creator Type:
+-------------
+
+This port uses the creator type 'IZip' and it is registered
+at Apple (since 08. March 1998). File types can not be
+registered any more. This port uses 'ZIP ' for Zip archive
+files. The creator 'IZip' type should be used for all future
+versions of MacZip.
+
+
+
+Hints for proper restoration of file-time stamps:
+-------------------------------------------------
+
+UnZip requires the host computer to have proper time zone
+information in order to handle certain tasks correctly (see
+unzip.txt). To set the time zone on the Macintosh, go to
+the Map Control Panel and enter the correct number of hours
+(and, in a few locales, minutes) offset from Universal
+Time/Greenwich Mean Time. For example, the US Pacific time
+zone is -8 hours from UTC/GMT during standard (winter) time
+and -7 hours from UTC/GMT during Daylight Savings Time. The
+US Eastern time zone is -5 hours during the winter and -4
+hours during the summer.
+
+Discussion of Daylight Savings Time
+-----------------------------------
+The setting in the Date & Time control panel for Daylight
+Savings time is a universal setting. That is, it assumes
+everybody in the world is observing Daylight Savings time
+when its check box is selected.
+
+If other areas of the world are not observing Daylight
+Savings time when the check box is selected in the Date &
+Time control panel, then the Map control panel will be off
+by an hour for all areas that are not recognizing Daylight
+Savings time.
+
+Conversely, if you set the Map control panel to an area that
+does not observe Daylight Savings time and deselect/uncheck
+the check box for Daylight Savings time in the Date & Time
+control panel, then time in all areas celebrating Daylight
+Savings time will be off by an hour in the Map control
+panel.
+
+Example:
+ In the case of Hawaiians, sometimes they are three hours
+ behind Pacific Standard Time (PST) and sometimes two hours
+ behind Pacific Daylight Time (PDT). The Map control panel
+ can only calculate differences between time zones relative
+ to Greenwich Mean Time (GMT). Hawaii will always show up as
+ three hours past the Pacific time zone and five hours past
+ the Central time zone.
+
+ When Hawaiians are not observing Daylight Savings time, but
+ the rest of the country is, there is no combination of
+ settings in Map and Date & Time control panels which will
+ enable you to display Hawaiian local time correctly AND
+ concurrently display the correct time in other places that
+ do observe Daylight Savings time.
+
+ The knowledge about which countries observe Daylight Savings
+ time and which do not is not built into the Map control
+ panel, so it does not allow for such a complex calculation.
+
+ This same situation also occurs in other parts of the world
+ besides Hawaii. Phoenix, Arizona is an example of an area of
+ the U.S. which also does not observe Daylight Savings time.
+
+Conclusion:
+MacZip only knows the GMT and DST offsets of the
+current time, not for the time in question.
+
+
+Projects & Packages:
+--------------------
+
+A Note to version numbers: Version of MacZip is currently
+1.06 and is based on the zip code version 2.3 and unzip code
+version 5.42. See About Box for current version and compiler
+build date.
+
+Because of the amount of sources I splitted this port into
+several projects. See http://www.sitec.net/maczip for
+updates.
+
+- core source parts:
+ unzxxx.zip
+ zipxxx.zip
+ These archives contains the main parts of the port. You can
+ build libraries and a standalone App with Metrowerks
+ standard console SIOUX. They contain only sources, no
+ executables. These archives are exact copies of the standard
+ Info-ZIP source distributions; they were only repackaged
+ under MacOS using MacZip, with one minor addition: For those
+ files that are stored in BinHex'ed format in the Info-ZIP
+ reference source archives, unpacked version that are ready
+ for use have been added.
+
+- additional source part:
+ MacZipxxx.zip: contains all the GUI stuff and the project
+ files to build the main-app. Only sources of the GUI, no
+ zip or unzip code. To build MacZip successfully you will
+ need to also download the zip and unzip packages.
+
+- executables:
+ MacZipxxxnc.hqx: contains only executables and 'README.TXT',
+ This version is without en-/decryption support !
+ MacZipxxxc.hqx: contains only executables and 'README.TXT',
+ This version supports en-/decryption !
+
+- encryption sources:
+ zcryptxx.zip: To build crypt versions of MacZip.
+ download from ftp://ftp.icce.rug.nl/infozip/ (and subdirectories)
+
+- documentation:
+ MacZipDocu.zip: contains some further docus about the algorithm,
+ limits, Info-ZIP's appnote and a How-to-do Webpage.
+
+
+Credits:
+--------
+
+Macstuff.c and recurse.c: All the functions are from More Files.
+More Files fixes many of the broken or underfunctional parts of
+the file system. Thanks to Jim Luther. (see morefiles.doc)
+
+
+
+
+---------------------------------------------------------------------------
+Footnotes:
+
+1. wild card:
+ The '*' is a wild card and means 'all files'
+ Just in case you don't know wild cards:
+ '*' is a place holder for any character.
+ e.g.:
+ "this*" matches with "this_file" or "this_textfile" but it
+ doesn't match with "only_this_file" or "first_this_textfile"
+ "*this*" matches with "this_file" or "this_textfile" AND
+ matches with "only_this_file" or "first_this_textfile"
+
+
+2. Mac pathnames:
+The following characteristics of Macintosh pathnames should
+be noted:
+
+ A full pathname never begins with a colon, but must contain
+ at least one colon.
+ A partial pathname always begins with a colon separator except
+ in the case where the file partial pathname is a simple file or
+ directory name.
+ Single trailing separator colons in full or partial pathnames
+ are ignored except in the case of full pathnames to volumes.
+ In full pathnames to volumes, the trailing separator colon is
+ required.
+ Consecutive separator colons can be used to ascend a level
+ from a directory to its parent directory. Two consecutive
+ separator colons will ascend one level, three consecutive
+ separator colons will ascend two levels, and so on. Ascending
+ can only occur from a directory; not a file.
+
+
+
+
+
+---------------------------------------------------------------------------
+
+Dirk Haase
+==========
diff --git a/macos/ZipLib.h b/macos/ZipLib.h
new file mode 100644
index 0000000..e3dacf3
--- /dev/null
+++ b/macos/ZipLib.h
@@ -0,0 +1,166 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ ZipLib.h
+
+ This header-files is global to the project ZipLib.
+
+ ---------------------------------------------------------------------------*/
+
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+#define MACOS
+#define MACZIP
+
+#define OLDROUTINENAMES 0 /* use new function names only */
+#define OLDROUTINELOCATIONS 0 /* use new headerlocations only */
+#define SystemSevenOrLater 1 /* Runs only on System 7.0 or later */
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c) */
+#undef getc
+#undef getchar
+#undef putchar
+#undef putc
+
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+#define NAME_MAX 1024
+
+
+/*****************************************************************************/
+/* Includes standard headers */
+/*****************************************************************************/
+#include <ansi_prefix.mac.h>
+#include <stdio.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Aliases.h>
+#include <Resources.h>
+#include <Gestalt.h>
+#include <Traps.h>
+#include <Processes.h>
+#include <MacWindows.h>
+
+
+/* Many things are different for mac-users, so we need
+ special mac functions :-) */
+int Zmacstat (const char *path, struct stat *buf);
+#define stat(path, bufPtr) Zmacstat(path, bufPtr)
+#define lstat(path, bufPtr) Zmacstat(path, bufPtr)
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+
+
+
+/*
+#define MAC_DEBUG 1
+#define DEBUG 1
+ */
+
+
+#ifdef MAC_DEBUG
+#define LOG_DEBUG 7 /* debug-level messages */
+int Print2Syslog(UInt8 priority, const char *format, ...);
+#include <ctype.h>
+
+
+#define Notify(msg) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG, "%s (file: %s line: %d)", \
+ msg, __FILE__, __LINE__); \
+ }
+
+
+
+
+#define Assert_it(cond,msg,kind) \
+ { \
+ if (!(cond)) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG,"%s failed: [%s] cond: [%s] (file: %s line: %d)", \
+ kind, msg, #cond, __FILE__, __LINE__); \
+ } \
+ }
+
+
+
+
+
+#define AssertBool(b,msg) Assert_it (((b) == TRUE) || ((b) == FALSE),(msg),("AssertBool "))
+
+
+
+#define AssertStr(s,msg) \
+ { \
+ int s_i = 0; \
+ Assert_it ((s),(msg),("1. AssertStr ")); \
+ while ((s)[s_i]) { \
+ Assert_it ((!iscntrl((s)[s_i]) || ((s)[s_i] == 0x0A) || \
+ ((s)[s_i] == 0x0D)),(s),("2. AssertStr ")); \
+ s_i++; \
+ } \
+ }
+
+
+
+#define AssertTime(t,msg) Assert_it (((t).tm_sec >= 0) && ((t).tm_sec < 62) && \
+ ((t).tm_min >= 0) && ((t).tm_min < 60) && \
+ ((t).tm_hour >= 0) && ((t).tm_hour < 24) && \
+ ((t).tm_mday >= 1) && ((t).tm_mday < 32) && \
+ ((t).tm_mon >= 0) && ((t).tm_mon < 12) && \
+ ((t).tm_wday >= 0) && ((t).tm_wday < 7) && \
+ ((t).tm_yday >= 0) && ((t).tm_yday < 366),(msg),("AssertStr "))
+
+
+
+#define AssertIntRange(myvalue,minimum,maximum, msg) Assert_it ( \
+ ((myvalue) >= (minimum)) && ((myvalue) <= (maximum)), msg,("AssertIntRange "))
+
+
+
+
+#define AssertStrNoOverlap(str1,str2,msg) \
+ { \
+ long s_i = 0; \
+ AssertStr((str1),(msg)) \
+ AssertStr((str2),(msg)) \
+ if ((str1) < (str2)) \
+ { \
+ s_i = strlen((str2)); \
+ Assert_it ( (((str1) + s_i) < (str2)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ else \
+ { \
+ s_i = strlen((str1)); \
+ Assert_it ( (((str2) + s_i) < (str1)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ } \
+
+
+
+
+#else
+#define Assert_it(cond,msg,kind)
+#define AssertBool(b,msg)
+#define AssertStr(s,msg)
+#define AssertTime(t,msg)
+#define AssertIntRange(myvalue,minimum,maximum,msg)
+#define AssertStrNoOverlap(str1,str2,msg)
+#endif
+
diff --git a/macos/ZipSx.h b/macos/ZipSx.h
new file mode 100644
index 0000000..d2b9ae8
--- /dev/null
+++ b/macos/ZipSx.h
@@ -0,0 +1,167 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ ZipSx.h
+
+ This header-files is global to the project ZipSioux.
+
+ ---------------------------------------------------------------------------*/
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+#define MACOS
+#define USE_SIOUX
+#define MACZIP
+
+#define OLDROUTINENAMES 0 /* use new function names only */
+#define OLDROUTINELOCATIONS 0 /* use new headerlocations only */
+#define SystemSevenOrLater 1 /* Runs only on System 7.0 or later */
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c) */
+#undef getc
+#undef getchar
+#undef putchar
+
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+#define NAME_MAX 1024
+
+
+/*****************************************************************************/
+/* Includes standard headers */
+/*****************************************************************************/
+#include <ansi_prefix.mac.h>
+#include <stdio.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Aliases.h>
+#include <Resources.h>
+#include <Gestalt.h>
+#include <Traps.h>
+#include <Processes.h>
+#include <MacWindows.h>
+
+
+/* Many things are different for mac-users, so we need
+ special mac functions :-) */
+int Zmacstat (const char *path, struct stat *buf);
+#define stat(path, bufPtr) Zmacstat(path, bufPtr)
+#define lstat(path, bufPtr) Zmacstat(path, bufPtr)
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+
+
+
+/*
+#define MAC_DEBUG 1
+ */
+
+
+
+
+
+
+#ifdef MAC_DEBUG
+#define LOG_DEBUG 7 /* debug-level messages */
+int Print2Syslog(UInt8 priority, const char *format, ...);
+#include <ctype.h>
+
+
+#define Notify(msg) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG, "%s (file: %s line: %d)", \
+ msg, __FILE__, __LINE__); \
+ }
+
+
+
+
+#define Assert_it(cond,msg,kind) \
+ { \
+ if (!(cond)) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG,"%s failed: [%s] cond: [%s] (file: %s line: %d)", \
+ kind, msg, #cond, __FILE__, __LINE__); \
+ } \
+ }
+
+
+
+
+#define AssertBool(b,msg) Assert_it (((b) == TRUE) || ((b) == FALSE),(msg),("AssertBool "))
+
+
+
+#define AssertStr(s,msg) \
+ { \
+ int s_i = 0; \
+ Assert_it ((s),(msg),("1. AssertStr ")); \
+ while ((s)[s_i]) { \
+ Assert_it ((!iscntrl((s)[s_i]) || ((s)[s_i] == 0x0A) || \
+ ((s)[s_i] == 0x0D)),(s),("2. AssertStr ")); \
+ s_i++; \
+ } \
+ }
+
+
+
+#define AssertTime(t,msg) Assert_it (((t).tm_sec >= 0) && ((t).tm_sec < 62) && \
+ ((t).tm_min >= 0) && ((t).tm_min < 60) && \
+ ((t).tm_hour >= 0) && ((t).tm_hour < 24) && \
+ ((t).tm_mday >= 1) && ((t).tm_mday < 32) && \
+ ((t).tm_mon >= 0) && ((t).tm_mon < 12) && \
+ ((t).tm_wday >= 0) && ((t).tm_wday < 7) && \
+ ((t).tm_yday >= 0) && ((t).tm_yday < 366),(msg),("AssertStr "))
+
+
+
+#define AssertIntRange(myvalue,minimum,maximum, msg) Assert_it ( \
+ ((myvalue) >= (minimum)) && ((myvalue) <= (maximum)), msg,("AssertIntRange "))
+
+
+
+
+#define AssertStrNoOverlap(str1,str2,msg) \
+ { \
+ long s_i = 0; \
+ AssertStr((str1),(msg)) \
+ AssertStr((str2),(msg)) \
+ if ((str1) < (str2)) \
+ { \
+ s_i = strlen((str2)); \
+ Assert_it ( (((str1) + s_i) < (str2)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ else \
+ { \
+ s_i = strlen((str1)); \
+ Assert_it ( (((str2) + s_i) < (str1)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ } \
+
+
+
+
+#else
+#define Assert_it(cond,msg,kind)
+#define AssertBool(b,msg)
+#define AssertStr(s,msg)
+#define AssertTime(t,msg)
+#define AssertIntRange(myvalue,minimum,maximum,msg)
+#define AssertStrNoOverlap(str1,str2,msg)
+#endif
+
diff --git a/macos/ZpPrj.hqx b/macos/ZpPrj.hqx
new file mode 100644
index 0000000..5bb3da0
--- /dev/null
+++ b/macos/ZpPrj.hqx
@@ -0,0 +1,455 @@
+(This file must be converted with BinHex 4.0)
+:#9T`8(*U,R0TG!"6594%8dP8)3#3"&66!*!%Ip96593K!!%!!&66FNaKG3)!N!3
+@!*!$$39DF&"bDJ#3!aEf1!,VX93!6&MU!*!$J!#3"!,cIF3NA3#3'[q3"%e08(*
+$9dP&!3b[H&ZZXklEb3#3"3,E[3#3"P40!!$hQ!#3"L8D"RMDS*NlIS6ISVG-[(8
+R+hBY21RaEd$i`XJbN!"bQK8YHRN,mmTE("$HbP6f+lXeRq'lH*3I@AbbH%Ef3E+
+Yif3KHp54hE%@hq8Fj,%GAml1RLpN-E,i(GQARdH@0q0,K(GffT%p5)X[RVFF@D4
+BKrHBaXd@6VD,AXpZB5d!C#'6K@abQi`@mJ[Cj$MPC!8iDT2X[EaXE0rjRCHM[$`
+Ej#4Rp[RPjG6VcFj"ITHAR9DQepPe(-SAiAji1arZ(-5ApPP[lbMciLAdmP)if0m
+4Z#m[-q'q["cNPGI1p`,!!JLip@eQPi2X'farqH4p"**I)T!!,ckH3A`!+i#AjfI
+6V9BMbl,P@GDh0P[fhKZcCArkf5`lka2F0rFYkb28qpDfD[R@DP(8@d9PSQMYcUH
+l#l&K+CqqV@b6b'8EXQaE[)pm16Za$2kVE&Ajrhr50p-icq)mQh-k-9rKr#ThirR
+rPjaIiecK!m`jJh-@jcQFFcJAF-lMl1)dliLFcVQ"F`IR*Xk0R"GcEZCFalQ0mbl
+1fcR[i$c+q@,1jh$HcAQBm`MR4C`2FElF9MERGNj6amLPR&XjIj*c$@F2jmXiAm$
+j*XlAFlk"mi@FrjhcMcNrbIN*cSpcISVc6cMr,HHpR$r0q3#eRXTrcYrLI$mR'2-
+,R+rKI"hRIH3Bb9R2#IC-iM3GT%lK(-,CcQPUVdlJ(-lCbMQ1Xi(6p)BkME10Xj%
+c+PDCdr561TN6d2S-jjpa'Lb,I*!!mcpbrKVR@cNIiIaPcSFjIjhc9cKrNI2GR'r
+Mr#$RKcMIc[R[1Aq9mbfFlq6m*Fi,1*Ga,Z@mKI0IFGl*#5!Dh)bmK[09R,GaAX,
+j"jarb2RI1(q(FaIR4cJrb[Nqc[Gb(Z#mQA-Ijhl1Jp4a$2rr-qGri@idr`pa2Tr
+c#j`c1@GcRXXjPh-Kjha1dcX4X#IbK!KDTSmLi&#%2SXmRI-QcLq9Z!9QHAK&RJp
+`lZ(FbhNGjrfFi0ZA1@rJr$6RRh*qP[1jR(r"H68Rb4GarLERAh1H6mK%r[mHjqp
+bAXYTHM*b(ZI2F2iXj`61[`QF)`)'4&l"HCccMCcrM[2R16r(qAR1Rq!dI4jj2HF
+pR$r&qmEbrbAmTmDmG5@R`BL)@2XZiLEchf"#j+Fj$@j%`)h)-cJ0YN6%B*!!fZ"
+0"!b*Q-YJ5Z6l13f@4"l,H6RRrq,m"ZHMR,r0#FVclQpbISXh8X0[Fcl'q6MRDNj
+kp$ZFEqEm1FlAFVk)df"Bj'l1*Cc,1EXjRmhj4Fi(1@rN[*lcMcMr0HFV1DrKT2p
+IcEQEmcpaIScc2h$Zj2`0c[G`AX&j+HFl*#EQK*KF5AfSiiFjrbYhe2BUcZFYQ8#
+8`"SqHK"mJ1I3kr3C28Brd%[d&(J&2Y#Ep#9p$1pa'!D(S)I"!2UBIUI2k&ekQ$k
+NTkNhA)PD1m`$$m!AqJL1"DHLhq&FB#FB#Zm#3m%Rq0Hr%%46EGlDqbRHVF#K%H!
+jCH(Hi#JG!5E6*4lH8SZ90Sij`3pl6lJjll@6MSXbZAq0&J$qBllBSmf01Ffr4[l
+C`lkV[XcL4ASG'Uq6pdGP+lLTLlHfZ[CGhY-)T@1p"c3qUpkHR1ZA["4,,hRFkea
+YBX@*hcX-dG"#+9Im%9i"mj8`IdC`pR"ZifcRl1$Xj"c&1CTc$1GBcR'FNcQl1'G
+`VZ*FcEQ@Fb2R*XiYR$GclZHmKI0@cJ1F"cN2F4lQ[)hc+1IYR(G`2Src(Xjl19r
+!q41F@f-(QGk,(-FjM(-iCbXRM$VH@aj#JTLJCcJ!8S+3!+!HU!JLJMDJ)qJ*@MT
+N"$e"8C!!&83&)8&+Kk"K"%KC3E!i)0$PJemF2ha%-$h8ZV&k4A@S8HedmNlrlUV
+k4r+lI'5L-VEe@@SUj"`H)5q"0Af[ML&D&MAMJ*Q(BUqXb8H5K0BVJkB$kF&FTK+
+E1,G`MZBF`cQ@Fa,R+-j1cKXiEq5mQA-NjdE1rCbhF0l+HC!!Xiec'fF2Cc[R#-j
+9R$GacZ$FblQDFbhR2Xl*R)FjEq-mbRNAjpfFcq0m2ZFpR&XjQcLE1BG`YR!1j4`
+QQE%pEq+fM@mD("[Z(pkQ6*ArB1m@(2NMrbrTZlE[a'9UA)NZ-1G*h2#q2MlNie#
+FlAKr`'(q0ph`MVp(96SX3dYqJ(B)h'F3ShNX,hEQPI(CraA+,q4E26%a@U*4G2h
+S*GZQpp4VDZqA6Ni-IBGlai[LEVbSIX8L6)&*mGBRF[Cp'P`'R8-#ZKG'%!T3Na#
+3!-m)-8N-L68ZIi`Zd6(CV9@'cMfh-Y4UGPU0[2,dLj`Tq,X[KR+QI5p6KIl4ahY
+LPcQ1D'%LG1"lQRGkkX`5C4jc2[L!DZG,#8B,5U,`Fq[1G#3r8(Mci'9Ud,jSF#T
+ciQZmAjrirRI0jCeZYIacC+Q'iD#62CM9E%`2YX+JZLEVVGQjbYU*LD&c+[cadf`
+LhS-SY$AS24*%1!"B$AaU%FbHEZBiI&Le*&2dm*m[h!(MBQeX&DQ`Q-m4dY!$bD8
+kHP%6%rda"hqX)Y,(1*GLV%NarU3BRe1-mLR'G"6MGiV4*m@3!)"LY%a"B48MHSS
+40SAJU"bI-b0DLV%IaELIFKb+X6Xc5U8Bhe115CP42-9iN@)m66&kT4ME8S`!+ND
+`&'1!bP%MmhBlHQAHENIq6!ilBQEHEJF8c*[YH+'TL4e&-HqfSf(QcBaJ-HTRalI
+-QaR0XZ0rjXefp0#0fM&5apJFihD-d6&kamJGih@-",S41aQYXQ09M1SaQXGB%f0
+hCUc,MZFamX5i(102M-iaYZG'X%`IfUkLVScJ-8E&'"jMCi`p-N,'Q#)M9BcX-BV
+'Q"BMLBaU-CE)q"NMMibJ-IE)5"TMN!#-G$%qb@JJif#-"c++a@JM)f+-p6(ZaTJ
+KSh#-26)#akJG)cf-J$+'b"JAii#-CXPS(b0DGM63M36#+mfiD'a8e)cUfE&(4Kd
+CKh5MMSa1-LV*b#0MNk!-Sj!!M&'kN8P'*"Q9G118M&bD)4$'`aJTC265MR%bcZP
+'1aP9C066MABbqXIS'D10M!$+f+!Gph0MPS`&-QVTa[BB(@4-N4%h4J8CE@2Ncih
+9-3l(i)SE-Q%iaBfmqX-Q$+-`f-)J#i-SE[L%N8I'C"PjC'5@m8FcHQK(%4PcC%5
+6F6X'BaM6C151N8h'laK*C-54N6Y'(XfiR"fhBr5488I'm4LVBlb4F8Q898Bc'FY
+Nh*049XBecBLQ(FQ%Kc2UL6M+q#hFJh%l0j,,+#lMSCR"(KP@53lhm0'6rT!!Ma[
+UBD#(34i'HKMHBCL(34i'HK"a'44#hN"HmSGk'1Y&cf"FQ2N+aL@4LKMrCE5BN@,
+'N4QbB-5Bd@)h&X`i-#2'M!XMmM*kc2JK)kb-*6,HbYJK+J9ML)`I-YTS4LJ91+[
+!9`@q+["9JFF+r&AJV!*R&6LV`'N&,L[`9S(h#Xa9B+i#Fa@iVm"G"8G3F!F&eLZ
+iJS*$+,L&JPXSZ)@#@bK`AX%V&,a#`5Z8I)+4BS-IGPcBi!!MbBb1-Tl+q'Cb60[
+d$q2CGJcCi*%Ge6-iT-!K"3iTm%H"2`Vm8H#2!Rm8q+2!(`Aq+2$(MLFcrQS`5)&
+"#Ja5i)S#Ea4iSm!E4@mSX%%jSQQ`4i%j#Xa4p)d#Fa5BSm!I"HiSF%H"1`VF8H#
+1!RF8Z+-F$6DiSm!G"HiSF%H"1mUH-pLM`"d&lLK`4p'AM"`UqPf"!`SX925k!JF
+9Q+$!"!8Q+,"5JBm+E&$JJJ)A&,LJ`!-&(LM`3)%(#Ma3i)%#$a4iS-!$"4iSm%#
+"X3T-8'##!K-8H+$J&!T1SH!5#LkKY"8`A%2"+44F3X%I&0a!`8%82%,")a3m3X%
+M&$a#`5-82%,")a3m3X'R&(a+`DH8)r@')bNiNS+[+(Q5i5E+N@E$663pT1NK63p
+THNM6EjVHd[55TTFd[D6T58hrDAT+de1DRY,dP+DR0$fPk5G02fRk5G02'KcAm'%
+06dC@e["L63pVkUDTQkCZQVTTq,1'2f[iS)C$DlLcKQYV1,D'3fXiY)C$DlLfT[i
+D,00`F!fHDALeKMYUZ,@'-fViYBCIDrLeKPpVq,@'[fTiVBD6DMLPKXYUH+@'9fT
+iTBE[DRL`"PmeZ+[Kq"UFe'#N"L-eA&1$NaUFe25LTKFe[DMT3Dd8ErTF`fXe[Dl
+TG3d@D$"!dr1DRYId[!BM0&a4Jp%DM0$JY!B(0"aCJ`-DRUc"!Jd@D,"!Jh%Dr02
+JP!EV0"LSiG%D204`D3f(eR"S$3CUF&1$QaVFe'#3!!Er0IL[`Am09pC`!#d(-"U
+!JQmVH,L#0bXd!S8fS1$IL[STDU%F#6HDJD)HL[FUhUTiUq+YL[j8p*ULca4pT1J
+K43mTHNJjGXriY(Q[3RG3p)b#RbZiX,,Z"XXdZ+2",JfQDEL!KJYSY!X0(p"`!3e
+Id2!%$5I3F!)0*p$`#-dl0*a&`b-dr%H$[aVqSm&RMHDK`9)0(QY`@S2A'Pc@B,N
+'bc9BVZ&''McAe&C6Fdep0(LZ`A-0RQX`A-060(a,`m-d2%a66`dAdh!a$5jVF&Q
+$baTFe[")$Br8p)Q'#fPiNSCVDMLQKYGSZ*''-fNiU+Eq'JkRiD!D(UIK8jUHdh!
+R66pU1*H'FfNiPiCcDAL@KQGTH*D'@fRk9F1[0$fVk9P0VfUiPSCVDEL@KQYT1+k
+'(fTiSBB6D[T3``Ze[*!!mAZM%5Pd(iAZSp!8&0U43[qaNaMS)%CV8'J-QJ!0RpE
+`E!hre["[$Ir@m'm0lpE`EJh[e["Y$Gr@m'd0hpEU*ZJ8B3GIH-fNB'1B3JRj'%8
+aRe@'`bJ'fdl93qCGKdIr(k0G&iF0[#%M-bGm-JqU9h[+JqSeiaYjr%&'P,'fP!I
+eE&M+JlTf@5p2X8P-&!VFXe-H9,V,8aj8[#Y6(T5qUe)He-#V8ai8`fY5(P6&De-
+H9-IV8Ki8h4Y6(Y6JQe)HP12l8Kl8cGHP2#LMVdTj8&6IP2+JVViQj8&jI8A+Jc,
+l`T3(pIDG[6c*-6!Ipe"iVdM[339qIXU$8[lbP!FerD'8"mApH-U$+[r6+3r+rBG
+5(Y6p$kBm6!$X6AQB%VJKj@'5i2U8KdQ$25N28`L[6hQB9(K$bX-Nd'G5(UDD4U8
+m6$f05hQBL*U8mM#jp2k8KmNUjfrAPiGTUkRIb12M+00CAFIbK"Kqp3Y@*5%[Rr2
+%D'*LHfYpqd1Q'%8rU[TPTCU9!ZrB&'H)J%d0cjQiHAcFqDRB&leNmjEJSQ'UecM
+CQLfQFbPHr@*FabPMeHRc*Y[jG(e(hFQek)D4d@'j&[q0Q2c#a@3MMkmhTaZc05I
+D'Q*m6rbr,IjI&Iq[MIpAarm[@Ra(jh'GXKM83X+ha2rhaIpharmEirp0LqRE9p+
++ebL#f'+Ck)liId6m2b2qEer-fV*LI2YZEIKFj6VMre(arqMiIdcm2cEq(lIiL+%
+q!PP&aq$*mArABT+aChCf9BZm9TR'hl5,@R8pUE+P'BEVKm9m,ieYpS,irfL-Zcr
+H(iVr$mIr0mIrpmErqq2r@q,r@q2r!r(r`F9kk-F-ETSFU3"H4kT&[B5!ZXA`qZA
+"AU-ZTQk0riI(rif,Z4U@"am$Q`X(*[RI&2rEmX+B%cR9+L!QqAUp'"dpr(VhhhD
+Tq6pX-9IMiGF2MIq(a2mYLlQ'R,!jAd!C&4qcGAjq[ZpAGXmfpecHfH(mT08%'lH
+MKZq)!"i#`hK'VKNDAcqmTV*QrH$8)(phM!a0+BL'U(aQTLGV3*0flr!0CV`6RKD
+ki0la6eC+49ZBd)TjNY!!CKar%am6&-kZK6RZZZ9Mch%qRrR`k,*p'r84B-kl2PX
+jV[V,2,2PlqCM2YNce[6Q[CXDkY+HUZXC0R[cfUi,m$j`mpI-q60rcBFRJ*P)DG)
+I!4m#TNliQ1e[rGV0jF`imqpYfhGlCEd)4Q3ri%JrmrTf@S3lTLJk-KL00dmF1D0
+9*Q3fedk!N!#$'@ZQ2,KM*Ye-FYKm+19MXTHeR"p'(4lE,LHDm)H`8aIFiA(!c$G
+hq"G-D&3P8ma'-`1q`RPL2"-Q26Bl9DN)$i2*`IQ,qGY)KBHD'M&V5kpCc`J6BQI
+[D82QckGP0kiQMPR!b1Vjq6ZG'fAqRKPqFY"rdaR5CDD1qINC38KKKYEdE11ERB2
+%0i,CIZBBm@%i9e6dCP-Mj`C2'qC1lD`rZI%LB1DI1fScKrFaPiL2`0b!&(91$-d
+,MKpeeSZDF-Im2pi!h$(PJ%F!GbJRH!9`"kpF&0K"R6i@LhAm-(Gi3P`3H%5G1,0
+Nf6lEUNlI"r`%$"1Ydb-"A`(Lm(GBPYei0VQLBYCbqX2d@p4T('EVJ5`m$&C52p0
+,8AR"KF("*5T@@A`dG`K@6+"`"c)bZmmGRKV#DU*k5c$,cahH$!+j8AZ#(J35`8&
+QqlPMAKm"KMY`%NQ%1l`pQ2AR$Qm-XHfUelH$k4(Z!$*kKcZm+*J#!@EaD3#[Z+-
+(K-Nhk!H#4`"hH(2`GZl`bU$1h1&p)GTAJpL$K`"hH%hJ*F!GrK(i#A$(Zr%9i)i
+DibrJi"f0L$X`(FcKMNNZm*-lqJm["ZlJ%(JkF!F'iIR!(4J"4q#1hXBEJM[k$Bm
+)lZJ0F)-lkQM"hYcaCN3,lSM"1i)lH!EH%G`a@5&#C+2H+Ki6L4b[M`VBcKfq+8b
+kF)GR#Ah+(6iN6+a`KhF+lq)1la3Q6lM$"d@mS"VY-cJ#GhL,#-YXe,X$0BFlq)V
+-4$EU6m+%#(IiH9!Vl["6`EF#kX58UUHr4%k3!*2K"m-GrK,iaA#(PiF`Z5Ca6Ub
+QQm4FDXiGrK[icA!(IZ%l`adi!VrLMMk(Lh&(2m&aZ+2ZBTMEC)h!,ZjiJaK`0ZN
+PJcm0Gr3(rF8GILc`$ZlS$haVZ-0r"EcL$Jm8m*ml2%c`Xq%1(aCmEEM$Xi3q09q
+c&"C-jJjZK*m-Gr!aZ"Khm#+i*(IiPH!h`aeiL4m0Gr3"IMAFd3IieR!(VZ&I`af
+B!LC`4fq$eGc49rMCF%HYi92Fm@CmEEMM2A!ClZ$1q0a`"jE!EER$CiGBlP"&)$V
+F`A("(ql`Im%2KcY`'PmFl["h`4q(1caKm-RK$Zj)2jT[L2L"p`phm'&i!AId"pi
+rh)'le)3lZ!FFK$Y`'3mKlX![[)5iSmrKM0c4*h!dlRJRhN,Fi4-%$R"(Vq-*`Kf
+H0IJ,FBFR$I8hAiXF!VmKlZKMq$jhm!EmKlL$@q*$a"eiKKm4Gr!LhXXGh!1Zc4f
+B$Mjc"fk#4Gb"4hJ(F3F@L"V9BKhKGp`4!aIQ$Tk(pa"hq1R!hlQMcq#NjKZUPJ'
+qFBH4-jj%h+%hi%h%(AS*(NAF`62TFHlJBrJ6F3F[`UH)1hS1[b,Z`'@i'hIJ(6h
+&(4J%eq!1,)!cFNFIiQ[%(If![a&h["1I)ql`(!*EZ--R#El2(9J,0c6I-2%$rX)
+G@![[jJj0"GcQMKVMBF3G(MqmLc[k%NmMlUJVRNEF`CI!-HlJ'23AGr3L(NIFJBP
+J"AGJ%lb*1rS5[b2ZU#1q4pca(VJ$GhJNiB0N[Z&b"IJXGfJpk"MFJArJ*hG`82U
+D1cJr[)`lH$9p`4dm&Tf"1cJKh)3lF!@[+1lJ-r"PlZ!9V(R!(CK16EJ$Bm"UlX!
+JH"phB!Gib"hp$0IQM[i4,i6KeS,Hj!kY#mmZml@+2AKhFBH'KBFAGiM4j1'1'X-
+VZB-$@IFdFiIIM(F9q6jpC15bPAVMFfA[m,U4dHe@*rGNR,99rb"C0k"9Mb$4reV
+eqa$pVe92$h&DD0@$4[5r9[eM42r$q"SI,AZ(4jESIfek"(Q,A841eGG(p,mfrA'
+B,1F1hae`L6[mHG!IZ'1b8I5r0MhAi-lFi@&KhQM[m$J5rDp0,a,4rpVd(8'li!j
+[($(TEG-M"pcM$KmFdIrDp-!3r@m%pEAV+A#(Ra%H80cK833[i!lr(bDaZF26KfP
+Vl[!KNY8K4ZJj*2VI#,hMd(bi`fF1[XmG[NkLrih3I`N[,qlS[j!!P8'%N!#!ch5
+Zld9UKQh3UIlaLhZ90LfCB+HE04Mpm4GQjPMU'f(#A*C+bmcjdR*"KRLhZmQ08,H
+[Ch*Nq,54CMF[QRQh-McAEV5+r0pRT[Ur6AP)1bHILaTp'0X(QAcISH&iEi$ZScF
+mlc8)0G[Md%K)frGH9Emd,R`-A'LIRcm3"c&#fVlId9NjM3XIZD(i+B6ERML)&Y,
+frD(ZffPFq+-ELX(2N!0r1!irK,&p''UB[j[90TPU,PNEQM`-RQb*HFS@L#B23bP
+EBakcfP!j$`-V25N2`bcE8Ki'AEDRqM$XXMrQDAM31X[NB4$QPT5()CPE8ak'CJk
+Q2!c8(%Tj',BjR2)`L(0EbX13!-k4P)F"RU-T$m-kGkBm$2,FPI)`N!"cImT$ql2
+pLMH9AXQ$UAKGbS24H%[+Jq&i8mU$+IQ3!*3(dr,QP!GMmk'p2%@V4*1(3IJ$k6d
+-(Gk6mQ!!-5cP`FKKH-U$FAaVbS-C4&[+J`(pL*3(NrVfP)GKpcX5rM!dqjb8Kb(
+jBbN2`q1hTc`-'ADN1Q+k2c,P`C5r)H9KkBXa+3p,B)a2H9JJBh,+``$j"hTmVj`
+(+mI1p"i'(UI&2%1qPBGP0kBFHdq)i4H'X#E+2fr"9&SEjIYlr)6!I@'"`h2@5$@
+XVIAp,b53!%`d$*`dZh&N+M[`fHJ8C,BRr2`AhD$'h(AM3,CdGYQ"6pqFII`(Vqi
+krM+"V@0DaSBhE8%[[(kU@ZLPGYrNe1BRF[r3a)4HL*&hEklAp)TkY*Th4C82%iq
+2bFIE4DjReZFf0+VQrIV8Q(iBNDpGN4FG&*8KkiZ@8Zr8dQe2[QLp((qaRR$4hHA
+)KqGhG@rTUfMpEp565cp'kX-@1$-VjIicGLXF['%mMl&l5cA9mjfk9hqpPZKCC6h
+[6NY#rZjHS44HRrA9rYB4iH`*Vmmc#!5CUV+8f6pZ!a"Ep$)@PCJ$HhV$[hmbHml
+YhaU[c1RhKTR3a&4,B%(QHX@DbarGGB)p"0dhPY!2ZK)B9TMe*`h@Y!r&JV*KSYl
+8KKClZmEU4%[l9@chQXC'P!fX09ac&`0kX5`E-TBhAD%+Qpb@,UELh[T9N91i-[9
+NrEE)UPBRjrfXU49j6,h4m!j,aYE*A5hAVX)HX1fCGCF[X$E+)mCD9h$('N4Qci%
+EZZ4MIDE)k9bCfV#H915-Ur)K9j!!`TkdXe'h0U`&&APXc)GYiZMZd"6eBmfSb&R
+GaQ9BeGCTIcHfhKbL0R9DXBdEkMDB$+l6&RKmBcCRkVK1'@4#im4*hP5RGHE%UEa
+M2Q`m*kd[P%RUY*HF2&98XEQYdj+aka3#c4f@J&K#QqQZU"1i8jZeR0k+ZQVCY,V
+2L+a3fMKVfEihB+-B&H[%%XlD&SXPA&3l5,'%LfSTLBdhGr3L0QG'ZUNAJE"bT)A
+j2f[C[YFbE9b[*H,Xl,JDr91[*DKB3YFl`5Dlb0CVIcShi%'ppTlc!Kl8Db-j2q"
+"[6,1JS!($8lK,Jaid1$+D1F(2'M3i@&4`)-'LlXii%'$0V!A"$aSd,Cd5F#$"Ud
+eP`BmD,![Z`-H0'T&Z#cJ3D1iY6cJ3D0fDLX#(M4U&ESbp,He"Vi`i%'MY9`9m+"
+4kd`QE8hr0@TaZ5EQ`iCaEF#$*LHCe`8mD0,fqU+!"dhfjIU!"deDafi)H0#N4Hh
+'J!G0pZ@QJ!G0@S0Z$RM3T(hPPS!(eZjfDm#$CLd"QB3e&U$0@U!bl@TUhDbe-KD
+fc&GKb`XZQhkfYV2)C)DR0@Z&#KBE'd9V)iZ9XTN5EpBpJ9SCI"NLaQ!*E55i)GU
+YBJR08$a[`a,D@"X1dIlbXN[c+qR4)IDPXB51JK0$l-[,4fEDp-d3mIk+LDd9F(b
+)eTeAATTG62eDV199MEBeE,'@9iHG&PVN%pFd@&r6h#%[AVZK-X)l@qJl,+(T[aD
+YG+m2q0HLGHDHJ(mYpZAH)&1fL$&Q1I)ZV(f(1K&qif6H*FP3qr+Q#TIQMYlBPdp
+@i5e$R8k&NaJq0&3,BV'%(UT0VPK#$p8'9LbKKfSh+TE3`m5BJjplRQX3$"0E$l(
+&P*%kKr(f52YMChH`A"dQ0lTYjlS+9Uc@k[3)2U1Q"iD*-8GG0X,FB@plM0+Ep`l
+6J[9fHX[JeM"Y3ZmBBE-#dl,djA2fV"X%$iEEPhIZkSK,`m@#Zpbl`0a4ZqHLjCL
+q(QjIhKhH0e`Hmlc`2QXYq[afZdlGKfY9HSpl'aMUK&[!mBYRkp5j94jhEdCbF`F
+ZL#9dUpa#,+&Ea6#aK'l9fPFXS9[P,Q)*MF@RXi4Zdkj6,+(EY(mA5qJf-88XSGZ
+dXaC,k$CYPX85ZNhF%N[S0RYG,+(Ej%CL#6e#e`'aK"iK0a*,k"&LQ9K#Mp"'@bb
+K4fMT,*E3f'8k5qJ4@YH+*I3)E96&LDKG'9SXSG[P%')*hDiYV&K#YfZl,CE3l9S
+pLb9dZdD3!')*hDjPVPK#Yf[I+TE3(ES)L#9dKha,,+%lP0A%%VV$(K0,k!kYPX8
+5ZN1X&8[S$Zeca4,DZTb+*I4)TAQaK"iTpaG,k*(DUSXPp%Ml@5bK4jTA,+&(DQ8
+XPY!Mj59L#GdTrSQmhLPI&%[S6ZhZa4+k8qiVPY#GpVPB3RIk0V'%lY4#@5bK1m9
+AXB3H*4m95qK4FNkaK"iPISXPp#KYf-85HT6p,*E3Shbc@%+2dNjC,+&(DI-VPY#
+MGI!35qM4fUD,*I4ShbIQRD2&2,'%(QhrLbAdD0mTPY#Ma3baK"kYhDjB3Sq4GiS
+Pp"MjM9K#Me%E%8[S-H+J@%+2XFI%%RU-m@)*28D1,TE3Bm9TXB3H+fm@5qLa1UQ
+**I4BF8J'2FD+&f)*2GEDL5Ad@2QI@%*E&eZaK"iR*a0,k((b','%(LG(%N[SFH+
+b@%+2Xmr&%RUFla&,k((D'SXPp(MjX9K#MpFH@LbKamZra4*k[2aE,+((LhGL#6h
+HAK*,k2(q&d[S#GUML#Ad",&(,+%Rb&2&%RU#j&!XS5H)k@)*28&F%%[S#GC),+%
+Rb"h&%RULqS4B3Nq8CiXPp%6aALbK*fUR,jE3%m9VXB5H+,k)*I4%DbD@d1`$l5b
+K*pPRBJNp5@`35qK*BS0B3Nq51iNPp#5aALbK*iNMBJNpb6U+*I4NY65aK*kXTL1
+Z5*2&Bl'%RU`++jE3Nm9lXB5H,'F35qM*B*Q6r#E6Efk5QT@pR59dPfXDLN90&qp
+cFQfA&XaL#GhP'K0L#GhP@SJbG0)&6MK,k#jUjbbKTp"ccK*kLZX-LLAd&0Fb&%[
+S+DlP+CE38l3r&N[S+DkI*jE38qKcC`NpPEc1%RUUkb++*I48ebB85qLTV[JTPY"
+6A@94,+'RZK+M@%*2"3HG*I48HXpC3Npcl85aK*lQqSCL#6h0e42&%RSDIHBXSDI
+4Cmi5HTUVm)NPp$4`bPP#RdAr1%[SXeb285bKch)94,'%2N[A$l'%2X[e3m85qLc
+AmK2plbcAk"2plba`c9P#RdeIX9kM[@1e4V%j2PXR&Y(rcYCp"%l%(DZ-bNSBCp[
+(S[qGE8q)rRFf1-9DMRc6U6[V1GSlqPK@`TMZ@SUb%XCd9f58P6#QZjUNV)3ahA8
+"iHrFXDSL()FlJf@Xp-Jh`jj$cq'1pl'q!(IJK+b%-81A#h#E1pDDK(G`a`U#XK,
+'$([1p#cI6(#+G4hY(6dR+f(-G$e(@3PMTUY!bNSB-qdj@3PMTUY4bNSB-eeM8&E
+#Q+R&ZDb%F3kiaPU2pSkHNj8`cY%P4eE#1-F9)f8PM(0F+e9@`MM(05YP*BacA)G
+39X)iajk6P6$1"DIX#L2FQEUc(U5p`ajG9X)iejk6P6$1eETG9X)i9aYd@3RMA&H
+%P*8`cVARC#@-@IDdV)3abji6*ljC[Np@`TLP8iQXK$(,062&hA1@Db$+5KLcA#p
+59X+BEFr*5KLcj41b%XCXHdj@`TLYKLmVBFc@qPa@`TKYcmP+',1eETH9-'DlSU5
+-)ThR#UDb%XCji"TVAGSlHNkQ8Fl6CPe@`MM2e9e&rcY21h[4rmjc*8A4rmjcc8R
+4rqEBFl)5aKa`LV8`lCfT1qYKfMZXff8PM$RfR-bLc(&e@&N*BiiV@-UXaKbjKDb
+%-GHHNj8`jYV6XK,'A(Y19X+BkrYN*BbjmL&C#@1Z+cR+*-GFEHYP*BajFJYC#@1
+H25FVBFac$3"C#@1H25%VBFbcjd6rQqIkRk,rcG2@Ar5rHDk"+IVII,Q&k(rcAGP
+6p,rjFJ[4rqE,%8ArQbq1L[ihhe9#4IqE,dF8r@qqp[ULrbe`E9E4raCSSbrkh`*
+l6[5r"Fk!L2kh3'iKqYm#ZBASI`YF@92d[`@ZXbMkhd*A%aApEk%p*rVI3YmRqYp
+#ZBASI`YGT96d[iAbCY(r&XSY42mlhp9K4Imlhp9'4Imlhji3rHpmHdld[r1T1bZ
+DfMZ`Ar5rmee,325rmm8jdIm@ZA+Xk(q,A*&8p,p&VJSUqYmLZB[SIi[NjD,r,A+
+PAG(r&SRpS[mY%SG%re[XbUDLrbffjd6r@qbk!U,r,CC$LrkhQ(jJ(94laqU@S[m
+YGK94dIm@ZckNk(mAf(1LrehJqd6rZd!q*rVI"ESELIjh!E9QV8alaaUCS[pGi&U
+MS[pGJ)E#fTPm5q`2dIq@Z&+#k(p,A,Y8p,mPpU,SId[N(+,r,E'ZS[mYN4q)rVG
+%6LRkha*V,2VI%VQ)k(p,A,Y8p,mPVN8UqKqqkkbrDHrS,G(rPMV',2VI8PFm&Ie
+[UBjKS[mY&AY%re[U@JZLrbf9pi[qYe6X&re[+6'Xd@R[i!'Lrbfe[dArklBr42r
+VGL9AdIqkl3r4rlVP6+,rGDYYL2lA,GD+rYGYIiMqeff2L[lAEAq)rYGY286rklB
+HS[peLm'Lrbf6YiRqYmaq&Ie[QEa6p,pPVViUqYmb9h`9r@qCXf1Lrbd64dAr@bB
+I&Ie[QCJRqYmbqEVSIm[%E0(rPVRDTZKrbq9jS[mYPdH+rVIFZ624rjDVEBMqYe`
+R10(rPX[242pElMV)S[mYYcp%re[ZZJkLrbfh2d6r@klf*[VIFVQqk(mVe"*%reX
+K4a6pEi9VdBVqYm+C*G(r9UKeLIkh`M@'42pEBHq+rVI#PCC&re[KfUVH9H3RAIY
+8p,m9VKNUJ5[!-PElY(F'#eMadpkCrQ(96hYRDX(+Rh`VAI06p,q9VLJUqYp+-)p
+931dGUkD+rVI5Y94&re[TUV#LrkedY9I4reDkJU[SIbYGV96d[j@ZmbVkhdVA(4A
+pEb@pa9UPpXld-'Z1mPe),9LRe0ka)URSIaHkiURSIaGD$p(r,U4[@028hY%VS[p
+Gk)U[S[pGk1UaS[pG#+k`[LRI+RU'P8hYRAN$Dj[D1eC@&Ie[P5ZrL[khbRP$dIp
+@ZFUXk(qVA-e8p,p9VJSVqYmUed)5r@m9[Fh+ThbVID[SIkYGJeAd[p@Z&#[khfT
+`La93l4hVd)VqYpS99NAr@qekV+,rVAD09Y(r9S0pV02+YiEqC1e@HfIHCYG8iSl
+e@%Ar@q1DXD,rVA%0@p(reYK2S[qYF9eDdIr@Z&kYk(pVa"M4rpD!@DcYbVH@hQ0
+e9hYRmV,#UlfMaU,rVAApA0(reVVUVHKrDm8jdIr@LQfLrkeeV9c4rpEk9Y(reY'
+hV2aUlqJRdIr@ZEUYk(rVA)&Ap,peiTESIq[%+Y(reVNqV1KrkebY9[5rGI!+9Vl
+PBpNeeX+eG`B,@!rAhTQkXb+Z[@20@p(r,K)[4Iqlb09h4Iqlb(9K4Iqlb&9M4Iq
+lb,9e4Iqlb29j4IpE$qkc2Ukp-aM('VRfc[3`kq6D1r0qeXUeGkce+rVIHYIV&Ie
+[[D[$L[khAJiKqYpkelF9r@mpI)QeFrNfZ#kXk(mE`%h@d,9hF!A4rcEiEY(r0[K
+ZdImfZ0U[k(mEd%&B1GMHXHDXk(mEA,p@p,m0m#T@&1EEk,UeS[pY"0GB9GMHQ9j
+PC@&lCpl'kX,fMTi@r@qMDrk+rVI4eAj&rpYSEiRqYa(1b@V$I*[N!D,rEE+R4Ir
+E"0D`mV#p-rh!kX2f$S`8r@q6EaApEj0i,2VI*[Q0k(qEa#h4rcD*@k,rE4BM4Ir
+EE$q*rVFCM'"0BAYRHS"eL1dGka+,rVGCr"$pEl1i*IVICYI$&Ie[XlJPqYm@9li
+9r@q,DqU+rVI&GAY&rpX#"YQCDqlJ(k,rED%@V&jXleM49r5r,Dj2,2VI&YFd&[e
+[Laa,p,qYiSISIeYGK9Id[kfZmb[kheE`MV@0lChT6eBfYRIJPZKr@ehE9r5rVDi
+9,2VI9VQ)k(pEIEISIcfq@r5r(R&,p,mHF9Vd[alV,ITI$lh01X$fcY51YAlY(9a
+%p,mHZBMSIcfZ#LckA`pmRY9mqEDj2V$SIpYmUqKrfjaY&re[QaJTqYmfDbckhcE
+HcfV(pSkH&[e[QcdYqYmf0![@2HEElYUqS[pY&lG%rp[ZQX5LrffhaU,rE3FI@AR
+ChS%PS[pYTaDX[fc[i1LLrfehY@24rlDl3V$SIc[N(k,rlA!eBp(rGXJM4IrE)@D
+)rVH$AQ+GBR[(UX1Lrqe`c@E4rbjf2@(4rbjf4@,4rbjfY@E4rbjfK@R4rbkfEd6
+rZjMqBG9QH`IA&rh[B[Q6k(mlAA9Bp,qGVPJXqYp1hbIkhdljK1Kr1m&69SqfGh!
+QdIpfbZp&rpYTr86rfb@(%2e[PkXHLrkh5b0ddIpff4qLrqebr@R4rhEj2Y(rGP%
+[9Q+fGq#Ck(qla@r4rhEE(k,rlCDML2khfrH*rVGEc8$d[peb"G(rGSXVS[rYMUX
+[fc[d#G(r,T&2LrjhLAaDp,p,A&GDp,p,A2YDp,p,`&r@TEChk#kLree#h9N&fpl
+"+8ArHjDV*B[qpbaAB4Ep,r6Q-`KQ0P,F2ZP@IfB[aB0l[QX3&!Eka6G#-KJB+AG
+F$&YT!11#*+*UL0YR"d$-'%Km(8V-im,H--&Bk"cVYYF0$1c'Dfe1ClEC2pfD'@J
+AVGVXG,FcX,ZfCq##rJX'DUhTcN#eABqc)5%MAh&&Mj!!PXqbJ[!DZfUfq3L&@E-
+K$'(eJhT(&G1pPQimQGZcBF`b-KX)MM1rb0`LmiV-+9TI3R-bMmM-),1)c!XbHmJ
+X)[1#GJPkFc*hb'`JXi,-!M)rb"bJc2q&+Rb0#j`NJcFRh62rH@q'TpdjRmU6UQS
+)h"F@D&CX#&efAfA2Ir,[2RqIjE#%$3rr$f1UIBdPaIZAa9rX2S2K$NX0"N5h8Y"
+-T-NGqZ,XE0FFGa$B-p[SeYF0cADkVCQ+hU1(LKVZSVN8UkGCLreSCD,DeAdd&im
+(+rkMaR,ejZE1"e+XVhYeR3kNa34iN!$ZKH%G+kS2a"Zm0K&lmd[bjS2KkqSGVEm
+2E'p!%AYcb$"EEc5+NR'4,E6*h-!H$V5TC1%"ASC,UdAc`4U[h6!QlFK(EYTF'@p
+hkc2eUrlME4LE)jmG"J*+iGALfIKRMAdpe*[cmr5j(G9Qh[KkNKh9cR5eFD6kNU+
+[r!`69PZBm-%@6X`MpNE['0l`8'LP38cikXl-0aYJChl9NHTILVXeaDeNZ21LThq
+lq)4A#NZdUjlmlbS4GDY@b-Q%aZkh(p**8!&dSQY`6S)UQ"0HJA+Lbd$ZJLXBi$)
+%MH*L#deZQk)+i2(i)RlCq$ai%eH"EU,,`"d,,KHX!0S%$N!f+@U!R8K3+AFCV&e
+`IjZ@J0V&CQ%k&PKUK`T%%ed"D+,li*Ri-MLli&)TI@"1"TYUpF-`#5S`6(30KNP
+3K@(#+c"-G"Q'AA#P[ef'S#PFE+8TUM!FMbrLNSh2`c"a&4JQZJc$XH"b`3S`61!
+!$*1L"X1*"*9bPf(B"IHhD3Q'A@`@KQ1"TADS`$$4&4JQZJq'L5r$X!XZPE)-`qX
+(Til#-!NU-%ad$BC*8)9K`LX`6(3CKPe`TEpGKU!TA'bP+DS`()m[iT+0cm-`F48
+B*VS-`l(JFX%+-%cJ!!b6SJE$L359FTGKf!AhYfN*KPeX&SCMJD9fU-!`d48B*VS
+2KSN[`l!,,T8b"m1RC+P"BHU80(9#R"U8T`B%UY-59Ep)05"6R45U6NT9&E&U8+l
+kVVKd5Pik*6!05%bR4DCqQDNU0!e)6B0Ldk$FG%Vk'44r6XNr*`5J33PS3!3k,32
+e#d%$8Y"*-HLN(&34K!BPSHm+1+FNR&-LcS#-FeV)kCGbUQ,1J*`c+1J-5MURj*9
+"JH@8a(*#C"Q8@3D%PY055lrB-L#hR"4F6NSZ&G&P8(EjVNKb5LBj*C3-5#@RaC*
+qZD3UQ!a)*S1LbD"XNT`B,8NBk54jZ%YR+!*H1NN!HHN8HG",CmM"AMj"[Krc@C)
+GQBp209kQF3,i+q4)BdXQK`q"kGJm#+BcP'!`RDB)K-8NrHA+J@%q`FRfb`*L2Mi
+1L8&`AfrQB6'GS4mB+i*(1NNr-&C%Mh55!@$X&6l5'@V!@"8rmPP+R9N83$+0-`#
+-C4%NNk-A'(Z&N!"dKP2!@"&$LNRkbe8$aUSNNXr5ehjPB#`+)lN%9@$X&8I5d*N
+EH3J5e2!j0IU3!!iZL2RT($P"2jqJMerNK2ed(p5Uh$YM&@3)UPbH(%VRU&@j-%'
+8MkqU"lND$ik[9!GB6JjN$)aNp!pP$)aP*!TINI$55IV*@dA'5bFC)'qp8Pik3if
+m9H@mI*B5)"3P[8cM$*!!Yl+XPmR45pjkTEedKP2NV5,[&C2dPkY'hUSLAcj,ArZ
+9b9Y4kXXPU*+hV0bApiI*iQ+3!#-*Ld'#$#S'19+J''4)BQ)K`FfG9M0@Zr$%@h1
+XE-[K2U+@iT-GA8SL$9d+GbeED,F8QPC5a0#TN!$#`p)J0!QP33+IiTAMqdVS5&i
+3Qi2T)%X'TDXjDQhJBh3TrN4$*a#k&!j!Pf1VRC+%jb$"#A41XqBJK8qE5r(9q[V
+%14-IL*j"MKSr##62)%Fr2mJ+RS8%9AjJReMK"aQjY"4IJj1d@&S+Vl9E2cr)+k@
+&&%9qN!$95B-%II`JUh+9%q6j39'$$E)-mS0!J5hNU2+$J[jD5P*Yk")rb)L[[I%
+9IT!!P9k$"!2m)#-CPZ+VpHhM"i'Z&Z5SmB0!93Ybp21$V+C@5&$P"rD*&Ak3!&(
+N5[%e1%RVFDA`@V[emi1m'&G)8H3(@5NZ50$($l)DF6P"RKm8CEiJbb!r#%5q3Si
+U2bK)I+8NeBBZmB1-[YFEAq%(*p5p[1SHT1MM"fRG[46ZDJKiTA0Nq8'3!#2*$i)
+%'Ai3j%MaJb"$NKm%#Ab!,m8RmD#842UP&&lVPa6!9e,%N!#YN!$#!rJJ0!R`33)
+Ii-[aI59d!"r%jJ!qb*)"q'U1@K[i!&q+2p(3#B![K32`jGKUTb3"2NL3!!6i)%%
+Di)-82X#AiU[e6IVbQAS1!Rb3!#-*m%'#$-!(19)!(f4)!Rb3!-!(q&*m%Jp+5D4
+I5Z'eINN"I#9&$0N++6b!$d+6!"mNm!'q(0pA3JI`3@`1i)-X'B#[jULeJ3r`TIJ
+6$Cd!q&)i!&q1VAC+%Z#$"%Q!$a+N!6j)i30m+EjDhd%'ElYpDl@jFlDk-rmQ(X3
+bP0k`VMAp-+Vi1GK1*CK!F(&*8Z'#-N6#aDA)JiY+%JBAj*-%2bD*)hkJp*BINUe
+K#[46B6'%Li9ji1kZNi$ZJP)pPi`5D%r'C!T5DVBFI,[)$'5Ril*&p+(CMbQd83+
+#r4"J0hQIVPB5APe3%P*G8"T'ACJ2RAj-ZKBq4")6f'5iZ#`X"@BB,Li(5eR,#aH
+8JD@#XB8IQ+KKaViL9X-F,190+Q*KF9M+@P'iS"`XC3E%Nc'CJJ5`9$5eF*%",!A
+@&E'i0#`9$#Vm`(3EqE#8FCj)a+4J+HX[iB,bX*3CC[GMdV9)`e)!59Ni#U!S"d0
+C#-V!6`&kdV#6JC`mh15K*J%c@BM*`8X'@V+`%N"+%8i#+!PJ*!-K"IK)3iF2'aR
+)b-*&$LTL5aS9@%Fm1XXpiU%"!iP(jhK)2$E,4Z+K'8k5LXa#DLSm!@DT3"p1%jA
+2FC9-F",X%m&ahK)2bV+AH'L1`k4M%d`Q(9NXAF"UiY&&EK12$aK10VUhp"QfNiU
+X0QLDqD3#(Ip*4a@UQq9#mG"HQ#Z4khKd,mb9L(BmZJ4c"G)G$bh#A*Q!Tm+cA45
+3!2&%j8X`ed[-%m%CQ#Z3!24iD!RQ!X+HMLb@VJ*c&3SIMkr!A)R1*k),-&HQpUR
+`3S2QB#iJqmR)!1B+a(pVIIY$A-l&CL(1"3B!jf*cm1BLXq$Q!M23jXGPqmB26R5
+0(qCh4kc118K,K5Dl1KBDKc-ANJ8c&jL$XQ4N!XL5F8'a!K"cX88)Fp%"J+9M#iA
+1J*FI9fl"0($jB3kfNM(jDQBKb`9Q!@[Gk'KP,C(R2!"CmHJXD-9$!pL+4qH!+ak
+EKDjiD!Dm8T(ChNQ&*lSR&HMh5U,b14$,"#Hl1a%F"l*i8"E+iU%j-%[(*Z!X(9N
+XA3"TmHJLU-AM!eM,4[H@2J0YUFKUJkEK,4AS!#iG9DKZ&Z6LS39H9K)IA'b"Pj@
+%"aGEj'8&dF%&"VbX,$Mi`@P5%)J0X6SAH9Q[d"!,6I'bJXMJ!SZm,"!BNR&"X8U
+mV#)YZ1J5,b[*#V(B2#mV5`TqF,i&-l`X%"-5F6PH9K!5iKV$ZRcll-kGH9%*-*5
+1AMmemB!bNCmqL!GRCK"5N4I06HHd["RG+V`X2Db3!!SX#S@9%K)GP,"hVLFHA#b
+KLkb@-$m'P!S-q(433"HE+Tq,bKI2K@C+jmF9#ZFRb!X$3G&+`"'M,GQLpB+'#`f
++9J--2d%H0BYJi5M0KNCV1pKGNcG0Q3j8Qc8I9j!!1$hQd+X@!p!$Mb5&HF1qmmD
+rT6p+JV,1+2%&h"XSG%c+kLed,,jFD+F3$6bb9ZKdJ[,F3+l3[R4BU%"5VmX@14Q
+G,l%[JG@Hee[HI(L[k&BXE3fUNT5h80SqQ2*CC1ejeG*@!#SIA@#@)23!FT46q05
+N9X'"4bCTc-lC*KNb%&J)cr+f62$!``LI[k"ZP%M%JV,VZQLl'iUUr#FG[r$"QBE
+c+i1e@Yf-8RG$RG*PlAmp'ITH6hcKp35@AqqkT[4f&epmZBY1[pZ&e9lGefmZ[[,
+UI+qjX-+V`lbqh'j4N3heSU-fHp0-hZaQkm+DBE6rTTPfUqL@Ll,e6'bpjhT0YG&
+Si4Df-@qdXl'YPD#)fN5ASQ"BfC!!@b2+49$fr05C$BV-CYAQ,CHfLNDYIjTellC
+@K[TPKHZVDjpD[rbLfMRpP-,'#FN``9k)8CR0reLZZIIN-Z8)AJ&6R01)1AD0M'r
+CCKBEQeNT*l,Z[SK-Aj!!*&ClZC6DFqXTPC&Y3q-E&KV!aXAl`5D9D[(!@29LYhE
+c[4ZVdrPLaIeQm,0kpA34UI+C4V2PbfcX%PRA@m`aPG%%jc)@RZ&D)p13!,'fNiF
+PZciINNP$Gq4$-QQSBMl%KjA$"j1QA-d,9ZIj92&#T)0bUH,&5!GYU-lN*IXb3AI
+N"9eYeLE(81p)cZUNM%dF+V*S`HH(G(ppEEdJ*TZ)!J8af858*iM*@jAi26lc`[V
+pH*X+5SANE8dLk`Jm8LhUH@GG4$6hhh2-cF&q)U-Rr-5FG5f`'a[$JfAD&,Th(iD
+$iL0FE40AA@[(k0TE+j[bDZ%i8+lmX4GRHb!H@BT,i(iL@5`N8b9dX%20GBG)35Q
+*)`[9$V06HcNZN@kKFM91p-ck`bf6CJ@C[LQ&ji2&HL5blZ#&Q$ji!F$KFq[YrU*
+66*FAqrah3e&`FDaDCa9)Fh'S8mYMT1'GjYq0+2EHcHe'F(ecLi[EZr8'IfmU0ED
+Mh1`TVQahqAqXHf@CB%marC3,`rpMeHeFl-eh0+TG(h1Xb(06APr[qVGlS5VfCPr
+jekY,pd*KZJp@aZE`8NPYZ,,&k9kS6RFX6hH[2Yd(#p4pX%)Q`LX4&ek0ZRY&kMj
+BTHjBTKZVHmSiqHmpfUZ([6K3RHjdChIX)0CFlDfA98X%FHG&QBY$jFYL&h%3-E-
+,92&)8)RPdS(0NIb+HJHTLCFPlVc+QKKhBGj&!ab0&A"h8S"i+@bP[2ViY6*iF+M
+9f0kD+pXJGV82@H1'SUaAr-VGQ2caUpZEpEP'2E4,iLjfCC)PlZblVbX,',mbL'A
++[@Hfk*5[L&qj'pX#lST'1TbcFkrA8pk9Zr(H*9IQ"Nb3!##j1Pc8Qpfb4q-hZeU
+c"@`cNGS2L6@0LdQ8aBAijABaLAC*[-C9a)A%X-i&a-!Q8j98S@*3NkP+)X6[c8a
+9dQ8R`'*c)NlZ$AqjP$&%2f-m*,8MYL8ImHZNBZd(`dr@6lB[hh'`X0!F`kRNJGh
+ha1i*4(N1"Eqq,&Xk9bEq-(6V)&U$Akp%61`Ud@'*Q)6Fl"A-A@l)ZaYDphC"2)3
+E#)VI2BQBj'#TpkciYHQbJke!3e*A4pZ0ZL3QF4@V51)PANI0T+95!6C$3XG1*,H
+j2'S%lh)APY6k!1%&q"#BM["ca&Sj'4$,kEGP1Q*IPM[KZQF([54hA#9kbBp2"AQ
+*BPG"q,kib(YLr$@lfAYfr3YrMMFcZjZDedh1k'EQj6+@X9NhdB5cTKYP5mrGTQG
+YCEif2RbAmR2-'#HQ"eLcIS+q-@$@#6(K#ZJF$K-1II%Te$flUX9-p4"T@8Z)DC&
+i5*iLq5hU3V,FbQpc&j*P*$Rb%qIEQHFR8k6BQ'-mlMV,i(,X+8r&mTc4alTXL%P
+mY&Fc3G&dK%NV%I&H-h#qDblm0kK1#KI"K4GLmL0XT9iN%BA*Xm+mQ%'b'jTA,$i
+L&R"J@X3i8K*kpm"ib!'(*2CFAK-824DH[!qQGA)61SQTR0#a5Cc3KUq*A@,VbSf
+RSb`-fl*dh*Ehhq'c#q5#"k&[J*!!`)1'J!IGpDXkZiUJ+R4RJHQ'XH'"q9[(AXZ
++QF&M4H[jHE'R`d#A'FbrVR!fRm'1ZdTpfNb`l3Nbfej'4+qVjF85BfL4i!Ierid
+(4X)00k-,#6aJ(ra6H""f4Ki6H+!#(RJ1,EHhRAS2Ba1A%RMJk3FKE!K3a!0lUE-
+60l@`GHVlkXE'*ST(ASfk[AYife4rifLHR#e$kV[hi$[Z1[U1[*P$pKfH"D3hCeE
+i4Je16)`q8[PV19HhfrpCpbIHXAEmQMh(mKJI&!TEbl'fdAPiH1Rd1cE[,REdFcj
+6elEbV@[A,`h3(cXR0`mY$I!1Lc$AlcU+-,i,6qpRhh(6p*&hj,e*NPm-1IGeCai
+"%IZ1r8HlqR6IK``JqB([`8Hm(J-F"6HNlliM&)"CA$ib86RfeX%qSqr0,1Ak4pl
+"YlFe2IY)Mi',eMdM&1!GI(1Q'`aVrV#ZpKhlUppMThEZLRHB!G`IpePff$[cG5d
+p`5KlaNB[2TBRl8C@V2b1dBH4kV[[#!eJJYX[h[KI#*bb95Ym1dCEfjF'U%G)"6-
+G`2+NY9cY(E21A5VJ(Id&qIYhe)$mIlpMN!!422'1'qD1&Z68&cDJ*2b`le&X3JB
+8J)(Z5,ND9[[M-#iB)3([f(1N3`El)elA2EZqMBarril$4pMlB&eMl`J28%L1jMZ
+A#-#c8!#P*Aa#f6LkUr%`AdalFKBq()A#!Gl"0iFQHDDZ1`kqidG0B[@'q$i%a54
+$PTj35%*101A`!!BA+U'pKLXJqHN[krH8q5BYqD%*QY,f9[jT6E$bMR#6kC!!Tc5
+iFRGm6i-lmBiR0EJ6lhK5Jc[jMLFdZ-&hK&*SF29lEpR2"&iNHrc@ekeF1hBUpar
+)([r'IGRM2RA0SET1ZR9p0VlbcK9hR2abiq[hhPCEU%F)J`CADE5R0EM"GcbT`I8
+qi`FDh)Ph2+A"&4m54U$"pHF3rr16l`J&B0bBV!r@,'[%R[p#2l5m-U"p6mZV-TQ
+`!#f[jb%T3VlfSG%YNipd%%`RI'+k+$aJ+LMXC(VQeU--cKKh-VNApr*-I6'Q%ci
+aK@-mYhq-DGilISM!XHQCJ5QF[kY(q-hdc,'P!(`kc@)j#bqX,+k#NrP'ISF4Q)I
+81[ST4R$L(8mbJK2[H",*6llM#53II%Gi!*+(,mc6pGBec''HVY*S6c1#`AFmb3K
+kRr%$4R$L(8pTHF@(a0ia)$1CGpL0P%lJd*(m5*raL"Xk8C6SHdFSJ*E(&b)`,mC
++'08[SGK8%Gqmip$fhGpqarEYZapqKdc[XkCANF)0r4p[&I1+5Sjrm&DT[H2dY-U
+J@Ka#-+hb)`q5'00j`S1NeKrK!@Vk2hKeP1[a2Dq1@Pe2UpHRqjl[5Bq0@MhX1jl
+`aULp3hCeUJc#G5cj-3IR&6LSr02UGH8Gi44cF%pTAP5eGl,K(c@[%qpi8[-kmBi
+R0Dq6lhK#maTm4hM!r0T6@P9[2@)-lLP0TrFG2p"d"YpaNJP@J&@qN!!+Pk4`!#d
+QYAA!d%H")&X(0#DRj0$6,l@HR,H1BmM+&`ShJf5r-lL,$65L0chhr0,pHY+CFbZ
+ZZI[*h+r+6RrarZa(VQXFUZ[%keGRQfjrdiTRAhfAmG'EUTpCU-FCIm8''Xr80Fc
+"YIS-h@8$M4#iVfGbC2LdN5BDpX'm@aQHDcGDaAGpIcI"38KVZ%MSLPeUD-cA-($
+5l-D4UHc!THH(!'-frrR*Di1rG$IFDHRXXJ22I%Efm4qmZ[0f3LEdEFa1(K[HY!@
+RSHZRUS@Z-IG06Qeq)[F268b8cPV[f&b[UISm@XflSXU(L8H2qhLl++Fm2VHK86A
+[ekH3!&(-rmHCa$LDpI@GY,jS`BM9MkjBj+(4HVD+[pH8GrZc-rRlKM,`hZb(q2H
+0XQDcpF&@*j9hFl+ePDc[CmUlml+RmHr&-4p@qQq2GjZcl14ha#IZjY6Bjr,C!*!
+!0A`-k,lrlHYffqX'"P5ejh4QQrhXiM'A)BZpXp2GcX$ZfTk"#rS[')$*(afSYZX
+$5j)dJ%CS-+"SIk%[hmJe3q2VKpG8eU`IR"VNlik4SDNe5kXd3#-l*hKI$![-mN-
+)KrZP60k1-d@B-(P'm2H@P+HG[lHQ2#2jHc$PkH6[SC4R&(m2Tca`cpY5RM(m2C,
+bM1A[dC4R%Rr[6(NQmrHZP!ISZMrPJ5rAaccQUTaR0F&e+Fp'JTY5RNebq90jc)b
+`1M(PkH([JC4R'hr[5AQB+AX6JS'(Kj8mGa2HN!$HFar"Be1HPa!m-Z9jJ1#1P1H
+Pr,dqeI&"`M[6Hhk+i#NTcrd%Mcq@j``)i8[YF0EbD"*NKl2UAJ'KTamlR1'D9E2
+,$MIj3Z0QN!$1j#jf1(ZQVQ%11bHFD96XF&DrpjEpj4k9NlHqEZADX91jrd$fq$I
+ZbalhU@X1eAA5VHZcmC9hVVMMj*FEAlrhYYT#2Fk-AhBiLpiA&3kd#FXePhHkeBI
+dZ*!!K)qp3N*N2SYTCb!)fmVpMiq'!,D9q`UEbrREbRhQCVH91qBfF'(UfmU&ebJ
+-pGRb93GYp@FLe*jcIiS,iaI#8"Zeq1T`Z@hckS'!8"JT[2NHk$E6p(RS([c#"k!
+pqCC,qUlY1h%C5mkj,k5JCbZ2!L8F8X6%N!"5eH`3'cQLkdF[f6DpTekE+&UlYdi
+bZK*G%U"`q[jKM[pAm1+kK6fFQcLhFDlLA-fjNA-,jpfFScR(F)lPR-3jQA-8CbG
+R1fFEj`M1NC`c1'rK[)rc*C`2F,k8md&i01XDARCX,6b6Kh80RjhbG2$hmT5(G3f
+[6(PBer#UP!IalHU8Kh80VdPj@0I`fT4R((q[5hPBer$'P!FamUD8"ijiAmV$91c
+V8KkceQ(NG5N2`emReL%dHFckKj%hT$aQrF2)De)Hl%9HQ2+`rZ%9+3rV(cirjB(
+aI#EPH5(KSe1H&r(h$5Q2@4-aFPh+BpBV2,R@SFPMeMp8I5N2DbGf(FYcjSh`SA2
+!$H&pjQcRl1$Xj"c&1CTcM*`I2JpAKiI$XH(2F'0i,j`@[JSAK4I#qH"cF$9iQ19
+BU686KckD"&NcXES19HMTjiEU&erdX,0`@-NA#MH$C,m`932+-&V$Y-B!KXm`2XY
+d3L(S6ZScQaX0f65qDA"XZ(pifcG`hNlH@[CVrXMrV*d4,hRb`C%$R(rqD1jLEG2
+S6Fmp[p3"*jdjYq+DZjr-rDVXp"I[chlNZXDKZNkmIR@fkIBhVAMfeAFC(lfTqTQ
+&HTca9kaYqNaG`aa@[6XMGeREp!`%BCR0,5b`bFFbQlZZ[AHCcBh2F*R0SfmR*,a
+NQFd`Qp8G)kG2GQYZmm,-c0&@)lp[QM@ffCieRq+NdbllNb83DK0HYlTM+!`'K-4
+mBET,iRA'T461l"1B8qN,SpMX08aJ1BNcq35qH(+YNc2["8BCEX)+``MH-j(c#h&
+$V5r'kGqrF#mpmhdTX[-[Pa[c4V)[aXlkDScrbh#[IMM'I5h'ICeYfIRqUTaBMQ4
+ha[ar(E[UEf+qEf52+IrrEAcR0m0rY6UqkqciIhVm2b2Qr9CmclGMh-3BpeKmrq1
+aMYm*HEb1#G9P8Q&RAi`(0@qmZ$AEV'%T9NaNA38`46*XLSdP[c1rG@66qZCXB`N
+!"l,3d!r"+DA6%f#$E(4LU6FAP2P#!0Ce-kqUVrDhC[r[%H"mcf$T31-@KJSGk*2
+HZc1lK1q-*81&5Ba0Kq'S-'Gf#9p)mIa,b)ZbmVekrYqlm,E[c(3"!cc"4B`(*55
+FaVR90SPDJ3fI$!,92Y4HqDVf`#@a+a`#&d*PqMl4UfG5%MJCl`SDZCd6Kfq'mh(
+%EZ$%+4ZAl$'FZ(@c-eJ(j`M1PSJ&Z(HhFJlPC0q`8C`iGSrN(-[Cb6PZ+BIb[Qf
+1lESL-jhZi9hIM[eUPUdf,MdK1KERmk('(6cF*M2j-j1iQqm0Dq"p)q2lkQlV"AD
+r`VE`hZI(+4E5Uir[mq0QdLI0qfHkjHD1#D4U)&rN,Z,BBM)4erK-rR60G$Z(mc@
+k$CV8bArIX"qMc@I2Y$Z(ihEF4)[[RHRZ2&bR4VCDLjc+ZkPhiRe0lqI2Vmed'ke
+liaEZ*IqULG&10e[q"AGIQacL1Rq$2h2+AGEU2[3HlXi,F3HI$p4X#R([(65(&cI
+bAm8J,qjAAX$Gh""hP(k0V!jahcR("T2hI8aFmZ)qi@k$bf+q4rRc8"NAIHSRZ9X
+Hqjlpe6D(I!ql41D+%0IbjX9q5K#ECc1('1[,4&bcZ9eI*Z)Dpbhf65+ZjAf,IC1
+)fr2V[IlirFZiNeeqphbdeam(a9AC$(1IQ#Vpm4XIjUiRa"e`efhTM`FrapeP-Hj
+RH[eal58@91*H[G!IGDqmNl[,Ber5Rejr4+IXb5Y#A)Fpj08TqT+riNj`m"G@,p3
+THVUB)CZUYPqd8+IS#phD8RC,I35mP$T&Alk&ZcXLlKVmN!!k45rl-qi-2YKm2pI
+Vil2&0[+$kp4'k[4+0d58h9mll$q[6[T*Rq)12+&pIRDK6VV2A[pfL"[bSB8kkCF
+kFrTBL*Yaad+Gp-@rc0hMXBrT6kp1H[LVh*PGk[L@[R1K6ZV2k5d(MGeLQeFRYCq
+P&Kh$(Q+0Qd,rIH9hL9XCFAU5A-UVklV2%bFlZcA*2b6IPrqCZ+YM(*[SHIRUAJY
+h8qAZGbD1hHfmI0'9p*EbAB5mTjI[VKF6*cMG4"p,(far#RdJHq"&6KBc[,KYY3Z
+)Hh1Xhk[i-cA8pHh'I65q!kiRrG&XAF&R)2'qKIl3,`*Ve0q%Z+%Z-1ReKci$6U6
+q0[)!qY*lRck0RPIr&2[l&EhhcB5R+V',IUAZdRm["`m82@*j#FZmbIZ@`@r99b*
+1rc*raT9aNAH!P9VqDm,(mGDfDd2FErdLFI"Gmld+rY%3qLEb02L`PYqDI,2Jah0
+[$A&AITBiq+lj4T!!3adIiUk&HfKj-Hrq2B[VaGh`am5"lF4pDU'ZN5IF5KbFQcJ
+ifA$MMXrrfpR%JIrJUhQ61LlNqp3r%LFFZdQHXc,%(3*lY([rm3lUEYpKS28"iLC
+%r[3R[%0f$A`aNp[DA4piKmNK1"(jrp4'4r`B$BG6TiDii@ka*rJa",i5Z6$%IC'
+HeR'Rf(fmThiLe1qVD!Mk#5(ZY@q&,lD(I!rF6Gc8%0FU"lSqa+hm#q+Q44b#-bd
+*F4I6NeUmSNlS&F0Lhm`Qc[5)M3-RT-q@fdr6Babm6ITXrkZ*NfA[4UTcr(D)H`p
+[dq+YqFj'$e"RKEK4p,D@Hj)2h(mia!eP0d)0[lCi4RpErR&mrN[`84ehqecm,Zk
+NRbDq4#iZIB-Z)6Md+*a@"hkXR[A&(Jlp+9a,"hkXpVb`Kd26fDT9"hkXpY+[$SI
+Qd%-kEUJi(plTF1J&Vb,1B,AY*lLAp-HGRb"Z3Dc(bhVpd3'2e%q*G@9h4-'26R"
+D2cA%E8,RF$Kd%Ea(Xd1LlH0hpA$SCA"F(IF5(UDZ*1qiiUA%A4$L0X06(3jp4*b
+!2e)RH+h8qe*Lp)q(Z0Ir83q(ERdpFD)(Y)Q$JN-cl$p2$e$Ai4cLiC!!@9'$r[$
+d!(8pQaFk(2ShD"XkkJ&M`"k(3epq*A(#cpVNiB*$M@#"M[bXaIF,$Mh(ZSTr3E[
+i+(dfrAELi)1d'$a-qZc2i-BkEPSl(ClUF1Kcm%XGYdImHIL3!-1KYlfE10Q%GXQ
+024cDLGDLikSI(El(im'4#ATBK`eXe9XqeX1Kc3HiJpp42rLcdcqmc6PX[VGm'Fc
+m303riR'40kZ2I6VU(iQi$KeDR2i4Mp1VA(GiAp3r%[R'LSq#IbhL)VU@HIH[`9m
+GrVd@(Up(3Yb(U+Z(ImIRri%lc@k5a2hqTKlqADA@*6V+'cl6`lpAQdpdP!jjTr6
+P#ML%MMV+-(QGlF[MmhI"QcA[XR@LVi5(I84H*AZd[J9mF[MhN!$i,FXr,j!![`V
+qAB9fSXXG+mdlf#YIm1qem'1p1G6[@q#T`lqAL+qbIhi,f1EKhr(j[r`)FHKA*Y9
+MD+`1rqTrMMM`h(a,h5&6m'mY'S'@6jP8Mm2I(!rl@lL3!0iDqV*1(9,`le+iVik
+kdI9I1SKraqFr)$m6h@L2pE,iGhcqGM"H4peS*(c&iGp9k-3kkNB,ZA0pGJ303$m
+RpJ&i)(hfQ(Km9BKlUhJLq(H*20[61I4ap+Z(ImIRhb0HHMU(2PiG3["[S4a,&SF
+p+Mm8([B&qEfhEV-q!9cfm1rir#I4)(6Fd,VeAaEa,llITPi&$fLk,H*I)Zj4GCc
+24[b,ad9'hD$@i9mLhbKU%m1r4,iMERlTi9rG(iKcKYq4Ec3mAr![qMbd62fL%$I
+M,3[mVqjkZ)F15f[VTi'TJRpe0mK6Aa$LKS"hJRr4Xq`ESrPBR(MP3Pp'XlmMcQ#
+[VCr*iI6#0m+9pG8acR!D`DhSFm3RlXhI&R"+m#pk$KLKeAQS+hUKKhr4&k$&k*G
+&r%"AN!"hX$QT$MU62NqYb-1rZLqK9HMr&h%DMG29qeH*)cqdefJcJRr4R`!l0$c
+8pMhij1&Ip!`d"5fI0Arh`Q@&rp@pPEN'$DFMEYk[,H"Ih4[T-Id,i4e[**r`[qK
+b0!r0HrRHl2XprKGYJR&DcC0hdbFHrNA24[[3kUl`*(L&p0RH$a,h81`$F%[dc[2
+3ZE@m$lS06RMi&jeKGe-0CbGZ2ca@q&rGAm1400S&FEI)%ccmLfk&BfYe$qU%rLf
+kmLr"bEAp6MkMK`VrUrX!ZE9e-(m2fK1HAKKj#4LQj4hQlf&Q1qSLRhL1ld!,jAe
+SXCiq&aN&Fl9kX[NHNFm,hSpr'h(SYm6"ai6RAI%QiPi6hMId$rRRkAD4[@J6@Th
+Ir$hI2[0dZmLBZSlT8q+1bVfN6S[S#DhHDrlH$MpdGET'r[(kq!jd5DR6@,LG9Qq
+(ek+h5CfDj8RHRUakcXehT%j[KPYVDQAMk$HTdb'iR9C$0Rr[kZQ,NBYqM`"2(p9
+AbKfP6K2JkYSj#22hERLfUe1RrIe`L,Z(A[(UC2LCd@)d1'rj4a`r)Um'1c5kQFh
+h"ldkGGe-!2Q*-jcHeHQ2k@hY,!Ed!Aj[kh4mrJjjfb-alS1p1Vd0E8@(29reci0
+9VNl23S28kY[d2Ea3k[40Z,j@4b81RLae@Lm2"XISEhLMe1R6B)%11mAUUpACT8k
+[&+F0YK2h)R&@qZNAdBVdlm3q0K`dFXS-HjV(Z40apkR(I@QQHYr'fir)JcfFDhi
+E'V5'Aj!!lhki8AfSGr-Pe%kMT4$h-R6+ZX!2QRm*,926bm3pf01IQYk2VUc9YBL
+MRlak0rmQ'V4fYS8iH-A9)@kRZLNk$h(`L6H'Z!I%!h!2qN#pjAh[rJ)"4YHbF3C
+2ACeZG6NKG"jJhf#'e+RTYp'U0"SbFDp5(jGk2b`rH(q-3kH81Xf#NqL`DDaq[EU
+fe1P+HPZr0mBaKq(9UHNVmM0i",#2VLh[Hm"h'pb`F8E2P6SeI36Xdmie!0HQ,ed
+rrD5D%r-[`#pp)rAq1*U)GTk)12LN9kHQVm)9p3GL($c%Ue26qq3I[a[MQ,f3!$T
+p5pd4[3iHKQiZGCU#4U$9Bi(hH$mel9HI0[K'h-1pIQVq@IX!hBCh`0qN6Tm8bm&
+Em!bq,rh8U2i02`9qk6qTdjqM9@Zd'Z,HUZiMIIm+Z)K@*`GqdF'ppcAHBTfBU5%
+1r9IH[3*ZS1NG'iIZ+A'2q1k24(k*VL&a9cPRi-eKk0qbYlbjMBEIK`2V-)HKhiP
+1*('0Tk(Yk6#(SGmPGjGmAd-ld'%13pmJYjDicm*&0&SaFEr1ZpAji4hhUQ-C$B'
+iGpJhZd2F,(NB1J"aCMBLmUS3plKkkLG#h$["!q(aM4H+LfBHMEKh`IrGqckYR[(
+*%2GZF9EHph*a&ai(c$+(+1qE3UpUjKTXR1'"lRdcl32$PBKl,rc%[HpCkVl-#J'
+rr*IhVD8(p+G$h2[8YH9pCm%4p5dacZ#1Hpm'iicH50a[dJrZIBqTVe0ri*Fj5RR
+I+p&H0E-*0Jlp5plh#E"!bq1)-h0)lRd2b*rXM0lr"`#3!edP!!!:
diff --git a/macos/osdep.h b/macos/osdep.h
new file mode 100644
index 0000000..5a69033
--- /dev/null
+++ b/macos/osdep.h
@@ -0,0 +1,118 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __MACOS_OSDEP_H
+#define __MACOS_OSDEP_H 1
+
+#ifndef MACOS
+# define MACOS
+#endif
+
+
+#include <setjmp.h>
+#include <types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unix.h>
+#include <unistd.h>
+#include <console.h>
+
+#include <Errors.h>
+#include <Files.h>
+
+#include "unixlike.h"
+#include "macglob.h"
+
+#define NO_MKTEMP 1
+#define PASSWD_FROM_STDIN 1
+#define NO_SYMLINKS 1
+
+#define USE_ZIPMAIN 1
+
+#define USE_CASE_MAP 1 /* case_map is used to ignore case in comparisons */
+
+
+
+
+/*
+#define DEBUG_TIME
+ */
+
+#if (!defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME))
+# define USE_EF_UT_TIME
+#endif
+
+#undef IZ_CHECK_TZ
+
+#ifndef ZP_NEED_MEMCOMPR
+# define ZP_NEED_MEMCOMPR
+#endif
+
+
+#define EXDEV 18
+
+#define PATHCUT ':'
+
+
+/* file operations use "b" for binary */
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+/*
+#define DEBUG
+*/
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c) */
+#undef getc
+#undef getchar
+#undef putchar
+
+
+
+void setfiletype(char *file, unsigned long Creator, unsigned long Type);
+
+char *GetZipVersionsInfo(void);
+char *GetZipVersionLocal(void);
+char *GetZipCopyright(void);
+
+void InitAllVars(void);
+
+void PrintFileInfo(void);
+
+
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+int macgetch(void);
+
+
+int MacOpen(const char *path,int oflag,...);
+FILE *MacFopen(const char *path,const char *mode);
+#define fopen(path, mode) MacFopen(path, mode)
+#define open(path, oflag) MacOpen(path, oflag)
+
+
+char *GetComment(char *filename);
+int readlink(char *path, char *buf, int size);
+
+void PrintStatProgress(char *msg);
+void InformProgress(const long progressMax, const long progressSoFar );
+void ShowCounter(Boolean reset);
+void leftStatusString(char *status);
+
+
+
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#endif /* __MACOS_OSDEP_H */
diff --git a/macos/readme.1st b/macos/readme.1st
new file mode 100644
index 0000000..6182756
--- /dev/null
+++ b/macos/readme.1st
@@ -0,0 +1,16 @@
+This port is for Mac versions before Mac OS X. As Mac OS X is build on Unix,
+use the Unix port for Mac OS X. - 7 June 2008
+
+
+Before you start:
+
+Extract "*.hqx" and "source:*.hqx" first and read the Readme.txt.
+
+The resource file and the compiler project files are in BinHex form because
+they contain Macintosh resource forks and as such can not be simply
+stored a normal file on a non-Macintosh system. BinHex form is the
+traditional way for transferring such files via non-Macintosh systems.
+It's also the safest since it uses only printable characters. The ".hqx"
+files must be converted with StuffitExpander or BinHex 4.0 (or equivalent)
+on a Macintosh system before using them.
+
diff --git a/macos/source/VolWarn.h b/macos/source/VolWarn.h
new file mode 100644
index 0000000..2d921eb
--- /dev/null
+++ b/macos/source/VolWarn.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+
+This is an Important note about pathnames
+
+*/
+
+static char DuplicVolumeNote[] = {
+ "\rIMPORTANT NOTE:" \
+ "\r" \
+ "\r This port has one weak point: It is based on pathnames !! " \
+ "\r Because it's a port !! Unlike MacOS: As far as I know all other "\
+ "\r Operatingsystems (eg.: Unix, DOS, OS/2, ...) are based on pathnames" \
+ "\r " \
+ /* a short quote from "Inside Macintintosh, Files"; slightly modified by me */
+ "\r On a Mac: Files and directories located in the same directory " \
+ "\r must all have unique names. However, there is no requirement " \
+ "\r that volumes have unique names. It is perfectly acceptable for two mounted" \
+ "\r volumes to have the same name. This is one reason why a application should " \
+ "\r use volume reference numbers rather than volume names to specify volumes," \
+ "\r but for this Zip-Port I can't use reference numbers. " \
+ "\r " \
+ /* end quote */
+ "\r" \
+ "\r From the developers point of view:"\
+ "\r The use of pathnames, however, is highly discouraged. If the user changes"\
+ "\r names or moves things around, they are worthless." \
+ "\r Full pathnames are particularly unreliable as a means of identifying files," \
+ "\r directories or volumes within your application," \
+ "\r for two primary reasons:" \
+ "\r" \
+ "\r* The user can change the name of any element in the path at" \
+ "\r virtually any time." \
+ "\r* Volume names on the Macintosh are *not* unique. Multiple" \
+ "\r mounted volumes can have the same name. For this reason, the use of" \
+ "\r a full pathname to identify a specific volume may not produce the" \
+ "\r results you expect. If more than one volume has the same name and" \
+ "\r a full pathname is used, the File Manager currently uses the first" \
+ "\r mounted volume it finds with a matching name in the volume queue." \
+ "\r" \
+ "\r" \
+ "\r The main reason is that an attempt to implement support exact saving of" \
+ "\r the MacOS specific internal file-structures would require a throughout" \
+ "\r rewrite of major parts of shared code, probably sacrifying compatibility" \
+ "\r with other systems." \
+ "\r I have no solution at the moment. The port will just warn you if you try" \
+ "\r zip from / to a volume which has a duplicate name." \
+ "\r MacZip has problems to find the archives and files." \
+ "\r" \
+ "\r" \
+ "\r ... and the moral of this story:" \
+ "\r" \
+ "\r Don't mount multiple volumes with the same " \
+ "\r name while zip/unzip is running" \
+ "\r and "\
+ "\r My (Big) recommendation: Name all your volumes with a unique name "\
+ "\r (e.g: add a space character to the name) and" \
+ "\r MacZip will run without any problem." \
+ "\r" \
+ "\r" \
+ "\r Dirk Haase" \
+ };
diff --git a/macos/source/charmap.h b/macos/source/charmap.h
new file mode 100644
index 0000000..5656b63
--- /dev/null
+++ b/macos/source/charmap.h
@@ -0,0 +1,380 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __macos_charmap_h
+#define __macos_charmap_h
+
+/*
+
+Conversion table from MacOS Roman to
+"Western Europe & America" Windows codepage 1252
+
+ Notes on Mac OS Roman:
+ ----------------------
+
+ Mac OS Roman character set is used for at least the following Mac OS
+ localizations: U.S., British, Canadian French, French, Swiss
+ French, German, Swiss German, Italian, Swiss Italian, Dutch,
+ Swedish, Norwegian, Danish, Finnish, Spanish, Catalan,
+ Portuguese, Brazilian, and the default International system.
+
+ Not every char of the charset MacRoman has their equivalent
+ in Windows CodePage1252.
+ To make the mapping in most cases possible, I choosed
+ most similar chars or at least the BULLET. Chars that
+ do not have a direct match are marked with '***'
+
+ The Windows codepage 1252 contains the ISO 8859-1 "Latin 1" codepage,
+ with some additional printable characters in the range (0x80 - 0x9F),
+ that is reserved to control codes in the ISO 8859-1 character table.
+
+In all Mac OS encodings, character codes 0x00-0x7F are identical to ASCII
+
+*/
+
+
+
+ZCONST unsigned char MacRoman_to_WinCP1252[128] = {
+/* Win CP1252 UniCode UniCode Names */
+ 0xC4 , /* 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS */
+ 0xC5 , /* 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE */
+ 0xC7 , /* 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA */
+ 0xC9 , /* 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE */
+ 0xD1 , /* 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE */
+ 0xD6 , /* 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS */
+ 0xDC , /* 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS */
+ 0xE1 , /* 0x00E1 #LATIN SMALL LETTER A WITH ACUTE */
+ 0xE0 , /* 0x00E0 #LATIN SMALL LETTER A WITH GRAVE */
+ 0xE2 , /* 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ 0xE4 , /* 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS */
+ 0xE3 , /* 0x00E3 #LATIN SMALL LETTER A WITH TILDE */
+ 0xE5 , /* 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE */
+ 0xE7 , /* 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA */
+ 0xE9 , /* 0x00E9 #LATIN SMALL LETTER E WITH ACUTE */
+ 0xE8 , /* 0x00E8 #LATIN SMALL LETTER E WITH GRAVE */
+ 0xEA , /* 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ 0xEB , /* 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS */
+ 0xED , /* 0x00ED #LATIN SMALL LETTER I WITH ACUTE */
+ 0xEC , /* 0x00EC #LATIN SMALL LETTER I WITH GRAVE */
+ 0xEE , /* 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ 0xEF , /* 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS */
+ 0xF1 , /* 0x00F1 #LATIN SMALL LETTER N WITH TILDE */
+ 0xF3 , /* 0x00F3 #LATIN SMALL LETTER O WITH ACUTE */
+ 0xF2 , /* 0x00F2 #LATIN SMALL LETTER O WITH GRAVE */
+ 0xF4 , /* 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ 0xF6 , /* 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS */
+ 0xF5 , /* 0x00F5 #LATIN SMALL LETTER O WITH TILDE */
+ 0xFA , /* 0x00FA #LATIN SMALL LETTER U WITH ACUTE */
+ 0xF9 , /* 0x00F9 #LATIN SMALL LETTER U WITH GRAVE */
+ 0xFB , /* 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ 0xFC , /* 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS */
+ 0x86 , /* 0x2020 #DAGGER */
+ 0xB0 , /* 0x00B0 #DEGREE SIGN */
+ 0xA2 , /* 0x00A2 #CENT SIGN */
+ 0xA3 , /* 0x00A3 #POUND SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 #BULLET */
+ 0xB6 , /* 0x00B6 #PILCROW SIGN */
+ 0xDF , /* 0x00DF #LATIN SMALL LETTER SHARP S */
+ 0xAE , /* 0x00AE #REGISTERED SIGN */
+ 0xA9 , /* 0x00A9 #COPYRIGHT SIGN */
+ 0x99 , /* 0x2122 #TRADE MARK SIGN */
+ 0xB4 , /* 0x00B4 #ACUTE ACCENT */
+ 0xA8 , /* 0x00A8 #DIAERESIS */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xC6 , /* 0x00C6 #LATIN CAPITAL LETTER AE */
+ 0xD8 , /* 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xB1 , /* 0x00B1 #PLUS-MINUS SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x00A5 #YEN SIGN */
+ 0xB5 , /* 0x00B5 #MICRO SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xAA , /* 0x00AA #FEMININE ORDINAL INDICATOR */
+ 0xBA , /* 0x00BA #MASCULINE ORDINAL INDICATOR */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xE6 , /* 0x00E6 #LATIN SMALL LETTER AE */
+ 0xF8 , /* 0x00F8 #LATIN SMALL LETTER O WITH STROKE */
+ 0xBF , /* 0x00BF #INVERTED QUESTION MARK */
+ 0xA1 , /* 0x00A1 #INVERTED EXCLAMATION MARK */
+ 0xAC , /* 0x00AC #NOT SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x83 , /* 0x0192 #LATIN SMALL LETTER F WITH HOOK */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xAB , /* 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0xBB , /* 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0x85 , /* 0x2026 #HORIZONTAL ELLIPSIS */
+ 0xA0 , /* 0x00A0 #NO-BREAK SPACE */
+ 0xC0 , /* 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE */
+ 0xC3 , /* 0x00C3 #LATIN CAPITAL LETTER A WITH TILDE */
+ 0xD5 , /* 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x96 , /* 0x2013 #EN DASH */
+ 0x97 , /* 0x2014 #EM DASH */
+ 0x93 , /* 0x201C #LEFT DOUBLE QUOTATION MARK */
+ 0x94 , /* 0x201D #RIGHT DOUBLE QUOTATION MARK */
+ 0x91 , /* 0x2018 #LEFT SINGLE QUOTATION MARK */
+ 0x92 , /* 0x2019 #RIGHT SINGLE QUOTATION MARK */
+ 0xF7 , /* 0x00F7 #DIVISION SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xFF , /* 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS */
+ 0x9F , /* 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xA4 , /* 0x00A4 #CURRENCY SIGN */
+ 0x8B , /* 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+ 0x9B , /* 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x87 , /* 0x2021 #DOUBLE DAGGER */
+ 0xB7 , /* 0x00B7 #MIDDLE DOT */
+ 0x82 , /* 0x201A #SINGLE LOW-9 QUOTATION MARK */
+ 0x84 , /* 0x201E #DOUBLE LOW-9 QUOTATION MARK */
+ 0x89 , /* 0x2030 #PER MILLE SIGN */
+ 0xC2 , /* 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ 0xCA , /* 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ 0xC1 , /* 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE */
+ 0xCB , /* 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS */
+ 0xC8 , /* 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE */
+ 0xCD , /* 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE */
+ 0xCE , /* 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ 0xCF , /* 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS */
+ 0xCC , /* 0x00CC #LATIN CAPITAL LETTER I WITH GRAVE */
+ 0xD3 , /* 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE */
+ 0xD4 , /* 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xD2 , /* 0x00D2 #LATIN CAPITAL LETTER O WITH GRAVE */
+ 0xDA , /* 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE */
+ 0xDB , /* 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ 0xD9 , /* 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x88 , /* 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT */
+ 0x98 , /* 0x02DC #SMALL TILDE */
+ 0xAF , /* 0x00AF #MACRON */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xB8 , /* 0x00B8 #CEDILLA */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 /* 0x2022 # *** BULLET */
+ };
+
+
+
+ZCONST unsigned char WinCP1252_to_MacRoman[128] = {
+/* Mac Roman UniCode UniCode Names */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xE2 , /* 0x201A # SINGLE LOW-9 QUOTATION MARK */
+ 0xC4 , /* 0x0192 # LATIN SMALL LETTER F WITH HOOK */
+ 0xE3 , /* 0x201E # DOUBLE LOW-9 QUOTATION MARK */
+ 0xC9 , /* 0x2026 # HORIZONTAL ELLIPSIS */
+ 0xA0 , /* 0x2020 # DAGGER */
+ 0xE0 , /* 0x2021 # DOUBLE DAGGER */
+ 0xF6 , /* 0x02C6 # MODIFIER LETTER CIRCUMFLEX ACCENT */
+ 0xE4 , /* 0x2030 # PER MILLE SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xDC , /* 0x2039 # SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xD4 , /* 0x2018 # LEFT SINGLE QUOTATION MARK */
+ 0xD5 , /* 0x2019 # RIGHT SINGLE QUOTATION MARK */
+ 0xD2 , /* 0x201C # LEFT DOUBLE QUOTATION MARK */
+ 0xD3 , /* 0x201D # RIGHT DOUBLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # BULLET */
+ 0xD0 , /* 0x2013 # EN DASH */
+ 0xD1 , /* 0x2014 # EM DASH */
+ 0xF7 , /* 0x02DC # SMALL TILDE */
+ 0xAA , /* 0x2122 # TRADE MARK SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xDD , /* 0x203A # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xD9 , /* 0x0178 # LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ 0xCA , /* 0x00A0 # NO-BREAK SPACE */
+ 0xC1 , /* 0x00A1 # INVERTED EXCLAMATION MARK */
+ 0xA2 , /* 0x00A2 # CENT SIGN */
+ 0xA3 , /* 0x00A3 # POUND SIGN */
+ 0xDB , /* 0x00A4 # CURRENCY SIGN */
+ 0xB4 , /* 0x00A5 # YEN SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xAC , /* 0x00A8 # DIAERESIS */
+ 0xA9 , /* 0x00A9 # COPYRIGHT SIGN */
+ 0xBB , /* 0x00AA # FEMININE ORDINAL INDICATOR */
+ 0xC7 , /* 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0xC2 , /* 0x00AC # NOT SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA8 , /* 0x00AE # REGISTERED SIGN */
+ 0xF8 , /* 0x00AF # MACRON */
+ 0xA1 , /* 0x00B0 # DEGREE SIGN */
+ 0xB1 , /* 0x00B1 # PLUS-MINUS SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xAB , /* 0x00B4 # ACUTE ACCENT */
+ 0xB5 , /* 0x00B5 # MICRO SIGN */
+ 0xA6 , /* 0x00B6 # PILCROW SIGN */
+ 0xE1 , /* 0x00B7 # MIDDLE DOT */
+ 0xFC , /* 0x00B8 # CEDILLA */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xBC , /* 0x00BA # MASCULINE ORDINAL INDICATOR */
+ 0xC8 , /* 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xC0 , /* 0x00BF # INVERTED QUESTION MARK */
+ 0xCB , /* 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE */
+ 0xE7 , /* 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE */
+ 0xE5 , /* 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ 0xCC , /* 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE */
+ 0x80 , /* 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS */
+ 0x81 , /* 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE */
+ 0xAE , /* 0x00C6 # LATIN CAPITAL LETTER AE */
+ 0x82 , /* 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA */
+ 0xE9 , /* 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE */
+ 0x83 , /* 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE */
+ 0xE6 , /* 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ 0xE8 , /* 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS */
+ 0xED , /* 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE */
+ 0xEA , /* 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE */
+ 0xEB , /* 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ 0xEC , /* 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0x84 , /* 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE */
+ 0xF1 , /* 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE */
+ 0xEE , /* 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE */
+ 0xEF , /* 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ 0xCD , /* 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE */
+ 0x85 , /* 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xAF , /* 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE */
+ 0xF4 , /* 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE */
+ 0xF2 , /* 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE */
+ 0xF3 , /* 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ 0x86 , /* 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA7 , /* 0x00DF # LATIN SMALL LETTER SHARP S */
+ 0x88 , /* 0x00E0 # LATIN SMALL LETTER A WITH GRAVE */
+ 0x87 , /* 0x00E1 # LATIN SMALL LETTER A WITH ACUTE */
+ 0x89 , /* 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ 0x8B , /* 0x00E3 # LATIN SMALL LETTER A WITH TILDE */
+ 0x8A , /* 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS */
+ 0x8C , /* 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE */
+ 0xBE , /* 0x00E6 # LATIN SMALL LETTER AE */
+ 0x8D , /* 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA */
+ 0x8F , /* 0x00E8 # LATIN SMALL LETTER E WITH GRAVE */
+ 0x8E , /* 0x00E9 # LATIN SMALL LETTER E WITH ACUTE */
+ 0x90 , /* 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ 0x91 , /* 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS */
+ 0x93 , /* 0x00EC # LATIN SMALL LETTER I WITH GRAVE */
+ 0x92 , /* 0x00ED # LATIN SMALL LETTER I WITH ACUTE */
+ 0x94 , /* 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ 0x95 , /* 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0x96 , /* 0x00F1 # LATIN SMALL LETTER N WITH TILDE */
+ 0x98 , /* 0x00F2 # LATIN SMALL LETTER O WITH GRAVE */
+ 0x97 , /* 0x00F3 # LATIN SMALL LETTER O WITH ACUTE */
+ 0x99 , /* 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ 0x9B , /* 0x00F5 # LATIN SMALL LETTER O WITH TILDE */
+ 0x9A , /* 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS */
+ 0xD6 , /* 0x00F7 # DIVISION SIGN */
+ 0xBF , /* 0x00F8 # LATIN SMALL LETTER O WITH STROKE */
+ 0x9D , /* 0x00F9 # LATIN SMALL LETTER U WITH GRAVE */
+ 0x9C , /* 0x00FA # LATIN SMALL LETTER U WITH ACUTE */
+ 0x9E , /* 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ 0x9F , /* 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xD8 /* 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS */
+ };
+
+
+/*
+
+The following characters has no equivalent
+to each other:
+
+MacCodes
+164 0xA4 0x00A7 # SECTION SIGN
+253 0xFD 0x02DD # DOUBLE ACUTE ACCENT
+189 0xBD 0x03A9 # GREEK CAPITAL LETTER OMEGA
+185 0xB9 0x03C0 # GREEK SMALL LETTER PI
+255 0xFF 0x02C7 # CARON
+249 0xF9 0x02D8 # BREVE
+250 0xFA 0x02D9 # DOT ABOVE
+251 0xFB 0x02DA # RING ABOVE
+254 0xFE 0x02DB # OGONEK
+218 0xDA 0x2044 # FRACTION SLASH
+182 0xB6 0x2202 # PARTIAL DIFFERENTIAL
+198 0xC6 0x2206 # INCREMENT
+184 0xB8 0x220F # N-ARY PRODUCT
+183 0xB7 0x2211 # N-ARY SUMMATION
+195 0xC3 0x221A # SQUARE ROOT
+176 0xB0 0x221E # INFINITY
+186 0xBA 0x222B # INTEGRAL
+197 0xC5 0x2248 # ALMOST EQUAL TO
+173 0xAD 0x2260 # NOT EQUAL TO
+178 0xB2 0x2264 # LESS-THAN OR EQUAL TO
+179 0xB3 0x2265 # GREATER-THAN OR EQUAL TO
+215 0xD7 0x25CA # LOZENGE
+240 0xF0 0xF8FF # Apple logo
+222 0xDE 0xFB01 # LATIN SMALL LIGATURE FI
+223 0xDF 0xFB02 # LATIN SMALL LIGATURE FL
+245 0xF5 0x0131 # LATIN SMALL LETTER DOTLESS I
+206 0xCE 0x0152 # LATIN CAPITAL LIGATURE OE
+207 0xCF 0x0153 # LATIN SMALL LIGATURE OE
+
+WinCodes
+129 0x81 #UNDEFINED
+141 0x8D #UNDEFINED
+143 0x8F #UNDEFINED
+144 0x90 #UNDEFINED
+157 0x9D #UNDEFINED
+167 0xA7 0x00A7 #SECTION SIGN
+173 0xAD 0x00AD #SOFT HYPHEN
+178 0xB2 0x00B2 #SUPERSCRIPT TWO
+179 0xB3 0x00B3 #SUPERSCRIPT THREE
+185 0xB9 0x00B9 #SUPERSCRIPT ONE
+188 0xBC 0x00BC #VULGAR FRACTION ONE QUARTER
+189 0xBD 0x00BD #VULGAR FRACTION ONE HALF
+190 0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS
+208 0xD0 0x00D0 #LATIN CAPITAL LETTER ETH
+215 0xD7 0x00D7 #MULTIPLICATION SIGN
+221 0xDD 0x00DD #LATIN CAPITAL LETTER Y WITH ACUTE
+222 0xDE 0x00DE #LATIN CAPITAL LETTER THORN
+240 0xF0 0x00F0 #LATIN SMALL LETTER ETH
+253 0xFD 0x00FD #LATIN SMALL LETTER Y WITH ACUTE
+254 0xFE 0x00FE #LATIN SMALL LETTER THORN
+140 0x8C 0x0152 #LATIN CAPITAL LIGATURE OE
+156 0x9C 0x0153 #LATIN SMALL LIGATURE OE
+138 0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON
+154 0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON
+142 0x8E 0x017D #LATIN CAPITAL LETTER Z WITH CARON
+158 0x9E 0x017E #LATIN SMALL LETTER Z WITH CARON
+128 0x80 0x20AC #EURO SIGN
+166 0xA6 0x00A6 #BROKEN BAR
+
+
+*/
+
+
+
+
+#endif /* !__macos_charmap_h */
diff --git a/macos/source/extrafld.c b/macos/source/extrafld.c
new file mode 100644
index 0000000..a2efcdb
--- /dev/null
+++ b/macos/source/extrafld.c
@@ -0,0 +1,920 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ extrafld.c
+
+ contains functions to build extra-fields.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <sound.h>
+#include "zip.h"
+#include "unixlike.h"
+#include "helpers.h"
+#include "pathname.h"
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'MAC3' extra field to the zlist data pointed to by z. */
+/* This is the (new) Info-zip extra block for Macintosh */
+#define EB_MAC3_HLEN 14 /* fixed length part of MAC3's header */
+#define EB_L_MAC3_FINFO_LEN 52 /* fixed part of MAC3 compressible data */
+
+#define EB_MAX_OF_VARDATA 1300 /* max possible datasize */
+
+#define EB_L_MAC3_SIZE (EB_HEADSIZE + EB_MAC3_HLEN)
+#define EB_C_MAC3_SIZE (EB_HEADSIZE + EB_MAC3_HLEN)
+
+/* maximum memcompress overhead is the sum of the compression header length */
+/* (6 = ush compression type, ulg CRC) and the worstcase deflate overhead */
+/* when uncompressible data are kept in 2 "stored" blocks (5 per block = */
+/* byte blocktype + 2 * ush blocklength) */
+#define MEMCOMPRESS_OVERHEAD (EB_MEMCMPR_HSIZ + EB_DEFLAT_EXTRA)
+
+#define EB_M3_FL_COMPRESS 0x00
+#define EB_M3_FL_DATFRK 0x01 /* data is data-fork */
+#define EB_M3_FL_NOCHANGE 0x02 /* filename will be not changed */
+#define EB_M3_FL_UNCMPR 0x04 /* data is 'natural' (not compressed) */
+#define EB_M3_FL_TIME64 0x08 /* time is coded in 64 bit */
+#define EB_M3_FL_NOUTC 0x10 /* only 'local' time-stamps are stored */
+
+
+#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+
+/* disable compressing of extra field
+#define MAC_EXTRAFLD_UNCMPR */
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'JLEE' extra field to the zlist data pointed to by z. */
+/* This is the (old) Info-zip resource-fork extra block for Macintosh
+(last Revision 1996-09-22) Layout made by Johnny Lee, Code made by me :-) */
+#define EB_L_JLEE_LEN 40 /* fixed length of JLEE's header */
+#define EB_C_JLEE_LEN 40 /* fixed length of JLEE's header */
+
+#define EB_L_JLEE_SIZE (EB_HEADSIZE + EB_L_JLEE_LEN)
+#define EB_C_JLEE_SIZE (EB_HEADSIZE + EB_C_JLEE_LEN)
+
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+extern MacZipGlobals MacZip;
+extern unsigned long count_of_Zippedfiles;
+
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+static int add_UT_ef(struct zlist far *z, iztimes *z_utim);
+static int add_JLEE_ef(struct zlist far *z); /* old mac extra field */
+static int add_MAC3_ef(struct zlist far *z); /* new mac extra field */
+
+static void make_extrafield_JLEE(char *l_ef);
+static unsigned make_extrafield_MAC3(char *ef);
+static char *make_EF_Head_MAC3(char *ef, unsigned compsize, ulg attrsize,
+ unsigned flag);
+
+static void print_extra_info(void);
+void UserStop(void);
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/*
+* Set the extra-field's for each compressed file
+*/
+int set_extra_field(struct zlist far *z, iztimes *z_utim)
+ /* store full data in local header but just modification time stamp info
+ in central header */
+{
+ int retval;
+
+ Assert_it(z, "set_extra_field","")
+ Assert_it(z_utim, "set_extra_field","")
+
+ z_utim = z_utim;
+
+ /* Check to make sure z is valid. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* Resource forks are always binary */
+ if (MacZip.CurrentFork == ResourceFork) z->att = BINARY;
+
+ if (noisy)
+ {
+ count_of_Zippedfiles++;
+ InformProgress(MacZip.RawCountOfItems, count_of_Zippedfiles );
+ }
+
+ /*
+ PrintFileInfo();
+ */
+ switch (MacZip.MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ retval = add_JLEE_ef( z );
+ if (retval != ZE_OK) return retval;
+ break;
+ }
+ case NewZipMode_EF:
+ { /* */
+#ifdef USE_EF_UT_TIME
+ retval = add_UT_ef(z, z_utim);
+ if (retval != ZE_OK) return retval;
+#endif
+
+ retval = add_MAC3_ef( z );
+ if (retval != ZE_OK) return retval;
+ break;
+ }
+ default:
+ {
+ printerr("Unknown Extrafieldmode", -1, -1, __LINE__, __FILE__, "");
+ return ZE_LOGIC; /* function should never reach this point */
+ }
+ }
+
+ /* MacStat information is now outdated and
+ must be refreshed for the next file */
+ MacZip.isMacStatValid = false;
+
+ return ZE_OK;
+}
+
+
+
+
+#ifdef USE_EF_UT_TIME
+/*
+* Build and add the Unix time extra-field. This extra field
+* will be included be default. Johnny Lee's implementation does
+* not use this kind of extra-field.
+* All datas are in Intel (=little-endian) format
+
+ Extra field info:
+ - 'UT' - UNIX time extra field
+
+ This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields
+ (full data in local header, only modification time in central header),
+ with the 'M3' field added to the end and the size of the 'M3' field
+ in the central header.
+ */
+
+static int add_UT_ef(struct zlist far *z, iztimes *z_utim)
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+
+ Assert_it(z, "add_UT_ef","")
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ /* We can't work if there's no entry to work on. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_UT_SIZE > EF_SIZE_MAX ||
+ z->cext + EB_C_UT_SIZE > EF_SIZE_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_UT_SIZE );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_UT_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'U';
+ *l_ef++ = 'T';
+ *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */
+ *l_ef++ = (char)0;
+ *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_CTIME);
+ *l_ef++ = (char)(z_utim->mtime);
+ *l_ef++ = (char)(z_utim->mtime >> 8);
+ *l_ef++ = (char)(z_utim->mtime >> 16);
+ *l_ef++ = (char)(z_utim->mtime >> 24);
+ *l_ef++ = (char)(z_utim->ctime);
+ *l_ef++ = (char)(z_utim->ctime >> 8);
+ *l_ef++ = (char)(z_utim->ctime >> 16);
+ *l_ef++ = (char)(z_utim->ctime >> 24);
+
+ z->ext += EB_L_UT_SIZE;
+
+ /* Now add the central version. */
+ memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE);
+ c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */
+
+ z->cext += EB_C_UT_SIZE;
+
+ return ZE_OK;
+}
+#endif /* USE_EF_UT_TIME */
+
+
+/*
+* Build and add the old 'Johnny Lee' Mac extra field
+* All native datas are in Motorola (=big-endian) format
+*/
+
+static int add_JLEE_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+
+ Assert_it(z, "add_JLEE_ef","")
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if ( z->ext + EB_L_JLEE_SIZE > EF_SIZE_MAX ||
+ z->cext + EB_C_JLEE_SIZE > EF_SIZE_MAX ) {
+ return ZE_MEM;
+ }
+
+
+ /* Allocate memory for the local extra fields. */
+ if ( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_JLEE_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_JLEE_SIZE );
+ z->ext = 0;
+ }
+ if ( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ /* Allocate memory for the central extra fields. */
+ if ( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_JLEE_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_JLEE_SIZE );
+ z->cext = 0;
+ }
+ if ( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+
+ if ( verbose ) {
+ print_extra_info();
+ }
+
+
+ /**
+ **
+ ** Now add the local version of the field.
+ **/
+ make_extrafield_JLEE(l_ef);
+ z->ext += EB_L_JLEE_SIZE;
+
+
+ /**
+ **
+ ** Now add the central version of the field.
+ ** It's identical to the local header. I wonder why ??
+ * the first two fields are in Intel little-endian format */
+ make_extrafield_JLEE(c_ef);
+ z->cext += EB_C_JLEE_SIZE;
+
+ return ZE_OK;
+}
+
+
+
+/*
+* This is an implementation of Johnny Lee's extra field.
+* I never saw Johnny Lee's code. My code is based on the extra-field
+* definition mac (see latest appnote 1997-03-11)
+* and on some experiments with Johnny Lee's Zip-app version 1.0, 1992
+*
+* Unfortunately I cannot agree with his extra-field layout.
+* - it wasted space
+* - and holds not all mac-specific information
+*
+* I coded this extra-field only for testing purposes.
+* I don't want support this extra-field. Please use my implementation.
+*
+* This is old implementation of Johnny Lee's extra field.
+* All native datas are in Motorola (=big-endian) format
+*/
+
+static void make_extrafield_JLEE(char *ef)
+{
+
+ Assert_it(ef, "make_extrafield_JLEE","")
+
+ if (MacZip.isMacStatValid == false)
+ {
+ fprintf(stderr,"Internal Logic Error: [%d/%s] MacStat is out of sync !",
+ __LINE__,__FILE__);
+ exit(-1);
+ }
+
+
+ /* the first two fields are in Intel little-endian format */
+ *ef++ = 0xC8; /* tag for this extra block */
+ *ef++ = 0x07;
+
+ *ef++ = (char)(EB_L_JLEE_LEN); /* total data size this block */
+ *ef++ = (char)((EB_L_JLEE_LEN) >> 8);
+
+ /* the following fields are in motorola big-endian format */
+ *ef++ = 'J'; /* extra field signature: 4 Bytes */
+ *ef++ = 'L'; /* the old style extra field */
+ *ef++ = 'E';
+ *ef++ = 'E';
+
+ /* Start Macintosh Finder FInfo structure 16 Bytes overall */
+ /* Type: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+ /* Creator: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+ /* file Finder Flags: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+
+ /* Finders Icon position of a file*/
+ /* V/Y-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+ /* H/X-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+
+ /* fdFldr Folder containing file 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr);
+ /* End Macintosh Finder FInfo structure */
+
+
+ /* Creation-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat);
+
+ /* Modification-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat);
+
+ /* info Bits 4 Bytes */
+ *ef++ = 0x00;
+ *ef++ = 0x00;
+ *ef++ = 0x00;
+ if (MacZip.DataForkOnly)
+ { /* don't convert filename for unzipping */
+ /* 0x01 = data-fork; 0x00 = resource-fork */
+ *ef++ = (char) (MacZip.CurrentFork == DataFork) | 2;
+ }
+ else
+ {
+ *ef++ = (char) (MacZip.CurrentFork == DataFork);
+ }
+
+ /* file's location folder ID 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID);
+ /* ============ */
+ /* 40 Bytes */
+}
+
+
+
+/*
+* Build and add the new mac extra field
+* All native data are stored in Intel (=little-endian) format
+*/
+
+static int add_MAC3_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ char *attrbuff = NULL;
+ off_t attrsize = (EB_L_MAC3_FINFO_LEN + EB_MAX_OF_VARDATA);
+ char *compbuff = NULL;
+ unsigned compsize = 0;
+ unsigned m3_compr;
+ Boolean compress_data = true;
+
+ Assert_it(z, "add_MAC3_ef","")
+
+ UserStop(); /* do event handling and let the user stop */
+
+ if( verbose ) {
+ print_extra_info();
+ }
+
+ /* allocate temporary buffer to collect the Mac extra field info */
+ attrbuff = (char *)malloc( (size_t)attrsize );
+ if( attrbuff == NULL ) {
+ return ZE_MEM;
+ }
+
+ /* fill the attribute buffer, to get its (uncompressed) size */
+ attrsize = make_extrafield_MAC3(attrbuff);
+
+ if (compress_data &&
+ ((compbuff = (char *)malloc((size_t)attrsize + MEMCOMPRESS_OVERHEAD))
+ != NULL))
+ {
+ /* Try compressing the data */
+ compsize = memcompress( compbuff,
+ (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+ attrbuff,
+ (size_t)attrsize );
+#ifdef MAC_EXTRAFLD_UNCMPR
+ compsize = attrsize;
+#endif
+ }
+ else
+ {
+ compsize = attrsize;
+ }
+
+ if ((compsize) < attrsize) {
+ /* compression gained some space ... */
+ free(attrbuff); /* no longer needed ... */
+ m3_compr = EB_M3_FL_COMPRESS;
+ } else {
+ /* compression does not help, store data in uncompressed mode */
+ if (compbuff != NULL) free(compbuff);
+ compbuff = attrbuff;
+ compsize = attrsize;
+ m3_compr = EB_M3_FL_UNCMPR;
+ }
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + (EB_L_MAC3_SIZE + compsize) > EF_SIZE_MAX ||
+ z->cext + EB_C_MAC3_SIZE > EF_SIZE_MAX ) {
+ if (compbuff != NULL) free(compbuff);
+ return ZE_MEM;
+ }
+
+ /* Allocate memory for the local extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext +
+ EB_L_MAC3_SIZE + compsize);
+ } else {
+ l_ef = (char *)malloc( EB_L_MAC3_SIZE + compsize);
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ /* Allocate memory for the central extra fields. */
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_MAC3_SIZE);
+ } else {
+ c_ef = (char *)malloc( EB_C_MAC3_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /**
+ ** Now add the local version of the field.
+ **/
+ l_ef = make_EF_Head_MAC3(l_ef, compsize, (ulg)attrsize, m3_compr);
+ memcpy(l_ef, compbuff, (size_t)compsize);
+ l_ef += compsize;
+ z->ext += EB_L_MAC3_SIZE + compsize;
+ free(compbuff);
+ /* And the central version. */
+ c_ef = make_EF_Head_MAC3(c_ef, 0, (ulg)attrsize, m3_compr);
+ z->cext += EB_C_MAC3_SIZE;
+
+ return ZE_OK;
+}
+
+
+
+
+/*
+* Build the new mac local extra field header.
+* It's identical with the central extra field.
+* All native data are in Intel (=little-endian) format
+*/
+static char *make_EF_Head_MAC3(char *ef, unsigned compsize, ulg attrsize,
+ unsigned flag)
+{
+ unsigned info_flag = flag;
+
+ Assert_it(ef, "make_EF_Head_MAC3","")
+
+ /* the first four fields are in Intel little-endian format */
+ *ef++ = 'M'; /* tag for this extra block 2 Bytes */
+ *ef++ = '3';
+
+ /* total data size this block 2 Bytes */
+ *ef++ = (char) (EB_MAC3_HLEN + compsize);
+ *ef++ = (char)((EB_MAC3_HLEN + compsize) >> 8);
+
+ *ef++ = (char)(attrsize);
+ *ef++ = (char)(attrsize >> 8);
+ *ef++ = (char)(attrsize >> 16);
+ *ef++ = (char)(attrsize >> 24);
+
+ /* info Bits (flags) 2 Bytes */
+
+ if (MacZip.DataForkOnly) info_flag |= (EB_M3_FL_DATFRK |
+ EB_M3_FL_NOCHANGE);
+ if (MacZip.CurrentFork == DataFork) info_flag |= EB_M3_FL_DATFRK;
+ if (!MacZip.HaveGMToffset) info_flag |= EB_M3_FL_NOUTC;
+
+ *ef++ = (char)info_flag;
+ *ef++ = (char)0x00; /* reserved at the moment */
+
+ /* Note: Apple defined File-Type/-Creator as OSType ( =unsigned long,
+ see Universal Headers 3.1). However, File-Type/-Creator are a
+ unique four-character sequence. Therefore the byteorder of the
+ File-Type/-Creator are NOT changed. The native format is used. */
+
+ /* Type: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+ /* Creator: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+ return ef;
+}
+
+
+
+
+
+/*
+* Build the new mac local extra field header.
+* All native data are in Intel (=little-endian) format
+*/
+unsigned make_extrafield_MAC3(char *ef)
+{
+ char *ef_m3_begin = ef;
+ char *temp_Pathname;
+ char tmp_buffer[NAME_MAX];
+ unsigned char comment[257];
+ unsigned short FLength = 0;
+ unsigned short CLength = 0;
+ short tempFork;
+ OSErr err;
+
+ Assert_it(ef, "make_extrafield_MAC3","")
+
+ if (MacZip.isMacStatValid == false)
+ {
+ fprintf(stderr,
+ "Internal Logic Error: [%d/%s] MacStat is out of sync !",
+ __LINE__, __FILE__);
+ exit(-1);
+ }
+
+ /* Start Macintosh Finder FInfo structure except Type/Creator
+ (see make_EF_Head_MAC3()) 8 Bytes overall */
+
+ /* file Finder Flags: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags >> 8);
+
+ /* Finders Icon position of a file*/
+ /* V/Y-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v >> 8);
+
+ /* H/X-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h >> 8);
+
+ /* fdFldr Folder containing file 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr >> 8);
+
+ /* End Macintosh Finder FInfo structure */
+
+ /* 8 Bytes so far ... */
+
+ /* Start Macintosh Finder FXInfo structure 16 Bytes overall */
+ /* Icon ID: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdIconID);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdIconID >> 8);
+
+ /* unused: 6 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[0]);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[0] >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[1]);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[1] >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[2]);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[2] >> 8);
+ /* Script flag: 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdScript);
+ /* More flag bits: 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdXFlags);
+ /* Comment ID 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdComment);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdComment >> 8);
+
+ /* Home Dir ID: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 24);
+ /* End Macintosh Finder FXInfo structure */
+
+ /* 24 Bytes so far ... */
+
+ /* file version number 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFVersNum);
+
+ /* directory access rights 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioACUser);
+
+ /* Creation-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 24);
+ /* Modification-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 24);
+ /* Backup-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 24);
+
+ /* 38 Bytes so far ... */
+#ifdef USE_EF_UT_TIME
+ if (MacZip.HaveGMToffset) {
+ /* GMT-Offset times 12 Bytes */
+ *ef++ = (char)(MacZip.Cr_UTCoffs);
+ *ef++ = (char)(MacZip.Cr_UTCoffs >> 8);
+ *ef++ = (char)(MacZip.Cr_UTCoffs >> 16);
+ *ef++ = (char)(MacZip.Cr_UTCoffs >> 24);
+ *ef++ = (char)(MacZip.Md_UTCoffs);
+ *ef++ = (char)(MacZip.Md_UTCoffs >> 8);
+ *ef++ = (char)(MacZip.Md_UTCoffs >> 16);
+ *ef++ = (char)(MacZip.Md_UTCoffs >> 24);
+ *ef++ = (char)(MacZip.Bk_UTCoffs);
+ *ef++ = (char)(MacZip.Bk_UTCoffs >> 8);
+ *ef++ = (char)(MacZip.Bk_UTCoffs >> 16);
+ *ef++ = (char)(MacZip.Bk_UTCoffs >> 24);
+ }
+ /* 50 Bytes so far ... */
+#endif
+
+ /* Text Encoding Base (charset) 2 Bytes */
+ *ef++ = (char)(MacZip.CurrTextEncodingBase);
+ *ef++ = (char)(MacZip.CurrTextEncodingBase >> 8);
+ /* 52 Bytes so far ... */
+
+ /* MacZip.CurrentFork will be changed, so we have to save it */
+ tempFork = MacZip.CurrentFork;
+ if (!MacZip.StoreFullPath) {
+ temp_Pathname = StripPartialDir(tmp_buffer, MacZip.SearchDir,
+ MacZip.FullPath);
+ } else {
+ temp_Pathname = MacZip.FullPath;
+ }
+ MacZip.CurrentFork = tempFork;
+
+ FLength = strlen(temp_Pathname) + 1;
+ memcpy( ef, temp_Pathname, (size_t)FLength );
+ ef += FLength; /* make room for the string - variable length */
+
+ err = FSpLocationFromFullPath(strlen(MacZip.FullPath), MacZip.FullPath,
+ &MacZip.fileSpec);
+ printerr("FSpLocationFromFullPath:", err, err,
+ __LINE__, __FILE__, tmp_buffer);
+
+ err = FSpDTGetComment(&MacZip.fileSpec, comment);
+ printerr("FSpDTGetComment:", (err != -5012) && (err != 0), err,
+ __LINE__, __FILE__, "");
+ PToCCpy(comment,tmp_buffer);
+
+ CLength = strlen(tmp_buffer) + 1;
+ memcpy( ef, tmp_buffer, (size_t)CLength );
+ ef += CLength; /* make room for the string - variable length */
+
+ if (verbose) printf("\n comment: [%s]", tmp_buffer);
+
+ return (unsigned)(ef - ef_m3_begin);
+}
+
+
+
+
+
+
+/*
+* Print all native data of the new mac local extra field.
+* It's for debugging purposes and disabled by default.
+*/
+
+static void PrintFileInfo(void)
+{
+DateTimeRec MacTime;
+
+printf("\n\n---------------------------------------------"\
+ "----------------------------------");
+printf("\n FullPath Name = [%s]", MacZip.FullPath);
+printf("\n File Attributes = %s 0x%x %d",
+ sBit2Str(MacZip.fpb.hFileInfo.ioFlAttrib),
+ MacZip.fpb.hFileInfo.ioFlAttrib,
+ MacZip.fpb.hFileInfo.ioFlAttrib);
+printf("\n Enclosing Folder ID# = 0x%x %d",
+ MacZip.fpb.hFileInfo.ioFlParID,
+ MacZip.fpb.hFileInfo.ioFlParID);
+
+if (!MacZip.isDirectory)
+{
+printf("\n File Type = [%c%c%c%c] 0x%lx",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+printf("\n File Creator = [%c%c%c%c] 0x%lx",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+printf("\n Data Fork :" );
+printf("\n Actual (Logical) Length = %d 0x%x ",
+ MacZip.fpb.hFileInfo.ioFlLgLen,
+ MacZip.fpb.hFileInfo.ioFlLgLen);
+printf("\n Allocated (Physical) Length = %d 0x%x",
+ MacZip.fpb.hFileInfo.ioFlPyLen,
+ MacZip.fpb.hFileInfo.ioFlPyLen);
+printf("\n Resource Fork :" );
+printf("\n Actual (Logical) Length = %d 0x%x",
+ MacZip.fpb.hFileInfo.ioFlRLgLen,
+ MacZip.fpb.hFileInfo.ioFlRLgLen );
+printf("\n Allocated (Physical) Length = %d 0x%x",
+ MacZip.fpb.hFileInfo.ioFlRPyLen,
+ MacZip.fpb.hFileInfo.ioFlRPyLen );
+}
+
+printf("\n Dates : ");
+
+SecondsToDate (MacZip.CreatDate, &MacTime);
+printf("\n Created = %4d/%2d/%2d %2d:%2d:%2d ",
+ MacTime.year,
+ MacTime.month,
+ MacTime.day,
+ MacTime.hour,
+ MacTime.minute,
+ MacTime.second);
+
+SecondsToDate (MacZip.BackDate, &MacTime);
+printf("\n Backup = %4d/%2d/%2d %2d:%2d:%2d ",
+ MacTime.year,
+ MacTime.month,
+ MacTime.day,
+ MacTime.hour,
+ MacTime.minute,
+ MacTime.second);
+
+SecondsToDate (MacZip.ModDate, &MacTime);
+printf("\n Modified = %4d/%2d/%2d %2d:%2d:%2d ",
+ MacTime.year,
+ MacTime.month,
+ MacTime.day,
+ MacTime.hour,
+ MacTime.minute,
+ MacTime.second);
+
+if (!MacZip.isDirectory)
+{
+printf("\n Finder Flags : %s 0x%x %d",
+ sBit2Str(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags),
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+printf("\n Finder Icon Position = X: %d 0x%x ",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+printf("\n Y: %d 0x%x ",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+}
+else
+{
+printf("\n Finder Flags : %s 0x%x %d",
+ sBit2Str(MacZip.fpb.dirInfo.ioDrUsrWds.frFlags),
+ MacZip.fpb.dirInfo.ioDrUsrWds.frFlags,
+ MacZip.fpb.dirInfo.ioDrUsrWds.frFlags);
+printf("\n Finder Icon Position = X: %d 0x%x ",
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.h,
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.h);
+printf("\n Y: %d 0x%x ",
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.v,
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.v);
+}
+
+printf("\n----------------------------------------------------"\
+ "---------------------------\n");
+}
+
+
+
+/*
+* If the switch '-v' is used, print some more info.
+*/
+
+static void print_extra_info(void)
+{
+char Fork[20];
+
+if (MacZip.CurrentFork == DataFork) sstrcpy(Fork,"<DataFork>");
+else sstrcpy(Fork,"<ResourceFork>");
+
+printf("\n%16s [%c%c%c%c] [%c%c%c%c]",Fork,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType,
+
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+}
diff --git a/macos/source/getenv.c b/macos/source/getenv.c
new file mode 100644
index 0000000..3b22327
--- /dev/null
+++ b/macos/source/getenv.c
@@ -0,0 +1,398 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+
+This file implements the getenv() function.
+
+# Background:
+# Under Unix: Each Process (= running Program) has a set of
+# associated variables. The variables are called enviroment
+# variables and, together, constitute the process environment.
+# These variables include the search path, the terminal type,
+# and the user's login name.
+
+# Unfortunatelly the MacOS has no equivalent. So we need
+# a file to define the environment variables.
+# Name of this file is "MacZip.Env". It can be placed
+# in the current folder of MacZip or in the
+# preference folder of the system disk.
+# If MacZip founds the "MacZip.Env" file in the current
+# the folder of MacZip the "MacZip.Env" file in the
+# preference folder will be ignored.
+
+# An environment variable has a name and a value:
+# Name=Value
+# Note: Spaces are significant:
+# ZIPOPT=-r and
+# ZIPOPT = -r are different !!!
+
+
+ */
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unix.h>
+#include <Files.h>
+#include <Folders.h>
+
+#include "pathname.h"
+#include "helpers.h"
+
+/*****************************************************************************/
+/* Module level Vars */
+/*****************************************************************************/
+
+static char ListAllKeyValues = 0;
+static unsigned LineNumber = 0;
+static char CompletePath[NAME_MAX];
+Boolean IgnoreEnvironment = false; /* used by dialog.c and initfunc.c
+ of the Mainapp */
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+typedef struct _EnviromentPair {
+ char *key;
+ char *value;
+} EnviromentPair;
+
+
+#define MAX_COMMAND 1024
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+
+int get_char(FILE *file);
+void unget_char(int ch,FILE *file);
+int get_string(char *string,int size, FILE *file, char *terms);
+void skip_comments(FILE *file);
+char *load_entry(FILE *file);
+char *getenv(const char *name);
+EnviromentPair *ParseLine(char *line);
+OSErr FSpFindFolder_Name(short vRefNum, OSType folderType,
+ Boolean createFolder,FSSpec *spec, unsigned char *name);
+FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode);
+void ShowAllKeyValues(void);
+void Set_LineNum(unsigned ln);
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/* get_string(str, max, file, termstr) : like fgets() but
+ * (1) has terminator string which should include \n
+ * (2) will always leave room for the null
+ * (3) uses get_char() so LineNumber will be accurate
+ * (4) returns EOF or terminating character, whichever
+ */
+int get_string(char *string, int size, FILE *file, char *terms)
+{
+ int ch;
+
+ while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) {
+ if (size > 1) {
+ *string++ = (char) ch;
+ size--;
+ }
+ }
+
+ if (size > 0)
+ {
+ *string = '\0';
+ }
+
+ return ch;
+}
+
+
+
+
+void Set_LineNum(unsigned ln)
+{
+ LineNumber = ln;
+}
+
+
+
+/* get_char(file) : like getc() but increment LineNumber on newlines
+ */
+int get_char(FILE *file)
+{
+ int ch;
+
+ ch = getc(file);
+ if (ch == '\n')
+ {
+ Set_LineNum(LineNumber + 1);
+ }
+
+ return ch;
+}
+
+
+
+
+/* skip_comments(file) : read past comment (if any)
+ */
+void skip_comments(FILE *file)
+{
+ int ch;
+
+ while (EOF != (ch = get_char(file)))
+ {
+ /* ch is now the first character of a line.
+ */
+
+ while (ch == ' ' || ch == '\t')
+ {
+ ch = get_char(file);
+ }
+
+ if (ch == EOF)
+ {
+ break;
+ }
+
+ /* ch is now the first non-blank character of a line.
+ */
+
+ if (ch != '\n' && ch != '#')
+ {
+ break;
+ }
+
+ /* ch must be a newline or comment as first non-blank
+ * character on a line.
+ */
+
+ while (ch != '\n' && ch != EOF)
+ {
+ ch = get_char(file);
+ }
+
+ /* ch is now the newline of a line which we're going to
+ * ignore.
+ */
+ }
+
+ if (ch != EOF)
+ {
+ unget_char(ch, file);
+ }
+}
+
+
+
+
+/* unget_char(ch, file) : like ungetc but do LineNumber processing
+ */
+void unget_char(int ch, FILE *file)
+{
+ ungetc(ch, file);
+ if (ch == '\n')
+ {
+ Set_LineNum(LineNumber - 1);
+ }
+}
+
+
+/* this function reads one file entry -- the next -- from a file.
+* it skips any leading blank lines, ignores comments, and returns
+* NULL if for any reason the entry can't be read and parsed.
+*/
+
+char *load_entry(FILE *file)
+{
+ int ch;
+ static char cmd[MAX_COMMAND];
+
+ skip_comments(file);
+
+ ch = get_string(cmd, MAX_COMMAND, file, "\n");
+
+ if (ch == EOF)
+ {
+ return NULL;
+ }
+
+ return cmd;
+}
+
+
+
+
+
+EnviromentPair *ParseLine(char *line)
+{
+char *tmpPtr;
+static EnviromentPair *Env;
+unsigned short length = strlen(line);
+
+Env->key = "";
+Env->value = "";
+
+for (tmpPtr = line; *tmpPtr; tmpPtr++)
+ {
+ if (*tmpPtr == '=')
+ {
+ *tmpPtr = 0;
+ Env->key = line;
+ if (strlen(Env->key) < length)
+ {
+ Env->value = ++tmpPtr;
+ }
+ return Env;
+ }
+ }
+return Env;
+}
+
+
+
+
+
+char *getenv(const char *name)
+{
+FILE *fp;
+char *LineStr = NULL;
+EnviromentPair *Env1;
+FSSpec spec;
+OSErr err;
+
+if (IgnoreEnvironment)
+ return NULL; /* user wants to ignore the environment vars */
+
+if (name == NULL)
+ return NULL;
+
+GetCompletePath(CompletePath,"MacZip.Env",&spec,&err);
+
+/* try open the file in the current folder */
+fp = FSp_fopen(&spec,"r");
+if (fp == NULL)
+ { /* Okey, lets try open the file in the preference folder */
+ FSpFindFolder_Name(
+ kOnSystemDisk,
+ kPreferencesFolderType,
+ kDontCreateFolder,
+ &spec,
+ "\pMacZip.Env");
+ fp = FSp_fopen(&spec,"r");
+ if (fp == NULL)
+ {
+ return NULL; /* there is no enviroment-file */
+ }
+ }
+
+LineStr = load_entry(fp);
+while (LineStr != NULL)
+ { /* parse the file line by line */
+ Env1 = ParseLine(LineStr);
+ if (strlen(Env1->value) > 0)
+ { /* we found a key/value pair */
+ if (ListAllKeyValues)
+ printf("\n Line:%3d [%s] = [%s]",LineNumber,Env1->key,Env1->value);
+ if (stricmp(name,Env1->key) == 0)
+ { /* we found the value of a given key */
+ return Env1->value;
+ }
+ }
+ LineStr = load_entry(fp); /* read next line */
+ }
+fclose(fp);
+
+return NULL;
+}
+
+
+
+
+
+OSErr FSpFindFolder_Name(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec, /* Pointer to resulting directory. */
+ unsigned char *name) /* Name of the file in the folder */
+{
+ short foundVRefNum;
+ long foundDirID;
+ OSErr err;
+
+ err = FindFolder(vRefNum, folderType, createFolder,
+ &foundVRefNum, &foundDirID);
+ if (err != noErr)
+ {
+ return err;
+ }
+
+ err = FSMakeFSSpec(foundVRefNum, foundDirID, name, spec);
+ return err;
+}
+
+
+
+
+void ShowAllKeyValues(void)
+{
+OSErr err;
+FSSpec spec;
+Boolean tmpIgnoreEnvironment = IgnoreEnvironment;
+
+ListAllKeyValues = 1;
+IgnoreEnvironment = false;
+
+GetCompletePath(CompletePath,"MacZip.Env",&spec,&err);
+if (err != 0)
+ { /* Okey, lets try open the file in the preference folder */
+ FSpFindFolder_Name(
+ kOnSystemDisk,
+ kPreferencesFolderType,
+ kDontCreateFolder,
+ &spec,
+ "\pMacZip.Env");
+ GetFullPathFromSpec(CompletePath,&spec, &err);
+ if (err != 0)
+ {
+ return; /* there is no enviroment-file */
+ }
+ }
+
+printf("\nLocation of the current \"MacZip.Env\" file:\n [%s]",CompletePath);
+
+printf("\n\nList of all environment variables\n");
+getenv(" ");
+printf("\n\nEnd\n\n");
+
+/* restore used variables */
+ListAllKeyValues = 0;
+LineNumber = 0;
+IgnoreEnvironment = tmpIgnoreEnvironment;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/macos/source/helpers.c b/macos/source/helpers.c
new file mode 100644
index 0000000..36b5bef
--- /dev/null
+++ b/macos/source/helpers.c
@@ -0,0 +1,479 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ helpers.c
+
+ Some useful functions Used by unzip and zip.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include "zip.h"
+#include <ctype.h>
+#include <time.h>
+#include <sound.h>
+
+#include "macstuff.h"
+#include "helpers.h"
+#include "pathname.h"
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+
+extern int noisy;
+extern char MacPathEnd;
+extern char *zipfile; /* filename of the Zipfile */
+extern char *tempzip; /* Temporary zip file name */
+extern ZCONST unsigned char MacRoman_to_WinCP1252[128];
+
+
+static char argStr[1024];
+static char *argv[MAX_ARGS + 1];
+
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/*
+** Copy a C string to a Pascal string
+**
+*/
+
+unsigned char *CToPCpy(unsigned char *pstr, char *cstr)
+{
+ register char *dptr;
+ register unsigned len;
+
+ len=0;
+ dptr=(char *)pstr+1;
+ while (len<255 && (*dptr++ = *cstr++)!='\0') ++len;
+ *pstr= (unsigned char)len;
+ return pstr;
+}
+
+
+/*
+** Copy a Pascal string to a C string
+**
+*/
+
+char *PToCCpy(unsigned char *pstr, char *cstr)
+{
+strncpy(cstr, (char *) &pstr[1], *pstr);
+ cstr[pstr[0]] = '\0'; /* set endmarker for c-string */
+return cstr;
+}
+
+
+/*
+** strcpy() and strcat() work-alikes which allow overlapping buffers.
+*/
+
+char *sstrcpy(char *to,const char *from)
+{
+ memmove(to, from, 1+strlen(from));
+ return to;
+}
+
+char *sstrcat(char *to,const char *from)
+{
+ sstrcpy(to + strlen(to), from);
+ return to;
+}
+
+
+
+/*
+** Alloc memory and init it
+**
+*/
+
+char *StrCalloc(unsigned short size)
+{
+char *strPtr = NULL;
+
+if ((strPtr = calloc(size, sizeof(char))) == NULL)
+ printerr("StrCalloc failed:", -1, size, __LINE__, __FILE__, "");
+
+Assert_it(strPtr,"strPtr == NULL","")
+return strPtr;
+}
+
+
+
+/*
+** Release only non NULL pointers
+**
+*/
+
+char *StrFree(char *strPtr)
+{
+
+if (strPtr != NULL)
+ {
+ free(strPtr);
+ }
+
+return NULL;
+}
+
+
+
+
+/*
+** Return a value in a binary string
+**
+*/
+
+char *sBit2Str(unsigned short value)
+{
+ static char str[sizeof(value)*8];
+ int biz = 16;
+ int strwid = 16;
+ int i, j;
+ char *tempPtr = str;
+
+ j = strwid - (biz + (biz >> 2)- (biz % 4 ? 0 : 1));
+
+ for (i = 0; i < j; i++) {
+ *tempPtr++ = ' ';
+ }
+ while (--biz >= 0)
+ {
+ *tempPtr++ = ((value >> biz) & 1) + '0';
+ if (!(biz % 4) && biz) {
+ *tempPtr++ = ' ';
+ }
+ }
+ *tempPtr = '\0';
+
+ return str;
+}
+
+
+
+
+/*
+** Parse commandline style arguments
+**
+*/
+
+int ParseArguments(char *s, char ***arg)
+{
+ int n = 1, Quote = 0;
+ char *p = s, *p1, c;
+
+ argv[0] = GetAppName();
+
+ *arg = argv;
+
+ p1 = (char *) argStr;
+ while ((c = *p++) != 0) {
+ if (c==' ') continue;
+ argv[n++] = p1;
+ if (n > MAX_ARGS)
+ return (n-1);
+ do {
+ if (c=='\\' && *p++)
+ c = *p++;
+ else
+ if ((c=='"') || (c == '\'')) {
+ if (!Quote) {
+ Quote = c;
+ continue;
+ }
+ if (c == Quote) {
+ Quote = 0;
+ continue;
+ }
+ }
+ *p1++ = c;
+ } while (*p && ((c = *p++) != ' ' || Quote));
+ *p1++ = '\0';
+ }
+ return n;
+}
+
+
+
+/*
+** Print commandline style arguments
+**
+*/
+
+void PrintArguments(int argc, char **argv)
+{
+
+printf("\n Arguments:");
+printf("\n --------------------------");
+
+while(--argc >= 0)
+ printf("\n argc: %d argv: [%s]", argc, &*argv[argc]);
+
+printf("\n --------------------------\n\n");
+return;
+}
+
+
+
+/*
+** return some error-msg on file-system
+**
+*/
+
+int PrintUserHFSerr(int cond, int err, char *msg2)
+{
+char *msg;
+
+if (cond != 0)
+ {
+ switch (err)
+ {
+ case -35:
+ msg = "No such Volume";
+ break;
+
+ case -56:
+ msg = "No such Drive";
+ break;
+
+ case -37:
+ msg = "Bad Volume Name";
+ break;
+
+ case -49:
+ msg = "File is already open for writing";
+ break;
+
+ case -43:
+ msg = "Directory/File not found";
+ break;
+
+ case -120:
+ msg = "Directory/File not found or incomplete pathname";
+ break;
+
+ default: return err;
+ }
+ fprintf(stderr, "\n\n Error: %s ->%s", msg, msg2);
+ exit(err);
+ }
+
+return 0;
+}
+
+
+
+/*
+** Check mounted volumes and return number of volumes
+** with the same name.
+*/
+
+short CheckMountedVolumes(char *FullPath)
+{
+FSSpec volumes[50]; /* 50 Volumes should be enough */
+char VolumeName[257], volume[257];
+short actVolCount, volIndex = 1, VolCount = 0;
+OSErr err;
+int i;
+
+GetVolumeFromPath(FullPath, VolumeName);
+
+err = OnLine(volumes, 50, &actVolCount, &volIndex);
+printerr("OnLine:", (err != -35) && (err != 0), err, __LINE__, __FILE__, "");
+
+for (i=0; i < actVolCount; i++)
+ {
+ PToCCpy(volumes[i].name,volume);
+ if (stricmp(volume, VolumeName) == 0) VolCount++;
+ }
+printerr("OnLine: ", (VolCount == 0), VolCount, __LINE__, __FILE__, FullPath);
+
+return VolCount;
+}
+
+
+
+
+
+
+
+
+/*
+** compares strings, ignoring differences in case
+**
+*/
+
+int stricmp(const char *p1, const char *p2)
+{
+int diff;
+
+while (*p1 && *p2)
+ {
+ if (*p1 != *p2)
+ {
+ if (isalpha(*p1) && isalpha(*p2))
+ {
+ diff = toupper(*p1) - toupper(*p2);
+ if (diff) return diff;
+ }
+ else break;
+ }
+ p1++;
+ p2++;
+ }
+return *p1 - *p2;
+}
+
+
+
+/*
+** Convert the MacOS-Strings (Filenames/Findercomments) to a most compatible.
+** These strings will be stored in the public area of the zip-archive.
+** Every foreign platform (outside macos) will access these strings
+** for extraction.
+*/
+
+void MakeCompatibleString(char *MacOS_Str,
+ const char SpcChar1, const char SpcChar2,
+ const char SpcChar3, const char SpcChar4,
+ short CurrTextEncodingBase)
+{
+ char *tmpPtr;
+ register uch curch;
+
+ Assert_it(MacOS_Str,"MakeCompatibleString MacOS_Str == NULL","")
+ for (tmpPtr = MacOS_Str; (curch = *tmpPtr) != '\0'; tmpPtr++)
+ {
+ if (curch == SpcChar1)
+ *tmpPtr = SpcChar2;
+ else
+ if (curch == SpcChar3)
+ *tmpPtr = SpcChar4;
+ else /* default */
+ /* now convert from MacRoman to ISO-8859-1 */
+ /* but convert only if MacRoman is activ */
+ if ((CurrTextEncodingBase == kTextEncodingMacRoman) &&
+ (curch > 127))
+ {
+ *tmpPtr = (char)MacRoman_to_WinCP1252[curch - 128];
+ }
+ } /* end for */
+}
+
+
+
+
+Boolean CheckForSwitch(char *Switch, int argc, char **argv)
+{
+ char *p; /* steps through option arguments */
+ int i; /* arg counter, root directory flag */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (argv[i][1])
+ {
+ for (p = argv[i]+1; *p; p++)
+ {
+ if (*p == Switch[0])
+ {
+ return true;
+ }
+ if ((Switch[1] != NULL) &&
+ ((*p == Switch[0]) && (*p == Switch[1])))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+return false;
+}
+
+
+
+
+
+
+
+#if (defined(USE_SIOUX) || defined(MACUNZIP_STANDALONE))
+
+/*
+** checks the condition and returns an error-msg
+** this function is for internal use only
+*/
+
+OSErr printerr(const char *msg, int cond, int err, int line, char *file,
+ const char *msg2)
+{
+
+if (cond != 0)
+ {
+ fprintf(stderr, "\nint err: %d: %s %d [%d/%s] {%s}\n", clock(), msg, err,
+ line, file, msg2);
+ }
+
+return cond;
+}
+
+
+/*
+fake-functions:
+Not Implemented for metrowerks SIOUX
+*/
+
+void leftStatusString(char *status)
+{
+status = status;
+}
+
+
+void rightStatusString(char *status)
+{
+status = status;
+}
+
+
+
+void DoWarnUserDupVol( char *FullPath )
+{
+ char VolName[257];
+ GetVolumeFromPath(FullPath, VolName);
+
+ printf("\n There are more than one volume that has the same name !!\n");
+
+ printf("\n Volume: %s\n",VolName);
+
+ printf("\n This port has one weak point:");
+ printf("\n It is based on pathnames. As you may be already know:");
+ printf("\n Pathnames are not unique on a Mac !");
+ printf("\n MacZip has problems to find the correct location of");
+ printf("\n the archive or the files.\n");
+
+ printf("\n My (Big) recommendation: Name all your volumes with an");
+ printf("\n unique name and MacZip will run without any problem.");
+}
+
+
+
+#endif
diff --git a/macos/source/helpers.h b/macos/source/helpers.h
new file mode 100644
index 0000000..a9df5d8
--- /dev/null
+++ b/macos/source/helpers.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef HELPERS_H
+#define HELPERS_H 1
+
+ /* Convert a C string to a Pascal string */
+unsigned char *CToPCpy(unsigned char *pstr, char *cstr);
+
+ /* Convert a Pascal string to a C string */
+char *PToCCpy(unsigned char *pstr, char *cstr);
+
+char *sstrcpy(char *to,const char *from);
+char *sstrcat(char *to,const char *from);
+
+char *StrCalloc(unsigned short size);
+char *StrFree(char *strPtr);
+
+char *sBit2Str(unsigned short value);
+
+void print_extra_info(void);
+
+int ParseArguments(char *s, char ***arg);
+void PrintArguments(int argc, char **argv);
+
+Boolean IsZipFile(char *name);
+OSErr printerr(const char *msg, int cond, int err, int line, char *file,
+ const char *msg2);
+int PrintUserHFSerr(int cond, int err, char *msg2);
+
+short CheckMountedVolumes(char *FullPath);
+void DoWarnUserDupVol(char *path);
+
+void PrintFileInfo(void);
+
+int stricmp(const char *p1, const char *p2);
+void leftStatusString(char *status);
+void rightStatusString(char *status);
+
+Boolean isZipFile(FSSpec *fileToOpen);
+
+unsigned long MacFileDate_to_UTime(unsigned long mactime);
+Boolean CheckForSwitch(char *Switch, int argc, char **argv);
+
+void MakeCompatibleString(char *MacOS_Str,
+ const char SpcChar1, const char SpcChar2,
+ const char SpcChar3, const char SpcChar4,
+ short CurrTextEncodingBase);
+
+#define MAX_ARGS 25
+
+#endif /* HELPERS_H */
diff --git a/macos/source/macglob.h b/macos/source/macglob.h
new file mode 100644
index 0000000..17415e1
--- /dev/null
+++ b/macos/source/macglob.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef _MACGLOBAL_
+#define _MACGLOBAL_
+
+#include <time.h>
+
+/*
+all my Global vars are defined here.
+*/
+
+#define ResourceFork -1
+#define DataFork 1
+#define NoFork 0
+
+/*
+all my Global vars are defined here.
+*/
+typedef struct {
+ short CurrentFork;
+ short MacZipMode;
+
+ Boolean isMacStatValid;
+ Boolean HaveGMToffset;
+
+ short CurrTextEncodingBase;
+
+ /* info about the current file */
+ Boolean isDirectory;
+ char FullPath[NAME_MAX];
+ char FileName[NAME_MAX];
+ FSSpec fileSpec;
+
+ long dirID;
+ CInfoPBRec fpb;
+
+ /* time infos about the current file */
+ time_t CreatDate;
+ time_t ModDate;
+ time_t BackDate;
+ long Cr_UTCoffs; /* offset "local time - UTC" for CreatDate */
+ long Md_UTCoffs; /* offset "local time - UTC" for ModDate */
+ long Bk_UTCoffs; /* offset "local time - UTC" for BackDate */
+
+ /* some statistics over all*/
+ unsigned long FoundFiles;
+ unsigned long FoundDirectories;
+ unsigned long RawCountOfItems;
+ unsigned long BytesOfData;
+
+ unsigned long attrsize;
+
+ /* some switches and user parameters */
+ Boolean DataForkOnly;
+ Boolean StoreFullPath;
+ Boolean StoreFoldersAlso; /* internal switch is true if '-r' is set */
+ unsigned short SearchLevels;
+ char Pattern[NAME_MAX];
+ Boolean IncludeInvisible;
+ Boolean StatingProgress;
+
+ char SearchDir[NAME_MAX];
+ char CurrentPath[NAME_MAX];
+
+ /* current zip / tempzip file info */
+ char ZipFullPath[NAME_MAX];
+
+ FSSpec ZipFileSpec;
+ unsigned long ZipFileType;
+ char TempZipFullPath[NAME_MAX];
+ FSSpec TempZipFileSpec;
+
+} MacZipGlobals;
+
+
+
+void UserStop(void);
+
+
+#endif
diff --git a/macos/source/macopen.c b/macos/source/macopen.c
new file mode 100644
index 0000000..9e18730
--- /dev/null
+++ b/macos/source/macopen.c
@@ -0,0 +1,363 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*** macopen.c; stuff only required for the Mac port ***/
+
+#include "zip.h"
+
+#include <string.h>
+#include <fcntl.h>
+#include <unix.h>
+#include <sound.h>
+
+#include "helpers.h"
+#include "pathname.h"
+#include "macopen.h"
+#include "macstuff.h"
+
+#ifdef MACZIP
+#include "macglob.h"
+
+extern char *zipfile; /* filename of the Zipfile */
+extern char *tempzip; /* Temporary zip file name */
+
+extern MacZipGlobals MacZip;
+
+
+/* don't include "osdep.h" otherwise we will trap into endless loop */
+#undef open
+#undef fopen
+
+
+
+FILE *MacFopen(const char *path, const char *mode)
+{
+static char TruncPath[NAME_MAX];
+OSErr err = 0;
+
+AssertStr(path,path)
+
+ /* open zipfile or tempzip */
+if (strcmp(zipfile,path) == 0)
+ {
+ GetCompletePath(MacZip.ZipFullPath,path,&MacZip.ZipFileSpec,&err);
+ err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+ printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);
+ if (CheckMountedVolumes(MacZip.ZipFullPath) > 1)
+ DoWarnUserDupVol(MacZip.ZipFullPath);
+
+ /* tempfile should appear in the same directory of the zipfile
+ -> save path of zipfile */
+ TruncFilename(TruncPath, MacZip.ZipFullPath);
+ return fopen(MacZip.ZipFullPath, mode);
+ }
+
+if (strcmp(tempzip,path) == 0)
+ { /* add path of zipfile */
+ sstrcat(TruncPath,tempzip);
+ GetCompletePath(MacZip.TempZipFullPath,TruncPath,&MacZip.TempZipFileSpec,&err);
+ err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+ printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);
+
+ return fopen(MacZip.TempZipFullPath, mode);
+ }
+
+printerr("MacFopen:",err,err,__LINE__,__FILE__,path);
+return NULL;
+}
+
+
+
+
+int MacOpen(const char *path,int oflag, ...)
+{
+char RealFname[NAME_MAX];
+
+AssertStr(path,path)
+
+RfDfFilen2Real(RealFname,path, MacZip.MacZipMode, MacZip.DataForkOnly, &MacZip.CurrentFork);
+/* convert to real fname and init global var MacZip.CurrentFork !! */
+
+switch (MacZip.CurrentFork)
+ {
+ case DataFork:
+ {
+ return my_open(RealFname, oflag);
+ break;
+ }
+ case ResourceFork:
+ {
+ return my_open( RealFname, oflag | O_RSRC);
+ break;
+ }
+ default: /* for now (Zip ver 2.3b) MacOpen should never reach this point */
+ { /* however, this may change in the future ... */
+ printerr("open: no resource / datafork ",-1,-1,__LINE__,__FILE__,path);
+ return -1;
+ }
+ }
+}
+
+
+#ifdef muell
+ /* file to delete */
+int destroy(char *path)
+{
+static char lastpath[NAME_MAX];
+char currpath[NAME_MAX];
+static Boolean FirstCall = true;
+long rc;
+
+AssertStr(path,path)
+
+RfDfFilen2Real(currpath, path, MacZip.MacZipMode, MacZip.DataForkOnly, &MacZip.CurrentFork);
+
+if (FirstCall == true)
+ {
+ FirstCall = false;
+ rc = remove(currpath);
+ }
+else if (strcmp(currpath,lastpath) == 0) return 0; /* ignore, file is already deleted */
+ else rc = remove(currpath); /* we are removeing all the files only by their
+ pathname this is dangerous on a mac but there is no other way without
+ a complete rewrite of the port */
+
+strcpy(lastpath,currpath);
+
+return rc;
+}
+#endif
+
+
+
+
+/* this function replaces the function "replace()" defined in fileio.c */
+int replace(char *new_f, char *temp_f) /* destination and source file names */
+{
+OSErr err = 0;
+char newfname[NAME_MAX];
+
+AssertStr(new_f,new_f)
+AssertStr(temp_f,temp_f)
+
+UserStop();
+
+GetFilename(newfname, new_f);
+
+/* check zipfile name and tempfile name */
+/* we are using this function only for replacing the tempfile with the zipfile */
+if ((strcmp(zipfile,new_f) == 0) || (strcmp(tempzip,temp_f) == 0))
+ {
+ remove(MacZip.ZipFullPath);
+
+ /* rename the temp file to the zip file */
+ err = rename(MacZip.TempZipFullPath,MacZip.ZipFullPath);
+ printerr("rename:",err,err,__LINE__,__FILE__,MacZip.TempZipFullPath);
+if (err != 0) return ZE_CREAT;
+ else return ZE_OK;
+ }
+else return ZE_CREAT;
+}
+
+
+
+ /* file to delete */
+ /* we are removeing all the files only by their
+ pathname this is dangerous on a mac but there is no
+ other way without a complete rewrite of the port */
+
+int destroy(char *path)
+{
+static char lastpath[NAME_MAX];
+static FSSpec trashfolder;
+static Boolean FirstCall = true;
+static char Num = 0;
+static Boolean Immediate_File_Deletion = false;
+char currpath[NAME_MAX], *envptr;
+FSSpec fileToDelete;
+OSErr err;
+
+/* init this function */
+if ((path == NULL) ||
+ (strlen(path) == 0))
+ {
+ FirstCall = true;
+ Num = 0;
+ return -1;
+ }
+
+UserStop();
+
+RfDfFilen2Real(currpath, path, MacZip.MacZipMode,
+ MacZip.DataForkOnly, &MacZip.CurrentFork);
+GetCompletePath(currpath,currpath,&fileToDelete, &err);
+
+if (FirstCall == true)
+ {
+ FirstCall = false;
+ sstrcpy(lastpath,currpath);
+ err = FSpFindFolder(fileToDelete.vRefNum, kTrashFolderType,
+ kDontCreateFolder,&trashfolder);
+ printerr("FSpFindFolder:",err,err,__LINE__,__FILE__,path);
+
+ envptr = getenv("Immediate_File_Deletion");
+ if (!(envptr == (char *)NULL || *envptr == '\0'))
+ {
+ if (stricmp(envptr,"yes") == 0)
+ Immediate_File_Deletion = true;
+ else
+ Immediate_File_Deletion = false;
+ }
+
+ if (Immediate_File_Deletion)
+ {
+ err = FSpDelete(&fileToDelete);
+ return err;
+ }
+
+ err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+ fileToDelete.name, trashfolder.parID, trashfolder.name);
+ return err;
+ }
+
+if (strcmp(currpath,lastpath) == 0)
+ {
+ return 0; /* ignore, file is already deleted */
+ }
+else
+ {
+
+ if (Immediate_File_Deletion)
+ {
+ err = FSpDelete(&fileToDelete);
+ sstrcpy(lastpath,path);
+ return err;
+ }
+
+ err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+ fileToDelete.name, trashfolder.parID, trashfolder.name);
+
+ /* -48 = file is already existing so we have to rename it before
+ moving the file */
+ if (err == -48)
+ {
+ Num++;
+ if (fileToDelete.name[0] >= 28) /* cut filename if to long */
+ fileToDelete.name[0] = 28;
+ P2CStr(fileToDelete.name);
+ sprintf(currpath,"%s~%d",(char *)fileToDelete.name,Num);
+ C2PStr(currpath);
+ C2PStr((char *)fileToDelete.name);
+ err = HRename (fileToDelete.vRefNum, fileToDelete.parID,
+ fileToDelete.name, (unsigned char *) currpath);
+ err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+ (unsigned char *) currpath, trashfolder.parID,
+ trashfolder.name);
+ }
+ }
+
+sstrcpy(lastpath,currpath);
+return err;
+}
+
+
+
+#endif /* #ifdef MACZIP */
+
+
+
+
+/*
+ * int open(const char *path, int oflag)
+ *
+ * Opens a file stream.
+ */
+int my_open(char *path, int oflag)
+{
+ FSSpec spec;
+ char permission;
+ HParamBlockRec hpb;
+ OSErr err, errno;
+ Boolean targetIsFolder, wasAliased;
+
+ AssertStr(path,path)
+
+ /* Setup permission */
+ if ((oflag & 0x03) == O_RDWR)
+ permission = fsRdWrPerm;
+ else
+ permission = (oflag & O_RDONLY) ? fsRdPerm : 0 + (oflag & O_WRONLY) ? fsWrPerm : 0;
+
+ FSpLocationFromFullPath(strlen(path),path, &spec);
+ if ((oflag & (O_ALIAS | O_NRESOLVE)) == 0)
+ ResolveAliasFile(&spec, true, &targetIsFolder, &wasAliased);
+ hpb.fileParam.ioNamePtr = spec.name;
+ hpb.fileParam.ioVRefNum = spec.vRefNum;
+ hpb.fileParam.ioDirID = spec.parID;
+ hpb.ioParam.ioPermssn = permission;
+
+ if (oflag & O_RSRC) /* open the resource fork of the file */
+ err = PBHOpenRFSync(&hpb);
+ else /* open the data fork of the file */
+ err = PBHOpenDFSync(&hpb);
+
+ if ((err == fnfErr) && (oflag & O_CREAT)) {
+ hpb.fileParam.ioFlVersNum = 0;
+ err = PBHCreateSync(&hpb);
+ if (err == noErr) {
+ /* Set the finder info */
+ unsigned long secs;
+ unsigned long isbinary = oflag & O_BINARY;
+
+ hpb.fileParam.ioFlFndrInfo.fdType = '\?\?\?\?';
+ hpb.fileParam.ioFlFndrInfo.fdCreator = '\?\?\?\?';
+ hpb.fileParam.ioFlFndrInfo.fdFlags = 0;
+ if (oflag & O_ALIAS) /* set the alias bit */
+ hpb.fileParam.ioFlFndrInfo.fdFlags = kIsAlias;
+ else /* clear all flags */
+ hpb.fileParam.ioFlFndrInfo.fdFlags = 0;
+
+ GetDateTime(&secs);
+ hpb.fileParam.ioFlCrDat = hpb.fileParam.ioFlMdDat = secs;
+ PBHSetFInfoSync(&hpb);
+ }
+
+ if (err && (err != dupFNErr)) {
+ errno = err; return -1;
+ }
+
+ if (oflag & O_RSRC) /* open the resource fork of the file */
+ err = PBHOpenRFSync(&hpb);
+ else /* open the data fork of the file */
+ err = PBHOpenDFSync(&hpb);
+ }
+
+ if (err && (err != dupFNErr) && (err != opWrErr)) {
+ errno = err; return -1;
+ }
+
+ if (oflag & O_TRUNC) {
+ IOParam pb;
+
+ pb.ioRefNum = hpb.ioParam.ioRefNum;
+ pb.ioMisc = 0L;
+ err = PBSetEOFSync((ParmBlkPtr)&pb);
+ if (err != noErr) {
+ errno = err; return -1;
+ }
+ }
+
+ if (oflag & O_APPEND) lseek(hpb.ioParam.ioRefNum,0,SEEK_END);
+
+ return (hpb.ioParam.ioRefNum);
+}
+
+
+
+
+
diff --git a/macos/source/macopen.h b/macos/source/macopen.h
new file mode 100644
index 0000000..152bceb
--- /dev/null
+++ b/macos/source/macopen.h
@@ -0,0 +1,21 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef __MACOPEN_H__
+#define __MACOPEN_H__
+
+#include <stdio.h>
+#include <Files.h>
+
+
+FILE *MacFopen(const char *path, const char *mode);
+int MacOpen(const char *path, int oflag, ...);
+
+int my_open(char *path, int oflag);
+
+#endif /* __MACOPEN_H__ */
diff --git a/macos/source/macos.c b/macos/source/macos.c
new file mode 100644
index 0000000..935c9a1
--- /dev/null
+++ b/macos/source/macos.c
@@ -0,0 +1,1079 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ macos.c
+
+ Macintosh-specific routines for use with Info-ZIP's Zip 2.3 and later.
+
+ ---------------------------------------------------------------------------*/
+
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include "zip.h"
+
+#include "revision.h"
+#include "crypt.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sound.h>
+
+#include <unistd.h>
+
+#include <Strings.h>
+#include <setjmp.h>
+
+/* #include "charmap.h" */
+#include "helpers.h"
+#include "macstuff.h"
+#include "pathname.h"
+#include "recurse.h"
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+#define PATH_END MacPathEnd
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+int error_level; /* used only in ziperr() */
+
+
+/* Note: sizeof() returns the size of this allusion
+ 13 is current length of "XtraStuf.mac:" */
+extern const char ResourceMark[13]; /* var is initialized in file pathname.c */
+
+
+extern jmp_buf EnvForExit;
+MacZipGlobals MacZip;
+
+unsigned long count_of_Zippedfiles = 0;
+
+
+/*****************************************************************************/
+/* Module level Vars */
+/*****************************************************************************/
+
+static const char MacPathEnd = ':'; /* the Macintosh dir separator */
+
+/* Inform Progress vars */
+long estTicksToFinish;
+long createTime;
+long updateTicks;
+
+static char *Time_Est_strings[] = {
+ "Zipping Files; Items done:",
+ "More than 24 hours",
+ "More than %s hours",
+ "About %s hours, %s minutes",
+ "About an hour",
+ "Less than an hour",
+ "About %s minutes, %s seconds",
+ "About a minute",
+ "Less than a minute",
+ "About %s seconds",
+ "About a second",
+ "About 1 minute, %s seconds"};
+
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+int DoCurrentDir(void);
+
+void DoAboutBox(void);
+void DoQuit(void);
+void DoEventLoop(void);
+
+void ZipInitAllVars(void);
+void UserStop(void);
+Boolean IsZipFile(char *name);
+
+static long EstimateCompletionTime(const long progressMax,
+ const long progressSoFar, unsigned char percent);
+static void UpdateTimeToComplete(void);
+
+
+
+
+#ifdef USE_SIOUX
+#include <sioux.h>
+void DoWarnUserDupVol( char *FullPath );
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+/*
+** Standalone Unzip with Metrowerks SIOUX starts here
+**
+*/
+int main(int argc, char **argv)
+{
+ int return_code;
+
+ SIOUXSettings.asktosaveonclose = FALSE;
+ SIOUXSettings.showstatusline = TRUE;
+
+ SIOUXSettings.columns = 100;
+ SIOUXSettings.rows = 40;
+
+ /* 30 = MacZip Johnny Lee's; 40 = new (my) MacZip */
+ MacZip.MacZipMode = NewZipMode_EF;
+
+ argc = ccommand(&argv);
+ if (verbose) PrintArguments(argc, argv);
+
+ ZipInitAllVars();
+
+ return_code = zipmain(argc, argv);
+
+ if (verbose) printf("\n\n Finish");
+ return return_code;
+}
+
+
+
+/*
+** SIOUX needs no extra event handling
+**
+*/
+
+void UserStop(void)
+{
+};
+
+
+
+
+/*
+** Password enter function '*' printed for each char
+**
+*/
+
+int macgetch(void)
+{
+ WindowPtr whichWindow;
+ EventRecord theEvent;
+ char c; /* one-byte buffer for read() to use */
+
+ do {
+ SystemTask();
+ if (!GetNextEvent(everyEvent, &theEvent))
+ theEvent.what = nullEvent;
+ else {
+ switch (theEvent.what) {
+ case keyDown:
+ c = theEvent.message & charCodeMask;
+ break;
+ case mouseDown:
+ if (FindWindow(theEvent.where, &whichWindow) ==
+ inSysWindow)
+ SystemClick(&theEvent, whichWindow);
+ break;
+ case updateEvt:
+ break;
+ }
+ }
+ } while (theEvent.what != keyDown);
+
+ printf("*");
+ fflush(stdout);
+
+ return (int)c;
+}
+
+#endif
+
+
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+/*
+** Print Compilers version and compile time/date
+**
+*/
+
+void version_local()
+{
+/* prints e.g:
+Compiled with Metrowerks CodeWarrior version 2000 for PowerPC Processor
+ compile time: Feb 4 1998 17:49:49.
+*/
+
+static ZCONST char CompiledWith[] =
+ "\n\nCompiled with %s %x for %s \n %s %s %s.\n\n";
+
+ printf(CompiledWith,
+
+
+#ifdef __MWERKS__
+ " Metrowerks CodeWarrior version", __MWERKS__,
+#endif
+
+
+#ifdef __MC68K__
+ " MC68K Processor",
+#else
+ " PowerPC Processor",
+#endif
+
+#ifdef __DATE__
+ "compile time: ", __DATE__, __TIME__
+#else
+ "", "", ""
+#endif
+ );
+} /* end function version_local() */
+
+
+
+
+
+/*
+** Deletes a dir if the switch '-m' is used
+**
+*/
+
+int deletedir(char *path)
+{
+static char Num = 0;
+static FSSpec trashfolder;
+static Boolean FirstCall = true;
+static Boolean Immediate_File_Deletion = false;
+OSErr err;
+FSSpec dirToDelete;
+char currpath[NAME_MAX], *envptr;
+CInfoPBRec fpb;
+
+/* init this function */
+if ((path == NULL) ||
+ (strlen(path) == 0))
+ {
+ Num = 0;
+ FirstCall = true;
+ return -1;
+ }
+
+UserStop();
+
+GetCompletePath(currpath,path,&dirToDelete, &err);
+
+if (FirstCall == true)
+ {
+ FirstCall = false;
+ envptr = getenv("Immediate_File_Deletion");
+ if (!(envptr == (char *)NULL || *envptr == '\0'))
+ {
+ if (stricmp(envptr,"yes") == 0)
+ Immediate_File_Deletion = true;
+ else
+ Immediate_File_Deletion = false;
+ }
+ err = FSpFindFolder(dirToDelete.vRefNum, kTrashFolderType,
+ kDontCreateFolder,&trashfolder);
+ printerr("FSpFindFolder:",err,err,__LINE__,__FILE__,path);
+ }
+
+ fpb.dirInfo.ioNamePtr = dirToDelete.name;
+ fpb.dirInfo.ioVRefNum = dirToDelete.vRefNum;
+ fpb.dirInfo.ioDrDirID = dirToDelete.parID;
+ fpb.dirInfo.ioFDirIndex = 0;
+
+ err = PBGetCatInfoSync(&fpb);
+ printerr("PBGetCatInfo deletedir ", err, err,
+ __LINE__, __FILE__, "");
+
+if (fpb.dirInfo.ioDrNmFls > 0)
+ {
+ return 0; /* do not move / delete folders which are not empty */
+ }
+
+if (Immediate_File_Deletion)
+ {
+ err = FSpDelete(&dirToDelete);
+ return err;
+ }
+
+err = CatMove (dirToDelete.vRefNum, dirToDelete.parID,
+ dirToDelete.name, trashfolder.parID, trashfolder.name);
+
+/* -48 = file is already existing so we have to rename it before
+ moving the file */
+if (err == -48)
+ {
+ Num++;
+ if (dirToDelete.name[0] >= 28) /* cut foldername if to long */
+ dirToDelete.name[0] = 28;
+ P2CStr(dirToDelete.name);
+ sprintf(currpath,"%s~%d",(char *)dirToDelete.name,Num);
+ C2PStr(currpath);
+ C2PStr((char *)dirToDelete.name);
+ err = HRename (dirToDelete.vRefNum, dirToDelete.parID,
+ dirToDelete.name, (unsigned char *) currpath);
+
+ err = CatMove (dirToDelete.vRefNum, dirToDelete.parID,
+ (unsigned char *) currpath, trashfolder.parID,
+ trashfolder.name);
+ }
+
+return err;
+}
+
+
+
+
+/*
+** Set the file-type so the archive will get the correct icon, type
+** and creator code.
+*/
+
+void setfiletype(char *new_f, unsigned long Creator, unsigned long Type)
+{
+OSErr err;
+
+if (strcmp(zipfile, new_f) == 0)
+ err = FSpChangeCreatorType(&MacZip.ZipFileSpec, Creator, Type);
+printerr("FSpChangeCreatorType:", err, err, __LINE__, __FILE__, new_f);
+
+return;
+}
+
+
+
+
+
+/*
+** Convert the external (native) filename into Zip's internal Unix compatible
+** name space.
+*/
+
+char *ex2in(char *externalFilen, int isdir, int *pdosflag)
+/* char *externalFilen external file name */
+/* int isdir input: externalFilen is a directory */
+/* int *pdosflag output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *internalFilen; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ char *Pathname;
+ char buffer[NAME_MAX];
+ int dosflag;
+
+ AssertStr(externalFilen, externalFilen)
+ AssertBool(isdir,"")
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ for (t = externalFilen; *t == PATH_END; t++)
+ ;
+
+ if (!MacZip.StoreFullPath)
+ {
+ Pathname = StripPartialDir(buffer, MacZip.SearchDir,t);
+ }
+ else
+ {
+ Pathname = t;
+ }
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ {
+ t = last(Pathname, PATH_END);
+ }
+ else t = Pathname;
+
+ /* Malloc space for internal name and copy it */
+ if ((internalFilen = malloc(strlen(t) + 10 + strlen(ResourceMark) )) == NULL)
+ return NULL;
+
+ sstrcpy(internalFilen, t);
+
+ /* we have to eliminate illegal chars:
+ * The name space for Mac filenames and Zip filenames (unix style names)
+ * do both include all printable extended-ASCII characters. The only
+ * difference we have to take care of is the single special character
+ * used as path delimiter:
+ * ':' on MacOS and '/' on Unix and '\' on Dos.
+ * So, to convert between Mac filenames and Unix filenames without any
+ * loss of information, we simply interchange ':' and '/'. Additionally,
+ * we try to convert the coding of the extended-ASCII characters into
+ * InfoZip's standard ISO 8859-1 codepage table.
+ */
+ MakeCompatibleString(internalFilen, ':', '/', '/', ':',
+ MacZip.CurrTextEncodingBase);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+
+ if (isdir)
+ {
+ return internalFilen; /* avoid warning on unused variable */
+ }
+
+ if (dosify)
+ {
+ msname(internalFilen);
+ printf("\n ex2in: %s",internalFilen);
+ }
+
+ return internalFilen;
+}
+
+
+
+/*
+** Collect all filenames. Go through all directories
+**
+*/
+
+int wild(char *Pathpat)
+ /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+ file system. Return an error code in the ZE_ class. */
+{
+FSSpec Spec;
+char fullpath[NAME_MAX];
+OSErr err;
+
+AssertStr(Pathpat, Pathpat);
+
+if (noisy) printf("%s \n\n",GetZipVersionsInfo());
+
+if (extra_fields == 0)
+ {
+ MacZip.DataForkOnly = true;
+ }
+
+/* for switch '-R' -> '.' means current dir */
+if (strcmp(Pathpat,".") == 0) sstrcpy(Pathpat,"*");
+
+sstrcpy(MacZip.Pattern,Pathpat);
+
+if (recurse)
+ {
+ MacZip.StoreFoldersAlso = true;
+ MacZip.SearchLevels = 0; /* if 0 we aren't checking levels */
+ }
+else
+ {
+ MacZip.StoreFoldersAlso = false;
+ MacZip.SearchLevels = 1;
+ }
+
+/* make complete path */
+GetCompletePath(fullpath, MacZip.Pattern, &Spec,&err);
+err = PrintUserHFSerr((err != -43) && (err != 0), err, MacZip.Pattern);
+printerr("GetCompletePath:", err, err, __LINE__, __FILE__, fullpath);
+
+/* extract the filepattern */
+GetFilename(MacZip.Pattern, fullpath);
+
+/* extract Path and get FSSpec of search-path */
+/* get FSSpec of search-path ; we need a dir to start
+ searching for filenames */
+TruncFilename(MacZip.SearchDir, fullpath);
+GetCompletePath(MacZip.SearchDir, MacZip.SearchDir, &Spec,&err);
+
+if (noisy) {
+ if (MacZip.SearchLevels == 0)
+ {
+ printf("\nSearch Pattern: [%s] Levels: all", MacZip.Pattern);
+ }
+ else
+ {
+ printf("\nSearch Pattern: [%s] Levels: %d", MacZip.Pattern,
+ MacZip.SearchLevels);
+ }
+ printf("\nSearch Path: [%s]", MacZip.SearchDir);
+ printf("\nZip-File: [%s] \n",MacZip.ZipFullPath);
+
+}
+
+/* we are working only with pathnames;
+ * this can cause big problems on a mac ...
+ */
+if (CheckMountedVolumes(MacZip.SearchDir) > 1)
+ DoWarnUserDupVol(MacZip.SearchDir);
+
+/* start getting all filenames */
+err = FSpRecurseDirectory(&Spec, MacZip.SearchLevels);
+printerr("FSpRecurseDirectory:", err, err, __LINE__, __FILE__, "");
+
+return ZE_OK;
+}
+
+
+
+/*
+** Convert the internal filename into a external (native).
+** The user will see this modified filename.
+** For more performance:
+** I do not completly switch back to the native macos filename.
+** The user will still see directory separator '/' and the converted
+** charset.
+*/
+
+char *in2ex(char *n) /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ AssertStr(n,n)
+
+ if ((x = malloc(strlen(n) + 1)) == NULL)
+ return NULL;
+
+ RfDfFilen2Real(x, n, MacZip.MacZipMode, MacZip.DataForkOnly,
+ &MacZip.CurrentFork);
+
+ return x;
+}
+
+
+
+
+/*
+** Process on filenames. This function will be called to collect
+** the filenames.
+*/
+
+int procname(char *filename, /* name to process */
+ int caseflag) /* true to force case-sensitive match
+ (always false on a Mac) */
+/* Process a name . Return
+ an error code in the ZE_ class. */
+{
+ int rc; /* matched flag */
+
+AssertBool(caseflag,"caseflag")
+AssertStr(filename,filename)
+
+ /* add or remove name of file */
+rc = newname(filename, MacZip.isDirectory, caseflag);
+
+return rc;
+}
+
+
+
+
+ulg filetime(
+char *f, /* name of file to get info on */
+ulg *a, /* return value: file attributes */
+long *n, /* return value: file size */
+iztimes *t) /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+
+ AssertStr(f,f)
+
+ if (strlen(f) == 0) return 0;
+
+ if (SSTAT(f, &s) != 0)
+ /* Accept about any file kind including directories
+ * (stored with trailing : with -r option)
+ */
+ return 0;
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if (MacZip.isDirectory) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & UNX_IFMT) == UNX_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime; /* on Mac, st_ctime contains creation time! */
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+
+
+void stamp(char *f, ulg d)
+/* char *f; name of file to change */
+/* ulg d; dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ time_t u[2]; /* argument for utime() */
+
+f = f;
+
+ /* Convert DOS time to time_t format in u */
+
+ u[0] = u[1] = dos2unixtime(d);
+/* utime(f, u); */
+}
+
+
+
+
+/*
+** return only the longest part of the path:
+** second parameter: Volume:test folder:second folder:
+** third parameter: Volume:test folder:second folder:third folder:file
+** result will be: third folder:file
+** first parameter: contains string buffer that will be used to prepend
+** the "resource mark" part in front of the result when
+** a resource fork is processed in "M3" mode.
+**
+*/
+
+char *StripPartialDir(char *CompletePath,
+ const char *PartialPath, const char *FullPath)
+{
+const char *tmpPtr1 = PartialPath;
+const char *tmpPtr2 = FullPath;
+int result;
+
+Assert_it(CompletePath,"StripPartialDir","")
+AssertStrNoOverlap(FullPath,PartialPath,PartialPath)
+
+if (MacZip.DataForkOnly)
+ {
+ tmpPtr2 += strlen(tmpPtr1);
+ return (char *)tmpPtr2;
+ }
+
+switch (MacZip.MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ tmpPtr2 += strlen(tmpPtr1);
+ return (char *)tmpPtr2;
+ break;
+ }
+
+ case NewZipMode_EF:
+ { /* determine Fork type */
+ result = strncmp(FullPath, ResourceMark, sizeof(ResourceMark)-2);
+ if (result != 0)
+ { /* data fork */
+ MacZip.CurrentFork = DataFork;
+ tmpPtr2 += strlen(tmpPtr1);
+ return (char *)tmpPtr2;
+ }
+ else
+ { /* resource fork */
+ MacZip.CurrentFork = ResourceFork;
+ sstrcpy(CompletePath, ResourceMark);
+ tmpPtr2 += strlen(tmpPtr1);
+ tmpPtr2 += sizeof(ResourceMark);
+ sstrcat(CompletePath, tmpPtr2);
+ return (char *)CompletePath;
+ }
+ break;
+ }
+ }
+
+ return NULL; /* function should never reach this point */
+}
+
+
+
+
+/*
+** Init all global variables
+** Must be called for each zip-run
+*/
+
+void ZipInitAllVars(void)
+{
+getcwd(MacZip.CurrentPath, sizeof(MacZip.CurrentPath));
+/* MacZip.MacZipMode = JohnnyLee_EF; */
+MacZip.MacZipMode = NewZipMode_EF;
+
+MacZip.DataForkOnly = false;
+MacZip.CurrentFork = NoFork;
+
+MacZip.StoreFoldersAlso = false;
+
+MacZip.FoundFiles = 0;
+MacZip.FoundDirectories = 0;
+MacZip.RawCountOfItems = 0;
+MacZip.BytesOfData = 0;
+
+MacZip.StoreFullPath = false;
+MacZip.StatingProgress = false;
+MacZip.IncludeInvisible = false;
+
+MacZip.isMacStatValid = false;
+
+MacZip.CurrTextEncodingBase = FontScript();
+
+MacZip.HaveGMToffset = false;
+
+createTime = TickCount();
+estTicksToFinish = -1;
+updateTicks = 0;
+
+/* init some functions */
+IsZipFile(NULL);
+
+destroy(NULL);
+deletedir(NULL);
+ShowCounter(true);
+
+extra_fields = 1;
+error_level = 0;
+count_of_Zippedfiles = 0;
+}
+
+
+
+
+/*
+** Get the findercomment and store it as file-comment in the Zip-file
+**
+*/
+char *GetComment(char *filename)
+{
+OSErr err;
+static char buffer[NAME_MAX];
+char buffer2[NAME_MAX];
+char *tmpPtr;
+
+if (filename == NULL) return NULL;
+
+ /* now we can convert Unix-Path in HFS-Path */
+for (tmpPtr = filename; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == '/')
+ *tmpPtr = ':';
+
+if (MacZip.StoreFullPath)
+ { /* filename is already a fullpath */
+ sstrcpy(buffer,filename);
+ }
+else
+ { /* make a fullpath */
+ sstrcpy(buffer,MacZip.SearchDir);
+ sstrcat(buffer,filename);
+ }
+
+/* make fullpath and get FSSpec */
+/* Unfortunately: I get only the converted filename here */
+/* so filenames with extended characters can not be found */
+GetCompletePath(buffer2,buffer, &MacZip.fileSpec, &err);
+printerr("GetCompletePath:",(err != -43) && (err != -120) && (err != 0) ,
+ err,__LINE__,__FILE__,buffer);
+
+err = FSpDTGetComment(&MacZip.fileSpec, (unsigned char *) buffer);
+printerr("FSpDTGetComment:", (err != -5012) && (err != 0), err,
+ __LINE__, __FILE__, filename);
+P2CStr((unsigned char *) buffer);
+if (err == -5012) return NULL; /* no finder-comments found */
+
+if (noisy) printf("\n%32s -> %s",filename, buffer);
+/*
+Beside the script change we need only to change 0x0d in 0x0a
+so the last two arguments are not needed and does nothing.
+*/
+MakeCompatibleString(buffer, 0x0d, 0x0a, ' ', ' ',
+ MacZip.CurrTextEncodingBase);
+
+return buffer;
+}
+
+
+
+
+/*
+** Print a progress indicator for stating the files
+**
+*/
+
+void PrintStatProgress(char *msg)
+{
+
+if (!noisy) return; /* do no output if noisy is false */
+
+MacZip.StatingProgress = true;
+
+if (strcmp(msg,"done") == 0)
+ {
+ MacZip.StatingProgress = false;
+ printf("\n ... done \n\n");
+ }
+else printf("\n %s",msg);
+
+}
+
+
+
+
+void InformProgress(const long progressMax, const long progressSoFar )
+{
+int curr_percent;
+char no_time[5] = "...";
+
+curr_percent = percent(progressMax, progressSoFar);
+
+if (curr_percent < 95)
+ {
+ estTicksToFinish = EstimateCompletionTime(progressMax,
+ progressSoFar, curr_percent);
+ }
+else
+ {
+ rightStatusString(no_time);
+ leftStatusString(no_time);
+ }
+
+updateTicks = TickCount() + 60;
+return;
+}
+
+
+void ShowCounter(Boolean reset)
+{
+static char statusline[100];
+static unsigned long filecount = 0;
+
+if (reset)
+ {
+ filecount = 0;
+ return;
+ }
+
+if (noisy)
+ {
+ sprintf(statusline, "%6d", filecount++);
+ rightStatusString(statusline);
+ }
+}
+
+
+static long EstimateCompletionTime(const long progressMax,
+ const long progressSoFar,
+ unsigned char curr_percent)
+{
+ long max = progressMax, value = progressSoFar;
+ static char buf[100];
+ unsigned long ticksTakenSoFar = TickCount() - createTime;
+ float currentRate = (float) ticksTakenSoFar / (float) value;
+ long newEst = (long)( currentRate * (float)( max - value ));
+
+ sprintf(buf, "%d [%d%%]",progressSoFar, curr_percent);
+ rightStatusString(buf);
+
+ estTicksToFinish = newEst;
+
+ UpdateTimeToComplete();
+
+return estTicksToFinish;
+}
+
+
+
+
+
+static void UpdateTimeToComplete(void)
+{
+ short days, hours, minutes, seconds;
+ char estStr[255];
+ Str15 xx, yy;
+ short idx = 0;
+
+ if ( estTicksToFinish == -1 )
+ return;
+
+ days = estTicksToFinish / 5184000L;
+ hours = ( estTicksToFinish - ( days * 5184000L )) / 216000L;
+ minutes = ( estTicksToFinish - ( days * 5184000L ) -
+ ( hours * 216000L )) / 3600L;
+ seconds = ( estTicksToFinish - ( days * 5184000L ) -
+ ( hours * 216000L ) - ( minutes * 3600L )) / 60L;
+
+ xx[0] = 0;
+ yy[0] = 0;
+
+ if ( days )
+ {
+ /* "more than 24 hours" */
+
+ idx = 1;
+ goto setEstTimeStr;
+ }
+
+ if ( hours >= 8 )
+ {
+ /* "more than x hours" */
+
+ NumToString( hours, xx );
+ idx = 2;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 252000L ) /* > 1hr, 10 minutes */
+ {
+ /* "about x hours, y minutes" */
+
+ NumToString( hours, xx );
+ NumToString( minutes, yy );
+ idx = 3;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 198000L ) /* > 55 minutes */
+ {
+ /* "about an hour" */
+ idx = 4;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 144000L ) /* > 40 minutes */
+ {
+ /* "less than an hour" */
+
+ idx = 5;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 4200L ) /* > 1 minute, 10 sec */
+ {
+ /* "about x minutes, y seconds */
+
+ NumToString( minutes, xx );
+ NumToString( seconds, yy );
+
+ if ( minutes == 1 )
+ idx = 11;
+ else
+ idx = 6;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 3000L ) /* > 50 seconds */
+ {
+ /* "about a minute" */
+
+ idx = 7;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 1500L ) /* > 25 seconds */
+ {
+ /* "less than a minute" */
+
+ idx = 8;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 120L ) /* > 2 seconds */
+ {
+ NumToString( seconds, xx );
+ idx = 9;
+ goto setEstTimeStr;
+ }
+
+ idx = 10;
+
+ setEstTimeStr:
+ sprintf(estStr,Time_Est_strings[idx],P2CStr(xx),P2CStr(yy));
+ leftStatusString((char *)estStr);
+}
+
+
+
+
+
+/*
+** Just return the zip version
+**
+*/
+
+char *GetZipVersionsInfo(void)
+{
+static char ZipVersion[100];
+
+sprintf(ZipVersion, "Zip Module\n%d.%d%d%s of %s", Z_MAJORVER, Z_MINORVER,
+ Z_PATCHLEVEL, Z_BETALEVEL, REVDATE);
+
+return ZipVersion;
+}
+
+
+
+
+#ifndef USE_SIOUX
+
+/*
+** Just return the copyright message
+**
+*/
+
+char *GetZipCopyright(void)
+{
+static char CopyR[300];
+
+sstrcpy(CopyR, copyright[0]);
+sstrcat(CopyR, copyright[1]);
+sstrcat(CopyR, "\r\rPlease send bug reports to the authors at\r"\
+ "Zip-Bugs@lists.wku.edu");
+
+return CopyR;
+}
+
+
+
+
+/*
+** Just return the compilers date/time
+**
+*/
+
+char *GetZipVersionLocal(void)
+{
+static char ZipVersionLocal[50];
+
+sprintf(ZipVersionLocal, "[%s %s]", __DATE__, __TIME__);
+
+return ZipVersionLocal;
+}
+
+#endif /* #ifndef USE_SIOUX */
+
+
+
+
diff --git a/macos/source/macstuff.c b/macos/source/macstuff.c
new file mode 100644
index 0000000..0323607
--- /dev/null
+++ b/macos/source/macstuff.c
@@ -0,0 +1,1724 @@
+/*
+These Functions were originally part of More Files version 1.4.8
+
+More Files fixes many of the broken or underfunctional
+parts of the file system.
+
+More Files
+
+A collection of File Manager and related routines
+
+by Jim Luther (Apple Macintosh Developer Technical Support Emeritus)
+with significant code contributions by Nitin Ganatra
+(Apple Macintosh Developer Technical Support Emeritus)
+Copyright 1992-1998 Apple Computer, Inc.
+Portions copyright 1995 Jim Luther
+All rights reserved.
+
+The Package "More Files" is distributed under the following
+license terms:
+
+ "You may incorporate this sample code into your
+ applications without restriction, though the
+ sample code has been provided "AS IS" and the
+ responsibility for its operation is 100% yours.
+ However, what you are not permitted to do is to
+ redistribute the source as "DSC Sample Code" after
+ having made changes. If you're going to
+ redistribute the source, we require that you make
+ it clear in the source that the code was descended
+ from Apple Sample Code, but that you've made
+ changes."
+
+
+The following changes are made by Info-ZIP:
+
+- The only changes are made by pasting the functions
+ (mostly found in MoreFilesExtras.c / MoreFiles.c)
+ directly into macstuff.c / macstuff.h and slightly
+ reformatting the text (replacement of TABs by spaces,
+ removal/replacement of non-ASCII characters).
+ The code itself is NOT changed.
+
+This file has been modified by Info-ZIP for use in MacZip.
+This file is NOT part of the original package More Files.
+
+More Files can be found on the MetroWerks CD and Developer CD from
+Apple. You can also download the latest version from:
+
+ http://members.aol.com/JumpLong/#MoreFiles
+
+Jim Luther's Home-page:
+ http://members.aol.com/JumpLong/
+
+
+*/
+
+#include <string.h>
+
+
+#include "macstuff.h"
+
+
+
+extern int errno;
+
+static OSErr GetCommentFromDesktopFile(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ Str255 comment);
+
+static OSErr GetCommentID(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ short *commentID);
+
+static OSErr GetDesktopFileName(short vRefNum,
+ Str255 desktopName);
+
+
+enum
+{
+ kBNDLResType = 'BNDL',
+ kFREFResType = 'FREF',
+ kIconFamResType = 'ICN#',
+ kFCMTResType = 'FCMT',
+ kAPPLResType = 'APPL'
+};
+
+
+/*****************************************************************************/
+
+/*
+** File Manager FSp calls
+*/
+
+/*****************************************************************************/
+
+pascal OSErr FSMakeFSSpecCompat(short vRefNum,
+ long dirID,
+ ConstStr255Param fileName,
+ FSSpec *spec)
+{
+ OSErr result;
+
+#if !__MACOSSEVENORLATER
+ if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+ {
+ Boolean isDirectory;
+
+ result = GetObjectLocation(vRefNum, dirID, fileName,
+ &(spec->vRefNum), &(spec->parID), spec->name,
+ &isDirectory);
+ }
+ else
+#endif /* !__MACOSSEVENORLATER */
+ {
+ /* Let the file system create the FSSpec if it can since it does the job */
+ /* much more efficiently than I can. */
+ result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
+
+ /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
+ /* returned in the parID field when making an FSSpec to the volume's */
+ /* root directory by passing a full pathname in MakeFSSpec's */
+ /* fileName parameter. Fixed in Mac OS 8.1 */
+ if ( (result == noErr) && (spec->parID == 0) )
+ spec->parID = fsRtParID;
+ }
+ return ( result );
+}
+
+
+/*****************************************************************************/
+/* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
+
+#if !__MACOSSEVENORLATER
+static Boolean FSHasFSSpecCalls(void)
+{
+ long response;
+#if !GENERATENODATA
+ static Boolean tested = false;
+ static Boolean result = false;
+#else
+ Boolean result = false;
+#endif
+
+#if !GENERATENODATA
+ if ( !tested )
+ {
+ tested = true;
+#endif
+ if ( Gestalt(gestaltFSAttr, &response) == noErr )
+ {
+ result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
+ }
+#if !GENERATENODATA
+ }
+#endif
+ return ( result );
+}
+#endif /* !__MACOSSEVENORLATER */
+
+
+
+/*****************************************************************************/
+/* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
+/* except for FSpExchangeFiles. */
+
+#if !__MACOSSEVENORLATER
+static Boolean QTHasFSSpecCalls(void)
+{
+ long response;
+#if !GENERATENODATA
+ static Boolean tested = false;
+ static Boolean result = false;
+#else
+ Boolean result = false;
+#endif
+
+#if !GENERATENODATA
+ if ( !tested )
+ {
+ tested = true;
+#endif
+ result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
+#if !GENERATENODATA
+ }
+#endif
+ return ( result );
+}
+#endif /* !__MACOSSEVENORLATER */
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpGetDefaultDir --
+ *
+ * This function gets the current default directory.
+ *
+ * Results:
+ * The provided FSSpec is changed to point to the "default"
+ * directory. The function returns what ever errors
+ * FSMakeFSSpecCompat may encounter.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int FSpGetDefaultDir(FSSpecPtr dirSpec) /* On return the default directory. */
+{
+ OSErr err;
+ short vRefNum = 0;
+ long int dirID = 0;
+
+ err = HGetVol(NULL, &vRefNum, &dirID);
+
+ if (err == noErr) {
+ err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
+ dirSpec);
+ }
+
+ return err;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpSetDefaultDir --
+ *
+ * This function sets the default directory to the directory
+ * pointed to by the provided FSSpec.
+ *
+ * Results:
+ * The function returns what ever errors HSetVol may encounter.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int FSpSetDefaultDir(FSSpecPtr dirSpec) /* The new default directory. */
+{
+ OSErr err;
+
+ /*
+ * The following special case is needed to work around a bug
+ * in the Macintosh OS. (Acutally PC Exchange.)
+ */
+
+ if (dirSpec->parID == fsRtParID) {
+ err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
+ } else {
+ err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
+ }
+
+ return err;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpFindFolder --
+ *
+ * This function is a version of the FindFolder function that
+ * returns the result as a FSSpec rather than a vRefNum and dirID.
+ *
+ * Results:
+ * Results will be simaler to that of the FindFolder function.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpFindFolder(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec) /* Pointer to resulting directory. */
+{
+ short foundVRefNum;
+ long foundDirID;
+ OSErr err;
+
+ err = FindFolder(vRefNum, folderType, createFolder,
+ &foundVRefNum, &foundDirID);
+ if (err != noErr) {
+ return err;
+ }
+
+ err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
+ return err;
+}
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpPathFromLocation --
+ *
+ * This function obtains a full path name for a given macintosh
+ * FSSpec. Unlike the More Files function FSpGetFullPath, this
+ * function will return a C string in the Handle. It also will
+ * create paths for FSSpec that do not yet exist.
+ *
+ * Results:
+ * OSErr code.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpPathFromLocation(
+ FSSpec *spec, /* The location we want a path for. */
+ int *length, /* Length of the resulting path. */
+ Handle *fullPath) /* Handle to path. */
+{
+ OSErr err;
+ FSSpec tempSpec;
+ CInfoPBRec pb;
+
+ *fullPath = NULL;
+
+ /*
+ * Make a copy of the input FSSpec that can be modified.
+ */
+ BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+
+ if (tempSpec.parID == fsRtParID) {
+ /*
+ * The object is a volume. Add a colon to make it a full
+ * pathname. Allocate a handle for it and we are done.
+ */
+ tempSpec.name[0] += 2;
+ tempSpec.name[tempSpec.name[0] - 1] = ':';
+ tempSpec.name[tempSpec.name[0]] = '\0';
+
+ err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ } else {
+ /*
+ * The object isn't a volume. Is the object a file or a directory?
+ */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrDirID = tempSpec.parID;
+ pb.dirInfo.ioFDirIndex = 0;
+ err = PBGetCatInfoSync(&pb);
+
+ if ((err == noErr) || (err == fnfErr)) {
+ /*
+ * If the file doesn't currently exist we start over. If the
+ * directory exists everything will work just fine. Otherwise we
+ * will just fail later. If the object is a directory, append a
+ * colon so full pathname ends with colon.
+ */
+ if (err == fnfErr) {
+ BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+ } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) {
+ tempSpec.name[0] += 1;
+ tempSpec.name[tempSpec.name[0]] = ':';
+ }
+
+ /*
+ * Create a new Handle for the object - make it a C string.
+ */
+ tempSpec.name[0] += 1;
+ tempSpec.name[tempSpec.name[0]] = '\0';
+ err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ if (err == noErr) {
+ /*
+ * Get the ancestor directory names - loop until we have an
+ * error or find the root directory.
+ */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrParID = tempSpec.parID;
+ do {
+ pb.dirInfo.ioFDirIndex = -1;
+ pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+ err = PBGetCatInfoSync(&pb);
+ if (err == noErr) {
+ /*
+ * Append colon to directory name and add
+ * directory name to beginning of fullPath.
+ */
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+
+ (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
+ tempSpec.name[0]);
+ err = MemError();
+ }
+ } while ( (err == noErr) &&
+ (pb.dirInfo.ioDrDirID != fsRtDirID) );
+ }
+ }
+ }
+
+ /*
+ * On error Dispose the handle, set it to NULL & return the err.
+ * Otherwise, set the length & return.
+ */
+ if (err == noErr) {
+ *length = GetHandleSize(*fullPath) - 1;
+ } else {
+ if ( *fullPath != NULL ) {
+ DisposeHandle(*fullPath);
+ }
+ *fullPath = NULL;
+ *length = 0;
+ }
+
+ return err;
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetDirectoryID(const FSSpec *spec,
+ long *theDirID,
+ Boolean *isDirectory)
+{
+ return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
+ theDirID, isDirectory) );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetDirectoryID(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ long *theDirID,
+ Boolean *isDirectory)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+ if ( error == noErr )
+ {
+ *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+ if ( *isDirectory )
+ {
+ *theDirID = pb.dirInfo.ioDrDirID;
+ }
+ else
+ {
+ *theDirID = pb.hFileInfo.ioFlParID;
+ }
+ }
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetCatInfoNoName(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ CInfoPBPtr pb)
+{
+ Str31 tempName;
+ OSErr error;
+
+ /* Protection against File Sharing problem */
+ if ( (name == NULL) || (name[0] == 0) )
+ {
+ tempName[0] = 0;
+ pb->dirInfo.ioNamePtr = tempName;
+ pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ else
+ {
+ pb->dirInfo.ioNamePtr = (StringPtr)name;
+ pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ pb->dirInfo.ioVRefNum = vRefNum;
+ pb->dirInfo.ioDrDirID = dirID;
+ error = PBGetCatInfoSync(pb);
+ pb->dirInfo.ioNamePtr = NULL;
+ return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr GetObjectLocation(short vRefNum,
+ long dirID,
+ ConstStr255Param pathname,
+ short *realVRefNum,
+ long *realParID,
+ Str255 realName,
+ Boolean *isDirectory)
+{
+ OSErr error;
+ CInfoPBRec pb;
+ Str255 tempPathname;
+
+ /* clear results */
+ *realVRefNum = 0;
+ *realParID = 0;
+ realName[0] = 0;
+
+ /*
+ ** Get the real vRefNum
+ */
+ error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
+ if ( error == noErr )
+ {
+ /*
+ ** Determine if the object already exists and if so,
+ ** get the real parent directory ID if it's a file
+ */
+
+ /* Protection against File Sharing problem */
+ if ( (pathname == NULL) || (pathname[0] == 0) )
+ {
+ tempPathname[0] = 0;
+ pb.hFileInfo.ioNamePtr = tempPathname;
+ pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ else
+ {
+ pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBGetCatInfoSync(&pb);
+ if ( error == noErr )
+ {
+ /*
+ ** The file system object is present and we have the file's
+ ** real parID
+ */
+
+ /* Is it a directory or a file? */
+ *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+ if ( *isDirectory )
+ {
+ /*
+ ** It's a directory, get its name and parent dirID, and then
+ ** we're done
+ */
+
+ pb.dirInfo.ioNamePtr = realName;
+ pb.dirInfo.ioVRefNum = *realVRefNum;
+ /* pb.dirInfo.ioDrDirID already contains the dirID of the
+ directory object */
+ pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
+ error = PBGetCatInfoSync(&pb);
+
+ /* get the parent ID here, because the file system can return the */
+ /* wrong parent ID from the last call. */
+ *realParID = pb.dirInfo.ioDrParID;
+ }
+ else
+ {
+ /*
+ ** It's a file - use the parent directory ID from the last call
+ ** to GetCatInfoparse, get the file name, and then we're done
+ */
+ *realParID = pb.hFileInfo.ioFlParID;
+ error = GetFilenameFromPathname(pathname, realName);
+ }
+ }
+ else if ( error == fnfErr )
+ {
+ /*
+ ** The file system object is not present - see if its parent is present
+ */
+
+ /*
+ ** Parse to get the object name from end of pathname
+ */
+ error = GetFilenameFromPathname(pathname, realName);
+
+ /* if we can't get the object name from the end, we can't continue */
+ if ( error == noErr )
+ {
+ /*
+ ** What we want now is the pathname minus the object name
+ ** for example:
+ ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
+ ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
+ ** if pathname is ':dir:file' tempPathname becomes ':dir:'
+ ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
+ ** if pathname is ':file' tempPathname becomes ':'
+ ** if pathname is 'file or file:' tempPathname becomes ''
+ */
+
+ /* get a copy of the pathname */
+ BlockMoveData(pathname, tempPathname, pathname[0] + 1);
+
+ /* remove the object name */
+ tempPathname[0] -= realName[0];
+ /* and the trailing colon (if any) */
+ if ( pathname[pathname[0]] == ':' )
+ {
+ --tempPathname[0];
+ }
+
+ /* OK, now get the parent's directory ID */
+
+ /* Protection against File Sharing problem */
+ pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
+ if ( tempPathname[0] != 0 )
+ {
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ else
+ {
+ pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBGetCatInfoSync(&pb);
+ *realParID = pb.dirInfo.ioDrDirID;
+
+ *isDirectory = false; /* we don't know what the object is
+ really going to be */
+ }
+
+ if ( error != noErr )
+ {
+ error = dirNFErr; /* couldn't find parent directory */
+ }
+ else
+ {
+ error = fnfErr; /* we found the parent, but not the file */
+ }
+ }
+ }
+
+ return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr DetermineVRefNum(ConstStr255Param pathname,
+ short vRefNum,
+ short *realVRefNum)
+{
+ HParamBlockRec pb;
+ OSErr error;
+
+ error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+ if ( error == noErr )
+ {
+ *realVRefNum = pb.volumeParam.ioVRefNum;
+ }
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetFilenameFromPathname(ConstStr255Param pathname,
+ Str255 filename)
+{
+ short index;
+ short nameEnd;
+ OSErr error;
+
+ /* default to no filename */
+ filename[0] = 0;
+
+ /* check for no pathname */
+ if ( pathname != NULL )
+ {
+ /* get string length */
+ index = pathname[0];
+
+ /* check for empty string */
+ if ( index != 0 )
+ {
+ /* skip over last trailing colon (if any) */
+ if ( pathname[index] == ':' )
+ {
+ --index;
+ }
+
+ /* save the end of the string */
+ nameEnd = index;
+
+ /* if pathname ends with multiple colons, then this pathname refers */
+ /* to a directory, not a file */
+ if ( pathname[index] != ':' )
+ {
+ /* parse backwards until we find a colon or hit the beginning
+ of the pathname */
+ while ( (index != 0) && (pathname[index] != ':') )
+ {
+ --index;
+ }
+
+ /* if we parsed to the beginning of the pathname and the
+ pathname ended */
+ /* with a colon, then pathname is a full pathname to a volume,
+ not a file */
+ if ( (index != 0) || (pathname[pathname[0]] != ':') )
+ {
+ /* get the filename and return noErr */
+ filename[0] = (char)(nameEnd - index);
+ BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
+ error = noErr;
+ }
+ else
+ {
+ /* pathname to a volume, not a file */
+ error = notAFileErr;
+ }
+ }
+ else
+ {
+ /* directory, not a file */
+ error = notAFileErr;
+ }
+ }
+ else
+ {
+ /* empty string isn't a file */
+ error = notAFileErr;
+ }
+ }
+ else
+ {
+ /* NULL pathname isn't a file */
+ error = notAFileErr;
+ }
+
+ return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+/*
+** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
+** in cases where the returned volume name is not needed by the caller.
+** The pathname and vRefNum parameters are not touched, and the pb
+** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
+** the parameter block is always returned as NULL (since it might point
+** to the local tempPathname).
+**
+** I noticed using this code in several places, so here it is once.
+** This reduces the code size of MoreFiles.
+*/
+pascal OSErr GetVolumeInfoNoName(ConstStr255Param pathname,
+ short vRefNum,
+ HParmBlkPtr pb)
+{
+ Str255 tempPathname;
+ OSErr error;
+
+ /* Make sure pb parameter is not NULL */
+ if ( pb != NULL )
+ {
+ pb->volumeParam.ioVRefNum = vRefNum;
+ if ( pathname == NULL )
+ {
+ pb->volumeParam.ioNamePtr = NULL;
+ pb->volumeParam.ioVolIndex = 0; /* use ioVRefNum only */
+ }
+ else
+ { /* make a copy of the string and */
+ BlockMoveData(pathname, tempPathname, pathname[0] + 1);
+ /* use the copy so original isn't trashed */
+ pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;
+ /* use ioNamePtr/ioVRefNum combination */
+ pb->volumeParam.ioVolIndex = -1;
+ }
+ error = PBHGetVInfoSync(pb);
+ pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local
+ tempPathname, so don't return it */
+ }
+ else
+ {
+ error = paramErr;
+ }
+ return ( error );
+}
+
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetFullPath(const FSSpec *spec,
+ short *fullPathLength,
+ Handle *fullPath)
+{
+ OSErr result;
+ OSErr realResult;
+ FSSpec tempSpec;
+ CInfoPBRec pb;
+
+ *fullPathLength = 0;
+ *fullPath = NULL;
+
+ /* Default to noErr */
+ realResult = noErr;
+
+ /* Make a copy of the input FSSpec that can be modified */
+ BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+
+ if ( tempSpec.parID == fsRtParID )
+ {
+ /* The object is a volume */
+
+ /* Add a colon to make it a full pathname */
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+
+ /* We're done */
+ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ }
+ else
+ {
+ /* The object isn't a volume */
+
+ /* Is the object a file or a directory? */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrDirID = tempSpec.parID;
+ pb.dirInfo.ioFDirIndex = 0;
+ result = PBGetCatInfoSync(&pb);
+ /* Allow file/directory name at end of path to not exist. */
+ realResult = result;
+ if ( (result == noErr) || (result == fnfErr) )
+ {
+ /* if the object is a directory, append a colon so full pathname
+ ends with colon */
+ if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+ {
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+ }
+
+ /* Put the object name in first */
+ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ if ( result == noErr )
+ {
+ /* Get the ancestor directory names */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrParID = tempSpec.parID;
+ do /* loop until we have an error or find the root directory */
+ {
+ pb.dirInfo.ioFDirIndex = -1;
+ pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+ result = PBGetCatInfoSync(&pb);
+ if ( result == noErr )
+ {
+ /* Append colon to directory name */
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+
+ /* Add directory name to beginning of fullPath */
+ (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
+ tempSpec.name[0]);
+ result = MemError();
+ }
+ } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
+ }
+ }
+ }
+ if ( result == noErr )
+ {
+ /* Return the length */
+ *fullPathLength = InlineGetHandleSize(*fullPath);
+ result = realResult; /* return realResult in case it was fnfErr */
+ }
+ else
+ {
+ /* Dispose of the handle and return NULL and zero length */
+ if ( *fullPath != NULL )
+ {
+ DisposeHandle(*fullPath);
+ }
+ *fullPath = NULL;
+ *fullPathLength = 0;
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpLocationFromFullPath(short fullPathLength,
+ const void *fullPath,
+ FSSpec *spec)
+{
+ AliasHandle alias;
+ OSErr result;
+ Boolean wasChanged;
+ Str32 nullString;
+
+ /* Create a minimal alias from the full pathname */
+ nullString[0] = 0; /* null string to indicate no zone or server name */
+ result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString,
+ nullString, &alias);
+
+ if ( result == noErr )
+ {
+ /* Let the Alias Manager resolve the alias. */
+ result = ResolveAlias(NULL, alias, spec, &wasChanged);
+
+ DisposeHandle((Handle)alias); /* Free up memory used */
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr GetFullPath(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ short *fullPathLength,
+ Handle *fullPath)
+{
+ OSErr result;
+ FSSpec spec;
+
+ *fullPathLength = 0;
+ *fullPath = NULL;
+
+ result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
+ if ( (result == noErr) || (result == fnfErr) )
+ {
+ result = FSpGetFullPath(&spec, fullPathLength, fullPath);
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr ChangeCreatorType(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ OSType creator,
+ OSType fileType)
+{
+ CInfoPBRec pb;
+ OSErr error;
+ short realVRefNum;
+ long parID;
+
+ pb.hFileInfo.ioNamePtr = (StringPtr)name;
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ error = PBGetCatInfoSync(&pb);
+ if ( error == noErr )
+ {
+ if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) /* if file */
+ { /* save parent dirID for BumpDate call */
+ parID = pb.hFileInfo.ioFlParID;
+
+ /* If creator not 0x00000000, change creator */
+ if ( creator != (OSType)0x00000000 )
+ {
+ pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
+ }
+
+ /* If fileType not 0x00000000, change fileType */
+ if ( fileType != (OSType)0x00000000 )
+ {
+ pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
+ }
+
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBSetCatInfoSync(&pb); /* now, save the new information
+ back to disk */
+
+ if ( (error == noErr) && (parID != fsRtParID) ) /* can't
+ bump fsRtParID */
+ {
+ /* get the real vRefNum in case a full pathname was passed */
+ error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+ if ( error == noErr )
+ {
+ error = BumpDate(realVRefNum, parID, NULL);
+ /* and bump the parent directory's mod date to wake
+ up the Finder */
+ /* to the change we just made */
+ }
+ }
+ }
+ else
+ {
+ /* it was a directory, not a file */
+ error = notAFileErr;
+ }
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpChangeCreatorType(const FSSpec *spec,
+ OSType creator,
+ OSType fileType)
+{
+ return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name,
+ creator, fileType) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr BumpDate(short vRefNum,
+ long dirID,
+ ConstStr255Param name)
+/* Given a file or directory, change its modification date to the
+ current date/time. */
+{
+ CInfoPBRec pb;
+ Str31 tempName;
+ OSErr error;
+ unsigned long secs;
+
+ /* Protection against File Sharing problem */
+ if ( (name == NULL) || (name[0] == 0) )
+ {
+ tempName[0] = 0;
+ pb.hFileInfo.ioNamePtr = tempName;
+ pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ else
+ {
+ pb.hFileInfo.ioNamePtr = (StringPtr)name;
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBGetCatInfoSync(&pb);
+ if ( error == noErr )
+ {
+ GetDateTime(&secs);
+ /* set mod date to current date, or one second into the future
+ if mod date = current date */
+ pb.hFileInfo.ioFlMdDat =
+ (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
+ if ( pb.dirInfo.ioNamePtr == tempName )
+ {
+ pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
+ }
+ else
+ {
+ pb.hFileInfo.ioDirID = dirID;
+ }
+ error = PBSetCatInfoSync(&pb);
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpBumpDate(const FSSpec *spec)
+{
+ return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr OnLine(FSSpecPtr volumes,
+ short reqVolCount,
+ short *actVolCount,
+ short *volIndex)
+{
+ HParamBlockRec pb;
+ OSErr error = noErr;
+ FSSpec *endVolArray;
+
+ if ( *volIndex > 0 )
+ {
+ *actVolCount = 0;
+ for ( endVolArray = volumes + reqVolCount;
+ (volumes < endVolArray) && (error == noErr); ++volumes )
+ {
+ pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
+ pb.volumeParam.ioVolIndex = *volIndex;
+ error = PBHGetVInfoSync(&pb);
+ if ( error == noErr )
+ {
+ volumes->parID = fsRtParID; /* the root directory's
+ parent is 1 */
+ volumes->vRefNum = pb.volumeParam.ioVRefNum;
+ ++*volIndex;
+ ++*actVolCount;
+ }
+ }
+ }
+ else
+ {
+ error = paramErr;
+ }
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr DTGetComment(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ Str255 comment)
+{
+ DTPBRec pb;
+ OSErr error;
+ short dtRefNum;
+ Boolean newDTDatabase;
+
+ if (comment != NULL)
+ {
+ comment[0] = 0; /* return nothing by default */
+
+ /* attempt to open the desktop database */
+ error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+ if ( error == noErr )
+ {
+ /* There was a desktop database and it's now open */
+
+ if ( !newDTDatabase )
+ {
+ pb.ioDTRefNum = dtRefNum;
+ pb.ioNamePtr = (StringPtr)name;
+ pb.ioDirID = dirID;
+ pb.ioDTBuffer = (Ptr)&comment[1];
+ /*
+ ** IMPORTANT NOTE #1: Inside Macintosh says that comments
+ ** are up to 200 characters. While that may be correct for
+ ** the HFS file system's Desktop Manager, other file
+ ** systems (such as Apple Photo Access) return up to
+ ** 255 characters. Make sure the comment buffer is a Str255
+ ** or you'll regret it.
+ **
+ ** IMPORTANT NOTE #2: Although Inside Macintosh doesn't
+ ** mention it, ioDTReqCount is a input field to
+ ** PBDTGetCommentSync. Some file systems (like HFS) ignore
+ ** ioDTReqCount and always return the full comment --
+ ** others (like AppleShare) respect ioDTReqCount and only
+ ** return up to ioDTReqCount characters of the comment.
+ */
+ pb.ioDTReqCount = sizeof(Str255) - 1;
+ error = PBDTGetCommentSync(&pb);
+ if (error == noErr)
+ {
+ comment[0] = (unsigned char)pb.ioDTActCount;
+ }
+ }
+ }
+ else
+ {
+ /* There is no desktop database - try the Desktop file */
+ error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
+ if ( error != noErr )
+ {
+ error = afpItemNotFound; /* return an expected error */
+ }
+ }
+ }
+ else
+ {
+ error = paramErr;
+ }
+
+ return (error);
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpDTGetComment(const FSSpec *spec,
+ Str255 comment)
+{
+ return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr DTSetComment(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ ConstStr255Param comment)
+{
+ DTPBRec pb;
+ OSErr error;
+ short dtRefNum;
+ Boolean newDTDatabase;
+
+ error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+ if ( error == noErr )
+ {
+ pb.ioDTRefNum = dtRefNum;
+ pb.ioNamePtr = (StringPtr)name;
+ pb.ioDirID = dirID;
+ pb.ioDTBuffer = (Ptr)&comment[1];
+ /* Truncate the comment to 200 characters just in case */
+ /* some file system doesn't range check */
+ if ( comment[0] <= 200 )
+ {
+ pb.ioDTReqCount = comment[0];
+ }
+ else
+ {
+ pb.ioDTReqCount = 200;
+ }
+ error = PBDTSetCommentSync(&pb);
+ }
+ return (error);
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpDTSetComment(const FSSpec *spec,
+ ConstStr255Param comment)
+{
+ return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr DTOpen(ConstStr255Param volName,
+ short vRefNum,
+ short *dtRefNum,
+ Boolean *newDTDatabase)
+{
+ OSErr error;
+ GetVolParmsInfoBuffer volParmsInfo;
+ long infoSize;
+ DTPBRec pb;
+
+ /* Check for volume Desktop Manager support before calling */
+ infoSize = sizeof(GetVolParmsInfoBuffer);
+ error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
+ if ( error == noErr )
+ {
+ if ( hasDesktopMgr(volParmsInfo) )
+ {
+ pb.ioNamePtr = (StringPtr)volName;
+ pb.ioVRefNum = vRefNum;
+ error = PBDTOpenInform(&pb);
+ /* PBDTOpenInform informs us if the desktop was just created */
+ /* by leaving the low bit of ioTagInfo clear (0) */
+ *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
+ if ( error == paramErr )
+ {
+ error = PBDTGetPath(&pb);
+ /* PBDTGetPath doesn't tell us if the database is new */
+ /* so assume it is not new */
+ *newDTDatabase = false;
+ }
+ *dtRefNum = pb.ioDTRefNum;
+ }
+ else
+ {
+ error = paramErr;
+ }
+ }
+ return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+** GetCommentFromDesktopFile
+**
+** Get a file or directory's Finder comment field (if any) from the
+** Desktop file's 'FCMT' resources.
+*/
+static OSErr GetCommentFromDesktopFile(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ Str255 comment)
+{
+ OSErr error;
+ short commentID;
+ short realVRefNum;
+ Str255 desktopName;
+ short savedResFile;
+ short dfRefNum;
+ StringHandle commentHandle;
+
+ /* Get the comment ID number */
+ error = GetCommentID(vRefNum, dirID, name, &commentID);
+ if ( error == noErr )
+ {
+ if ( commentID != 0 ) /* commentID == 0 means there's no comment */
+ {
+ error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+ if ( error == noErr )
+ {
+ error = GetDesktopFileName(realVRefNum, desktopName);
+ if ( error == noErr )
+ {
+ savedResFile = CurResFile();
+ /*
+ ** Open the 'Desktop' file in the root directory. (because
+ ** opening the resource file could preload unwanted resources,
+ ** bracket the call with SetResLoad(s))
+ */
+ SetResLoad(false);
+ dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName,
+ fsRdPerm);
+ SetResLoad(true);
+
+ if ( dfRefNum != -1)
+ {
+ /* Get the comment resource */
+ commentHandle = (StringHandle)Get1Resource(kFCMTResType,
+ commentID);
+ if ( commentHandle != NULL )
+ {
+ if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
+ {
+ BlockMoveData(*commentHandle, comment,
+ *commentHandle[0] + 1);
+ }
+ else
+ { /* no comment available */
+ error = afpItemNotFound;
+ }
+ }
+ else
+ { /* no comment available */
+ error = afpItemNotFound;
+ }
+
+ /* restore the resource chain and close
+ the Desktop file */
+ UseResFile(savedResFile);
+ CloseResFile(dfRefNum);
+ }
+ else
+ {
+ error = afpItemNotFound;
+ }
+ }
+ else
+ {
+ error = afpItemNotFound;
+ }
+ }
+ }
+ else
+ {
+ error = afpItemNotFound; /* no comment available */
+ }
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr HGetVolParms(ConstStr255Param volName,
+ short vRefNum,
+ GetVolParmsInfoBuffer *volParmsInfo,
+ long *infoSize)
+{
+ HParamBlockRec pb;
+ OSErr error;
+
+ pb.ioParam.ioNamePtr = (StringPtr)volName;
+ pb.ioParam.ioVRefNum = vRefNum;
+ pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+ pb.ioParam.ioReqCount = *infoSize;
+ error = PBHGetVolParmsSync(&pb);
+ if ( error == noErr )
+ {
+ *infoSize = pb.ioParam.ioActCount;
+ }
+ return ( error );
+}
+
+/*****************************************************************************/
+/*
+** GetCommentID
+**
+** Get the comment ID number for the Desktop file's 'FCMT' resource ID from
+** the file or folders fdComment (frComment) field.
+*/
+static OSErr GetCommentID(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ short *commentID)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+ *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
+ return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+** GetDesktopFileName
+**
+** Get the name of the Desktop file.
+*/
+static OSErr GetDesktopFileName(short vRefNum,
+ Str255 desktopName)
+{
+ OSErr error;
+ HParamBlockRec pb;
+ short index;
+ Boolean found;
+
+ pb.fileParam.ioNamePtr = desktopName;
+ pb.fileParam.ioVRefNum = vRefNum;
+ pb.fileParam.ioFVersNum = 0;
+ index = 1;
+ found = false;
+ do
+ {
+ pb.fileParam.ioDirID = fsRtDirID;
+ pb.fileParam.ioFDirIndex = index;
+ error = PBHGetFInfoSync(&pb);
+ if ( error == noErr )
+ {
+ if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
+ (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
+ {
+ found = true;
+ }
+ }
+ ++index;
+ } while ( (error == noErr) && !found );
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr XGetVInfo(short volReference,
+ StringPtr volName,
+ short *vRefNum,
+ UnsignedWide *freeBytes,
+ UnsignedWide *totalBytes)
+{
+ OSErr result;
+ long response;
+ XVolumeParam pb;
+
+ /* See if large volume support is available */
+ if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
+ {
+ /* Large volume support is available */
+ pb.ioVRefNum = volReference;
+ pb.ioNamePtr = volName;
+ pb.ioXVersion = 0; /* this XVolumeParam version (0) */
+ pb.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
+ result = PBXGetVolInfoSync(&pb);
+ if ( result == noErr )
+ {
+ /* The volume name was returned in volName (if not NULL) and */
+ /* we have the volume's vRefNum and allocation block size */
+ *vRefNum = pb.ioVRefNum;
+
+ /* return the freeBytes and totalBytes */
+ *totalBytes = pb.ioVTotalBytes;
+ *freeBytes = pb.ioVFreeBytes;
+ }
+ }
+ else
+ {
+ /* No large volume support */
+
+ /* Use HGetVInfo to get the results */
+ result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
+ if ( result == noErr )
+ {
+ /* zero the high longs of totalBytes and freeBytes */
+ totalBytes->hi = 0;
+ freeBytes->hi = 0;
+ }
+ }
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr HGetVInfo(short volReference,
+ StringPtr volName,
+ short *vRefNum,
+ unsigned long *freeBytes,
+ unsigned long *totalBytes)
+{
+ HParamBlockRec pb;
+ unsigned long allocationBlockSize;
+ unsigned short numAllocationBlocks;
+ unsigned short numFreeBlocks;
+ VCB *theVCB;
+ Boolean vcbFound;
+ OSErr result;
+
+ /* Use the File Manager to get the real vRefNum */
+ pb.volumeParam.ioVRefNum = volReference;
+ pb.volumeParam.ioNamePtr = volName;
+ pb.volumeParam.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
+ result = PBHGetVInfoSync(&pb);
+
+ if ( result == noErr )
+ {
+ /* The volume name was returned in volName (if not NULL) and */
+ /* we have the volume's vRefNum and allocation block size */
+ *vRefNum = pb.volumeParam.ioVRefNum;
+ allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz;
+
+ /* System 7.5 (and beyond) pins the number of allocation blocks and */
+ /* the number of free allocation blocks returned by PBHGetVInfo to */
+ /* a value so that when multiplied by the allocation block size, */
+ /* the volume will look like it has $7fffffff bytes or less. This */
+ /* was done so older applications that use signed math or that use */
+ /* the GetVInfo function (which uses signed math) will continue to work. */
+ /* However, the unpinned numbers (which we want) are always available */
+ /* in the volume's VCB so we'll get those values from the VCB if possible. */
+
+ /* Find the volume's VCB */
+ vcbFound = false;
+ theVCB = (VCB *)(GetVCBQHdr()->qHead);
+ while ( (theVCB != NULL) && !vcbFound )
+ {
+ /* Check VCB signature before using VCB. Don't have to check for */
+ /* MFS (0xd2d7) because they can't get big enough to be pinned */
+ if ( theVCB->vcbSigWord == 0x4244 )
+ {
+ if ( theVCB->vcbVRefNum == *vRefNum )
+ {
+ vcbFound = true;
+ }
+ }
+
+ if ( !vcbFound )
+ {
+ theVCB = (VCB *)(theVCB->qLink);
+ }
+ }
+
+ if ( theVCB != NULL )
+ {
+ /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
+ /* and the number of free blocks from the VCB. */
+ numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks;
+ numFreeBlocks = (unsigned short)theVCB->vcbFreeBks;
+ }
+ else
+ {
+ /* Didn't find a VCB we can use. Return the number of allocation blocks */
+ /* and the number of free blocks returned by PBHGetVInfoSync. */
+ numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks;
+ numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
+ }
+
+ /* Now, calculate freeBytes and totalBytes using unsigned values */
+ *freeBytes = numFreeBlocks * allocationBlockSize;
+ *totalBytes = numAllocationBlocks * allocationBlockSize;
+ }
+
+ return ( result );
+}
+
+
+/*
+** PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
+** File Manager requests from CFM-based programs. At some point, Apple
+** will get around to adding this to the standard libraries you link with
+** and you'll get a duplicate symbol link error. At that time, just delete
+** this code (or comment it out).
+**
+** Non-CFM 68K programs don't needs this glue (and won't get it) because
+** they instead use the inline assembly glue found in the Files.h interface
+** file.
+*/
+
+#if __WANTPASCALELIMINATION
+#undef pascal
+#endif
+
+#if GENERATINGCFM
+pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
+{
+ enum
+ {
+ kXGetVolInfoSelector = 0x0012, /* Selector for XGetVolInfo */
+
+ uppFSDispatchProcInfo = kRegisterBased
+ | REGISTER_RESULT_LOCATION(kRegisterD0)
+ | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
+ | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */
+ | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */
+ | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
+ };
+
+ return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
+ uppFSDispatchProcInfo,
+ _FSDispatch,
+ kXGetVolInfoSelector,
+ paramBlock) );
+}
+#endif
+
+#if __WANTPASCALELIMINATION
+#define pascal
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr GetDirName(short vRefNum,
+ long dirID,
+ Str31 name)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ if ( name != NULL )
+ {
+ pb.dirInfo.ioNamePtr = name;
+ pb.dirInfo.ioVRefNum = vRefNum;
+ pb.dirInfo.ioDrDirID = dirID;
+ pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
+ error = PBGetCatInfoSync(&pb);
+ }
+ else
+ {
+ error = paramErr;
+ }
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetVolFileSystemID(ConstStr255Param pathname,
+ short vRefNum,
+ short *fileSystemID)
+{
+ HParamBlockRec pb;
+ OSErr error;
+
+ error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+ if ( error == noErr )
+ {
+ *fileSystemID = pb.volumeParam.ioVFSID;
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr GetDInfo(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ DInfo *fndrInfo)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+ if ( error == noErr )
+ {
+ if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+ {
+ /* it's a directory, return the DInfo */
+ *fndrInfo = pb.dirInfo.ioDrUsrWds;
+ }
+ else
+ {
+ /* oops, a file was passed */
+ error = dirNFErr;
+ }
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetDInfo(const FSSpec *spec,
+ DInfo *fndrInfo)
+{
+ return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
+}
+
+
diff --git a/macos/source/macstuff.h b/macos/source/macstuff.h
new file mode 100644
index 0000000..9e92dce
--- /dev/null
+++ b/macos/source/macstuff.h
@@ -0,0 +1,18 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _MACSTUFF_H
+#define _MACSTUFF_H 1
+
+#include "MoreFilesExtras.h"
+#include "MoreDesktopMgr.h"
+#include "MoreFiles.h"
+#include "FSpCompat.h"
+#include "FullPath.h"
+
+#endif /* _MACSTUFF_H */
diff --git a/macos/source/mactime.c b/macos/source/mactime.c
new file mode 100644
index 0000000..af9ad5e
--- /dev/null
+++ b/macos/source/mactime.c
@@ -0,0 +1,451 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* -----------------------------------------------------------------------------
+
+The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
+mktime and time do not work correctly. The supplied link library mactime.c
+contains replacement functions for them.
+
+ * Caveat: On a Mac, we only know the GMT and DST offsets for
+ * the current time, not for the time in question.
+ * Mac has no support for DST handling.
+ * DST changeover is all manually set by the user.
+
+
+------------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <OSUtils.h>
+
+#include "mactime.h"
+
+
+/*
+The MacOS function GetDateTime returns the
+number of seconds elapsed since midnight, January 1, 1904.
+*/
+const unsigned long MacOS_2_Unix = 2082844800L;
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+
+#ifndef TEST_TIME_LIB
+#define my_gmtime gmtime
+#define my_localtime localtime
+#define my_mktime mktime
+#define my_time time
+#endif
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+/* internal prototypes */
+static void clear_tm(struct tm * tm);
+static long GMTDelta(void);
+static Boolean DaylightSaving(void);
+static time_t GetTimeMac(void);
+static time_t Mactime(time_t *timer);
+static void normalize(int *i,int *j,int norm);
+static struct tm *time2tm(const time_t *timer);
+static time_t tm2time(struct tm *tp);
+
+/* Because serial port and SLIP conflict with ReadXPram calls,
+ we cache the call here so we don't hang on calling ReadLocation() */
+static void myReadLocation(MachineLocation * loc);
+
+
+/* prototypes for STD lib replacement functions */
+struct tm *my_gmtime(const time_t *t);
+struct tm *my_localtime(const time_t *t);
+time_t my_mktime(struct tm *tp);
+time_t my_time(time_t *t);
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+ /*
+ * Mac file times are based on 1904 Jan 1 00:00 local time,
+ * not 1970 Jan 1 00:00 UTC.
+ * So we have to convert the time stamps into UNIX UTC
+ * compatible values.
+ */
+time_t MacFtime2UnixFtime(unsigned long macftime)
+{
+ long UTCoffset;
+
+ GetGMToffsetMac(macftime, &UTCoffset);
+ MACOS_TO_UNIX(macftime);
+ macftime -= UTCoffset;
+
+ return macftime;
+}
+
+
+ /*
+ * Mac file times are based on 1904 Jan 1 00:00 local time,
+ * not 1970 Jan 1 00:00 UTC.
+ * So we have to convert the time stamps into MacOS local
+ * compatible values.
+ */
+unsigned long UnixFtime2MacFtime(time_t unxftime)
+{
+ long UTCoffset;
+ unsigned long macftime = unxftime;
+
+ UNIX_TO_MACOS(macftime);
+ GetGMToffsetMac(macftime, &UTCoffset);
+ macftime += UTCoffset;
+
+ return macftime;
+}
+
+
+
+
+
+/*
+* This function convert a file-localtime to an another
+* file-localtime.
+*/
+time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs)
+{
+ time_t MacGMTTime;
+ long UTCoffset;
+
+ /* convert macloctim into corresponding UTC value */
+ MacGMTTime = macloctim - s_gmtoffs;
+ GetGMToffsetMac(macloctim, &UTCoffset);
+
+ return (MacGMTTime + UTCoffset);
+} /* AdjustForTZmove() */
+
+
+
+
+/*
+ * This function calculates the difference between the supplied Mac
+ * ftime value (local time) and the corresponding UTC time in seconds.
+ */
+Boolean GetGMToffsetMac(unsigned long mactime, long *UTCoffset)
+{
+
+mactime = mactime;
+/*
+ * Caveat: On a Mac, we only know the GMT and DST offsets for
+ * the current time, not for the time in question.
+ * Mac has no support for DST handling.
+ * DST changeover is all manually set by the user.
+
+ May be later I can include a support of GMT offset calculation for the
+ time in question here.
+*/
+ *UTCoffset = GMTDelta();
+
+ return true;
+}
+
+
+
+
+
+
+
+/*****************************************************************************
+ * Standard Library Replacement Functions
+ * gmtime(), mktime(), localtime(), time()
+ *
+ * The unix epoch is used here.
+ * These functions gmtime(), mktime(), localtime() and time()
+ * expects and returns unix times.
+ *
+ * At midnight Jan. 1, 1970 GMT, the local time was
+ * midnight Jan. 1, 1970 + GMTDelta().
+ *
+ *
+ *****************************************************************************/
+
+
+struct tm *my_gmtime(const time_t *timer)
+{
+ return time2tm(timer);
+}
+
+
+
+
+struct tm *my_localtime(const time_t *timer)
+{
+ time_t maclocal;
+
+ maclocal = *timer;
+ maclocal += GMTDelta();
+
+ return time2tm(&maclocal);
+}
+
+
+
+
+time_t my_mktime(struct tm *tp)
+{
+ time_t maclocal;
+
+ maclocal = tm2time(tp);
+ maclocal -= GMTDelta();
+
+ return maclocal;
+}
+
+
+
+
+
+
+time_t my_time(time_t *time)
+{
+time_t tmp_time;
+
+GetDateTime(&tmp_time);
+
+MACOS_TO_UNIX(tmp_time);
+
+if (time)
+ {
+ *time = tmp_time;
+ }
+
+return tmp_time;
+}
+
+
+
+/*****************************************************************************/
+/* static module level functions
+/*****************************************************************************/
+
+
+/*
+ * The geographic location and time zone information of a Mac
+ * are stored in extended parameter RAM. The ReadLocation
+ * produdure uses the geographic location record, MachineLocation,
+ * to read the geographic location and time zone information in
+ * extended parameter RAM.
+ *
+ * Because serial port and SLIP conflict with ReadXPram calls,
+ * we cache the call here.
+ *
+ * Caveat: this caching will give the wrong result if a session
+ * extend across the DST changeover time, but
+ * this function resets itself every 2 hours.
+ */
+static void myReadLocation(MachineLocation * loc)
+{
+ static MachineLocation storedLoc; /* InsideMac, OSUtilities, page 4-20 */
+ static time_t first_call = 0, last_call = 86400;
+
+ if ((last_call - first_call) > 7200)
+ {
+ GetDateTime(&first_call);
+ ReadLocation(&storedLoc);
+ }
+
+ GetDateTime(&last_call);
+ *loc = storedLoc;
+}
+
+
+
+
+static Boolean DaylightSaving(void)
+{
+ MachineLocation loc;
+ unsigned char dlsDelta;
+
+ myReadLocation(&loc);
+ dlsDelta = loc.u.dlsDelta;
+
+ return (dlsDelta != 0);
+}
+
+
+
+
+/* current local time = GMTDelta() + GMT
+ GMT = local time - GMTDelta() */
+static long GMTDelta(void)
+{
+ MachineLocation loc;
+ long gmtDelta;
+
+ myReadLocation(&loc);
+
+ /*
+ * On a Mac, the GMT value is in seconds east of GMT. For example,
+ * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour)
+ * east of GMT. The gmtDelta field is a 3-byte value contained in a
+ * long word, so you must take care to get it properly.
+ */
+ gmtDelta = loc.u.gmtDelta & 0x00FFFFFF;
+ if ((gmtDelta & 0x00800000) != 0)
+ {
+ gmtDelta |= 0xFF000000;
+ }
+
+ return gmtDelta;
+}
+
+
+
+/* This routine simulates stdclib time(), time in seconds since 1.1.1970
+ The time is in GMT */
+static time_t GetTimeMac(void)
+{
+ unsigned long maclocal;
+
+
+ /*
+ * Get the current time expressed as the number of seconds
+ * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time).
+ * On a Mac, current time accuracy is up to a second.
+ */
+
+ GetDateTime(&maclocal); /* Get Mac local time */
+ maclocal -= GMTDelta(); /* Get Mac GMT */
+ MACOS_TO_UNIX(maclocal);
+
+ return maclocal; /* return unix GMT */
+}
+
+
+
+
+/*
+ * clear_tm - sets a broken-down time to the equivalent of 1970/1/1 00:00:00
+ */
+
+static void clear_tm(struct tm * tm)
+{
+ tm->tm_sec = 0;
+ tm->tm_min = 0;
+ tm->tm_hour = 0;
+ tm->tm_mday = 1;
+ tm->tm_mon = 0;
+ tm->tm_year = 0;
+ tm->tm_wday = 1;
+ tm->tm_yday = 0;
+ tm->tm_isdst = -1;
+}
+
+
+static void normalize(int *i,int *j,int norm)
+{
+ while(*i < 0)
+ {
+ *i += norm;
+ (*j)--;
+ }
+
+ while(*i >= norm)
+ {
+ *i -= norm;
+ (*j)++;
+ }
+}
+
+
+
+/* Returns the GMT times */
+static time_t Mactime(time_t *timer)
+{
+ time_t t = GetTimeMac();
+
+ if (timer != NULL)
+ *timer = t;
+
+ return t;
+}
+
+
+
+
+static struct tm *time2tm(const time_t *timer)
+{
+ DateTimeRec dtr;
+ MachineLocation loc;
+ time_t macLocal = *timer;
+
+ static struct tm statictime;
+ static const short monthday[12] =
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+ UNIX_TO_MACOS(macLocal);
+ SecondsToDate(macLocal, &dtr);
+
+ statictime.tm_sec = dtr.second; /* second, from 0 to 59 */
+ statictime.tm_min = dtr.minute; /* minute, from 0 to 59 */
+ statictime.tm_hour = dtr.hour; /* hour, from 0 to 23 */
+ statictime.tm_mday = dtr.day; /* day of the month, from 1 to 31 */
+ statictime.tm_mon = dtr.month - 1; /* month, 1= January and 12 = December */
+ statictime.tm_year = dtr.year - 1900; /* year, ranging from 1904 to 2040 */
+ statictime.tm_wday = dtr.dayOfWeek - 1; /* day of the week, 1 = Sun, 7 = Sat */
+
+ statictime.tm_yday = monthday[statictime.tm_mon]
+ + statictime.tm_mday - 1;
+
+ if (2 < statictime.tm_mon && !(statictime.tm_year & 3))
+ {
+ ++statictime.tm_yday;
+ }
+
+ myReadLocation(&loc);
+ statictime.tm_isdst = DaylightSaving();
+
+ return(&statictime);
+}
+
+
+
+
+
+static time_t tm2time(struct tm *tp)
+{
+time_t intMacTime;
+DateTimeRec dtr;
+
+ normalize(&tp->tm_sec, &tp->tm_min, 60);
+ normalize(&tp->tm_min, &tp->tm_hour,60);
+ normalize(&tp->tm_hour,&tp->tm_mday,24);
+ normalize(&tp->tm_mon, &tp->tm_year,12);
+
+ dtr.year = tp->tm_year + 1900; /* years since 1900 */
+ dtr.month = tp->tm_mon + 1; /* month, 0 = January and 11 = December */
+ dtr.day = tp->tm_mday; /* day of the month, from 1 to 31 */
+ dtr.hour = tp->tm_hour; /* hour, from 0 to 23 */
+ dtr.minute = tp->tm_min; /* minute, from 0 to 59 */
+ dtr.second = tp->tm_sec; /* second, from 0 to 59 */
+
+ DateToSeconds(&dtr, &intMacTime);
+
+ MACOS_TO_UNIX(intMacTime);
+
+ return intMacTime;
+}
diff --git a/macos/source/mactime.h b/macos/source/mactime.h
new file mode 100644
index 0000000..cb76aa4
--- /dev/null
+++ b/macos/source/mactime.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _MACTIME_H_
+#define _MACTIME_H_
+/* -----------------------------------------------------------------------------
+
+The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
+mktime and time do not work correctly. The supplied link library mactime.c
+contains replacement functions for them.
+
+ * Caveat: On a Mac, we only know the GMT and DST offsets for
+ * the current time, not for the time in question.
+ * Mac has no support for DST handling.
+ * DST changeover is all manually set by the user.
+
+
+------------------------------------------------------------------------------*/
+
+#include <time.h>
+#include <mactypes.h>
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+
+ /*
+ * ARGH. Mac times are based on 1904 Jan 1 00:00, not 1970 Jan 1 00:00.
+ * So we have to diddle time_t's appropriately: add or subtract 66 years'
+ * worth of seconds == number of days times 86400 == (66*365 regular days +
+ * 17 leap days ) * 86400 == (24090 + 17) * 86400 == 2082844800L seconds.
+ * We hope time_t is an unsigned long (ulg) on the Macintosh...
+ */
+/*
+This Offset is only used by MacFileDate_to_UTime()
+*/
+
+#define MACOS_TO_UNIX(x) (x) -= (unsigned long)MacOS_2_Unix
+#define UNIX_TO_MACOS(x) (x) += (unsigned long)MacOS_2_Unix
+
+/*
+The MacOS function GetDateTime returns the
+number of seconds elapsed since midnight, January 1, 1904.
+*/
+extern const unsigned long MacOS_2_Unix;
+
+
+/* prototypes for public utility functions */
+time_t MacFtime2UnixFtime(unsigned long macftime);
+unsigned long UnixFtime2MacFtime(time_t unxftime);
+time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs);
+Boolean GetGMToffsetMac(unsigned long macftime, long *UTCoffset);
+
+
+#endif
diff --git a/macos/source/pathname.c b/macos/source/pathname.c
new file mode 100644
index 0000000..6bf1003
--- /dev/null
+++ b/macos/source/pathname.c
@@ -0,0 +1,726 @@
+/*
+ Copyright (c) 1990-2003 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ pathname.c
+
+ Function dealing with the pathname. Mostly C-string work.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sound.h>
+
+#include "pathname.h"
+#include "helpers.h"
+#include "macstuff.h"
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+const char ResourceMark[] = "XtraStuf.mac:"; /* see also macos.c */
+
+
+#include "zip.h"
+
+
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpFindFolder --
+ *
+ * This function is a version of the FindFolder function that
+ * returns the result as a FSSpec rather than a vRefNum and dirID.
+ *
+ * Results:
+ * Results will be simaler to that of the FindFolder function.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpFindFolder(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec) /* Pointer to resulting directory. */
+{
+ short foundVRefNum;
+ long foundDirID;
+ OSErr err;
+
+ err = FindFolder(vRefNum, folderType, createFolder,
+ &foundVRefNum, &foundDirID);
+ if (err != noErr) {
+ return err;
+ }
+
+ err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
+ return err;
+}
+
+
+/*
+** return volumename from pathname
+**
+*/
+
+unsigned short GetVolumeFromPath(const char *FullPath, char *VolumeName)
+{
+const char *VolEnd, *tmpPtr1;
+char *tmpPtr2 = VolumeName;
+
+AssertStr(FullPath,"GetVolumeFromPath")
+
+for (VolEnd = FullPath; *VolEnd != '\0' && *VolEnd != ':'; VolEnd++)
+ ;
+if (*VolEnd == '\0') return 0;
+
+for (tmpPtr1 = FullPath; tmpPtr1 != VolEnd;)
+ {
+ *tmpPtr2++ = *tmpPtr1++;
+ }
+
+*tmpPtr2 = '\0';
+
+return (unsigned short) strlen(VolumeName);
+}
+
+
+
+/***********************************/
+/* Function FindNewExtractFolder() */
+/***********************************/
+
+char *FindNewExtractFolder(char *ExtractPath, Boolean uniqueFolder)
+{
+char buffer[NAME_MAX], *tmpPtr, *namePtr;
+char *last_dotpos = ExtractPath;
+short count = 0, folderCount = 0;
+OSErr err;
+FSSpec Spec;
+long theDirID;
+Boolean isDirectory;
+unsigned short namelen, pathlen = strlen(ExtractPath);
+unsigned long ext_length = 0;
+unsigned long num_to_cut = 0;
+long firstpart_length = pathlen;
+
+AssertStr(ExtractPath,"FindNewExtractFolder ExtractPath == NULL")
+
+for (tmpPtr = ExtractPath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':')
+ {
+ folderCount++;
+ namePtr = tmpPtr;
+ }
+
+if (folderCount > 1) {
+ namelen = strlen(namePtr);
+} else {
+ namelen = strlen(ExtractPath);
+}
+
+if (uniqueFolder) {
+ for (count = 0; count < 99; count++)
+ {
+ memset(buffer,0,sizeof(buffer));
+
+ if (namelen >= 28)
+ ExtractPath[pathlen-2] = 0x0;
+ else
+ ExtractPath[pathlen-1] = 0x0;
+
+ sprintf(buffer,"%s%d",ExtractPath,count);
+ GetCompletePath(ExtractPath, buffer, &Spec,&err);
+ err = FSpGetDirectoryID(&Spec, &theDirID, &isDirectory);
+ if (err == -43) break;
+ }
+} else {
+ /* Look for the last extension pos */
+ for (tmpPtr = ExtractPath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == '.') last_dotpos = tmpPtr;
+
+ ext_length = strlen(last_dotpos);
+
+ if (ext_length < 6) { /* up to 5 chars are treated as a */
+ /* normal extension like ".html" or ".class" */
+ int nameLength = last_dotpos - ExtractPath;
+ if (nameLength > 1) {
+ ExtractPath[nameLength] = 0x0;
+ } else {
+ ExtractPath[pathlen-1] = 0x0;
+ }
+ } else {
+ ExtractPath[pathlen-1] = 0x0;
+ }
+
+ GetCompletePath(ExtractPath, ExtractPath, &Spec,&err);
+}
+
+/* Foldernames must always end with a colon */
+sstrcat(ExtractPath,":");
+return ExtractPath;
+}
+
+
+
+/*
+** creates an archive file name
+**
+*/
+
+void createArchiveName(char *thePath)
+{
+char *tmpPtr, *namePtr;
+short folderCount = 0;
+unsigned short namelen, pathlen = strlen(thePath);
+
+if (thePath[pathlen-1] == ':') thePath[pathlen-1] = 0x0;
+
+for (tmpPtr = thePath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':')
+ {
+ folderCount++;
+ namePtr = tmpPtr;
+ }
+
+namelen = strlen(namePtr);
+
+ /* we have to eliminate illegal chars:
+ * The name space for Mac filenames and Zip filenames (unix style names)
+ * do both include all printable extended-ASCII characters. The only
+ * difference we have to take care of is the single special character
+ * used as path delimiter:
+ * ':' on MacOS and '/' on Unix and '\\' on Dos.
+ * So, to convert between Mac filenames and Unix filenames without any
+ * loss of information, we simply interchange ':' and '/'. Additionally,
+ * we try to convert the coding of the extended-ASCII characters into
+ * InfoZip's standard ISO 8859-1 codepage table.
+ */
+ MakeCompatibleString(namePtr, '/', '_', '.', '-', -1);
+
+ /* Avoid filenames like: "Archive..zip" */
+if (thePath[pathlen-1] == '.')
+ {
+ thePath[pathlen-1] = 0;
+ }
+
+if (folderCount >= 1)
+ { /* path contains at least one folder */
+
+ if (namelen >= 28)
+ {
+ pathlen = pathlen-4;
+ }
+
+ thePath[pathlen] = '.';
+ thePath[pathlen+1] = 'z';
+ thePath[pathlen+2] = 'i';
+ thePath[pathlen+3] = 'p';
+ thePath[pathlen+4] = 0x0;
+ return;
+ }
+else
+ { /* path contains no folder */
+ FindDesktopFolder(thePath);
+ createArchiveName(thePath);
+ }
+}
+
+
+
+/*
+** finds the desktop-folder on a volume with
+** largest amount of free-space.
+*/
+
+void FindDesktopFolder(char *Path)
+{
+char buffer[255];
+FSSpec volumes[50]; /* 50 Volumes should be enough */
+short actVolCount, volIndex = 1, VolCount = 0;
+OSErr err;
+short i, foundVRefNum;
+FSSpec spec;
+UInt64 freeBytes;
+UInt64 totalBytes;
+UInt64 MaxFreeBytes;
+
+err = OnLine(volumes, 50, &actVolCount, &volIndex);
+printerr("OnLine:", (err != -35) && (err != 0), err, __LINE__, __FILE__, "");
+
+MaxFreeBytes = 0;
+
+for (i=0; i < actVolCount; i++)
+ {
+ XGetVInfo(volumes[i].vRefNum,
+ volumes[i].name,
+ &volumes[i].vRefNum,
+ &freeBytes,
+ &totalBytes);
+
+ if (MaxFreeBytes < freeBytes) {
+ MaxFreeBytes = freeBytes;
+ foundVRefNum = volumes[i].vRefNum;
+ }
+
+ if ((freeBytes == 0) && (MaxFreeBytes < freeBytes)) {
+ MaxFreeBytes = freeBytes;
+ foundVRefNum = volumes[i].vRefNum;
+ }
+
+}
+
+ FSpFindFolder(foundVRefNum, kDesktopFolderType,
+ kDontCreateFolder,&spec);
+
+ GetFullPathFromSpec(buffer, &spec , &err);
+ sstrcat(buffer,Path);
+ sstrcpy(Path,buffer);
+}
+
+
+/*
+** return the path without the filename
+**
+*/
+
+char *TruncFilename(char *DirPath, const char *FilePath)
+{
+char *tmpPtr;
+char *dirPtr = NULL;
+
+AssertStr(DirPath,"TruncFilename")
+Assert_it(Spec,"TruncFilename","")
+
+sstrcpy(DirPath, FilePath);
+
+for (tmpPtr = DirPath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':')
+ dirPtr = tmpPtr;
+
+if (dirPtr)
+ *++dirPtr = '\0';
+else
+ printerr("TruncFilename: FilePath has no Folders", -1,
+ -1, __LINE__, __FILE__, FilePath);
+
+return DirPath;
+}
+
+
+
+/*
+** return only filename
+**
+*/
+
+char *GetFilename(char *FileName, const char *FilePath)
+{
+const char *tmpPtr;
+const char *dirPtr = NULL;
+
+Assert_it(FileName,"GetFilename","")
+Assert_it(FilePath,"GetFilename","")
+
+for (tmpPtr = FilePath; *tmpPtr; tmpPtr++)
+ {
+ if (*tmpPtr == ':')
+ {
+ dirPtr = tmpPtr;
+ }
+ }
+
+if (dirPtr)
+ {
+ ++dirPtr; /* jump over the ':' */
+ }
+else
+ {
+ return strcpy(FileName, FilePath); /* FilePath has no Folders */
+ }
+
+return strcpy(FileName, dirPtr);
+}
+
+
+
+/*
+** return fullpathname from folder/dir-id
+**
+*/
+
+char *GetFullPathFromID(char *CompletePath, short vRefNum, long dirID,
+ ConstStr255Param name, OSErr *err)
+{
+FSSpec spec;
+
+ *err = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
+ printerr("FSMakeFSSpecCompat:", (*err != -43) && (*err != 0), *err,
+ __LINE__, __FILE__, "");
+ if ( (*err == noErr) || (*err == fnfErr) )
+ {
+ return GetFullPathFromSpec(CompletePath, &spec, err);
+ }
+
+return NULL;
+}
+
+
+
+/*
+** convert real-filename to archive-filename
+**
+*/
+
+char *Real2RfDfFilen(char *RfDfFilen, const char *RealPath,
+ short CurrentFork, short MacZipMode, Boolean DataForkOnly)
+{
+
+AssertStr(RealPath,"Real2RfDfFilen")
+AssertStr(RfDfFilen,"Real2RfDfFilen")
+
+if (DataForkOnly) /* make no changes */
+ {
+ return sstrcpy(RfDfFilen, RealPath);
+ }
+
+switch (MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ sstrcpy(RfDfFilen, RealPath);
+ if (CurrentFork == DataFork) /* data-fork */
+ return sstrcat(RfDfFilen, "d");
+ if (CurrentFork == ResourceFork) /* resource-fork */
+ return sstrcat(RfDfFilen, "r");
+ break;
+ }
+
+ case NewZipMode_EF:
+ {
+ switch (CurrentFork)
+ {
+ case DataFork:
+ {
+ sstrcpy(RfDfFilen, RealPath);
+ return RfDfFilen; /* data-fork */
+ break;
+ }
+ case ResourceFork:
+ {
+ sstrcpy(RfDfFilen, ResourceMark);
+ sstrcat(RfDfFilen, RealPath); /* resource-fork */
+ return RfDfFilen;
+ break;
+ }
+ default:
+ {
+ printerr("Real2RfDfFilen:", -1, -1,
+ __LINE__, __FILE__, RealPath);
+ return NULL; /* function should never reach this point */
+ }
+ }
+ break;
+ }
+ default:
+ {
+ printerr("Real2RfDfFilen:", -1, -1, __LINE__, __FILE__, RealPath);
+ return NULL; /* function should never reach this point */
+ }
+ }
+
+printerr("Real2RfDfFilen:", -1, -1, __LINE__, __FILE__, RealPath);
+return NULL; /* function should never come reach this point */
+}
+
+
+
+/*
+** convert archive-filename into a real filename
+**
+*/
+
+char *RfDfFilen2Real(char *RealFn, const char *RfDfFilen, short MacZipMode,
+ Boolean DataForkOnly, short *CurrentFork)
+{
+short length;
+int result;
+
+AssertStr(RfDfFilen,"RfDfFilen2Real")
+
+if (DataForkOnly ||
+ (MacZipMode == UnKnown_EF) ||
+ (MacZipMode < JohnnyLee_EF))
+ {
+ *CurrentFork = DataFork;
+ return sstrcpy(RealFn,RfDfFilen);
+ }
+
+result = strncmp(RfDfFilen, ResourceMark, sizeof(ResourceMark)-2);
+if (result == 0)
+ {
+ MacZipMode = NewZipMode_EF;
+ }
+
+switch (MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ sstrcpy(RealFn, RfDfFilen);
+ length = strlen(RealFn); /* determine Fork type */
+ if (RealFn[length-1] == 'd') *CurrentFork = DataFork;
+ else *CurrentFork = ResourceFork;
+ RealFn[length-1] = '\0'; /* simply cut one char */
+ return RealFn;
+ break;
+ }
+
+ case NewZipMode_EF:
+ { /* determine Fork type */
+ result = strncmp(RfDfFilen, ResourceMark, sizeof(ResourceMark)-2);
+ if (result != 0)
+ {
+ *CurrentFork = DataFork;
+ sstrcpy(RealFn, RfDfFilen);
+ return RealFn; /* data-fork */
+ }
+ else
+ {
+ *CurrentFork = ResourceFork;
+ if (strlen(RfDfFilen) > (sizeof(ResourceMark) - 1))
+ {
+ sstrcpy(RealFn, &RfDfFilen[sizeof(ResourceMark)-1]);
+ }
+ else RealFn[0] = '\0';
+ return RealFn; /* resource-fork */
+ }
+ break;
+ }
+ default:
+ {
+ *CurrentFork = NoFork;
+ printerr("RfDfFilen2Real():", -1, MacZipMode,
+ __LINE__, __FILE__, RfDfFilen);
+ return NULL; /* function should never reach this point */
+ }
+ }
+
+printerr("RfDfFilen2Real():", -1, MacZipMode, __LINE__, __FILE__, RfDfFilen);
+return NULL; /* function should never reach this point */
+}
+
+
+
+/*
+** return the applications name (argv[0])
+**
+*/
+
+char *GetAppName(void)
+{
+ProcessSerialNumber psn;
+static Str255 AppName;
+ProcessInfoRec pinfo;
+OSErr err;
+
+GetCurrentProcess(&psn);
+pinfo.processName = AppName;
+pinfo.processInfoLength = sizeof(pinfo);
+pinfo.processAppSpec = NULL;
+
+err = GetProcessInformation(&psn,&pinfo);
+AppName[AppName[0]+1] = 0x00;
+
+return (char *)&AppName[1];
+}
+
+
+
+/*
+** return fullpathname from FSSpec
+**
+*/
+
+char *GetFullPathFromSpec(char *FullPath, FSSpec *Spec, OSErr *err)
+{
+Handle hFullPath;
+short len;
+
+Assert_it(Spec,"GetFullPathFromSpec","")
+
+*err = FSpGetFullPath(Spec, &len, &hFullPath);
+printerr("FSpGetFullPath:", (*err != -43) && (*err != 0), *err,
+ __LINE__, __FILE__, "");
+
+memmove(FullPath, (Handle) *hFullPath, len);
+FullPath[len] = '\0'; /* make c-string */
+
+DisposeHandle((Handle)hFullPath); /* we don't need it any more */
+
+printerr("Warning path length exceeds limit: ", len >= NAME_MAX, len,
+ __LINE__, __FILE__, " chars ");
+
+return FullPath;
+}
+
+
+
+
+/*
+* This function expands a given partial path to a complete path.
+* Path expansions are relative to the running app.
+* This function follows the notation:
+* 1. relative path:
+* a: ":subfolder:filename" -> ":current folder:subfolder:filename"
+* b: "::folder2:filename" -> folder2 is beside the current
+* folder on the same level
+* c: "filename" -> in current folder
+*
+* An absolute path will be returned.
+
+The following characteristics of Macintosh pathnames should be noted:
+
+ A full pathname never begins with a colon, but must contain at
+ least one colon.
+ A partial pathname always begins with a colon separator except in
+ the case where the file partial pathname is a simple file or
+ directory name.
+ Single trailing separator colons in full or partial pathnames are
+ ignored except in the case of full pathnames to volumes.
+ In full pathnames to volumes, the trailing separator colon is required.
+ Consecutive separator colons can be used to ascend a level from a
+ directory to its parent directory. Two consecutive separator colons
+ will ascend one level, three consecutive separator colons will ascend
+ two levels, and so on. Ascending can only occur from a directory;
+ not a file.
+*/
+
+char *GetCompletePath(char *CompletePath, const char *name, FSSpec *Spec,
+ OSErr *err)
+{
+Boolean hasDirName = false;
+char currentdir[NAME_MAX];
+char *tmpPtr;
+unsigned short pathlen;
+
+AssertStr(name,"GetCompletePath")
+Assert_it(Spec,"GetCompletePath","")
+Assert_it((CompletePath != name),"GetCompletePath","")
+
+for (tmpPtr = name; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':') hasDirName = true;
+
+if (name[0] != ':') /* case c: path including volume name or only filename */
+ {
+ if (hasDirName)
+ { /* okey, starts with volume name, so it must be a complete path */
+ sstrcpy(CompletePath, name);
+ }
+ else
+ { /* only filename: add cwd and return */
+ getcwd(currentdir, NAME_MAX);
+ sstrcat(currentdir, name);
+ sstrcpy(CompletePath, currentdir);
+ }
+ }
+else if (name[1] == ':') /* it's case b: "::folder2:filename" */
+ {
+ printerr("GetCompletePath ", -1, *err, __LINE__, __FILE__, "not implemented");
+ /* it's not yet implemented; do we really need this case ?*/
+ return NULL;
+ }
+else /* it's case a: ":subfolder:filename" */
+ {
+ getcwd(CompletePath, NAME_MAX); /* we don't need a second colon */
+ CompletePath[strlen(CompletePath)-1] = '\0';
+ sstrcat(CompletePath, name);
+ }
+
+pathlen = strlen(CompletePath);
+*err = FSpLocationFromFullPath(pathlen, CompletePath, Spec);
+
+return CompletePath;
+}
+
+
+
+char *MakeFilenameShorter(const char *LongFilename)
+{
+static char filename[35]; /* contents should be never longer than 32 chars */
+static unsigned char Num = 0; /* change the number for every call */
+ /* this var will rollover without a problem */
+char tempLongFilename[1024], charnum[5];
+char *last_dotpos = tempLongFilename;
+unsigned long full_length = strlen(LongFilename);
+unsigned long ext_length = 0;
+unsigned long num_to_cut = 0;
+long firstpart_length;
+char *tmpPtr;
+short MaxLength = 31;
+
+if (full_length <= MaxLength) /* filename is not long */
+ {
+ return strcpy(filename,LongFilename);
+ }
+
+Num++;
+strcpy(tempLongFilename,LongFilename);
+
+/* Look for the last extension pos */
+for (tmpPtr = tempLongFilename; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == '.') last_dotpos = tmpPtr;
+
+ext_length = strlen(last_dotpos);
+firstpart_length = last_dotpos - tempLongFilename;
+
+if (ext_length > 6) /* up to 5 chars are treated as a */
+ { /* normal extension like ".html" or ".class" */
+ firstpart_length = 0;
+ }
+
+num_to_cut = full_length - MaxLength;
+
+/* number the files to make the names unique */
+sprintf(charnum,"~%x", Num);
+num_to_cut += strlen(charnum);
+
+if (firstpart_length == 0)
+ {
+ firstpart_length = full_length;
+ tempLongFilename[firstpart_length - num_to_cut] = 0;
+ sprintf(filename,"%s%s", tempLongFilename, charnum);
+ }
+else
+ {
+ tempLongFilename[firstpart_length - num_to_cut] = 0;
+ sprintf(filename,"%s%s%s", tempLongFilename, charnum, last_dotpos);
+ }
+
+return filename;
+}
diff --git a/macos/source/pathname.h b/macos/source/pathname.h
new file mode 100644
index 0000000..1a39ed3
--- /dev/null
+++ b/macos/source/pathname.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef PATHNAME_H
+#define PATHNAME_H 1
+
+
+char *StripPartialDir(char *CompletePath,
+ const char *PartialPath, const char *FullPath);
+
+char *Real2RfDfFilen(char *RfDfFilen, const char *RealPath, short CurrentFork,
+ short MacZipMode, Boolean DataForkOnly);
+char *RfDfFilen2Real(char *RealFn, const char *RfDfFilen, short MacZipMode,
+ Boolean DataForkOnly, short *CurrentFork);
+
+unsigned short GetVolumeFromPath(const char *FullPath, char *VolumeName);
+char *GetCompletePath(char *CompletePath, const char *name, FSSpec *Spec,
+ OSErr *err);
+char *TruncFilename(char *DirPath, const char *FilePath);
+char *GetFilename(char *CompletePath, const char *name);
+char *GetFullPathFromSpec(char *CompletePath, FSSpec *Spec, OSErr *err);
+char *GetFullPathFromID(char *CompletePath, short vRefNum, long dirID,
+ ConstStr255Param name, OSErr *err);
+
+char *GetAppName(void);
+void createArchiveName(char *Path);
+void FindDesktopFolder(char *Path);
+char *FindNewExtractFolder(char *ExtractPath, Boolean uniqueFolder);
+OSErr FSpFindFolder(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec); /* Pointer to resulting directory. */
+
+char *MakeFilenameShorter(const char *LongFilename);
+
+/*
+Rule: UnKnown_EF should always be zero.
+ JohnnyLee_EF, NewZipMode_EF should always greater than all
+ other definitions
+*/
+#define UnKnown_EF 0
+#define TomBrownZipIt1_EF 10
+#define TomBrownZipIt2_EF 20
+#define JohnnyLee_EF 30
+#define NewZipMode_EF 40
+
+
+
+#define ResourceFork -1
+#define DataFork 1
+#define NoFork 0
+
+
+#ifndef NAME_MAX
+#define NAME_MAX 1024
+#endif
+
+#endif /* PATHNAME_H */
diff --git a/macos/source/recurse.c b/macos/source/recurse.c
new file mode 100644
index 0000000..e87db3c
--- /dev/null
+++ b/macos/source/recurse.c
@@ -0,0 +1,442 @@
+/*
+These functions are based on Jim Luther's IterateDirectory() found in MoreFiles
+However, it's heavily modified by Dirk Haase
+*/
+
+/*
+** IterateDirectory: File Manager directory iterator routines.
+**
+** by Jim Luther
+**
+** File: IterateDirectory.c
+**
+** Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc.
+** All rights reserved.
+**
+** You may incorporate this sample code into your applications without
+** restriction, though the sample code has been provided "AS IS" and the
+** responsibility for its operation is 100% yours.
+**
+** IterateDirectory is designed to drop into the MoreFiles sample code
+** library I wrote while in Apple Developer Technical Support
+*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Files.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include "zip.h"
+#include "macstuff.h"
+#include "helpers.h"
+#include "recurse.h"
+#include "macglob.h"
+#include "pathname.h"
+
+
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+/* The RecurseGlobals structure is used to minimize the amount of
+** stack space used when recursively calling RecurseDirectoryLevel
+** and to hold global information that might be needed at any time.
+*/
+struct RecurseGlobals
+{
+ short vRefNum;
+ CInfoPBRec cPB; /* the parameter block used for
+ PBGetCatInfo calls */
+ unsigned char *itemName; /* the name of the current item */
+ char *FullPath;
+ short FullPathLen;
+ OSErr result; /* temporary holder of results -
+ saves 2 bytes of stack each level */
+ Boolean quitFlag; /* set to true if filter wants to
+ kill interation */
+ unsigned short maxLevels; /* Maximum levels to
+ iterate through */
+ unsigned short currentLevel; /* The current level
+ IterateLevel is on */
+};
+
+typedef struct RecurseGlobals RecurseGlobals;
+typedef RecurseGlobals *RecurseGlobalsPtr;
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+extern MacZipGlobals MacZip;
+extern const char ResourceMark[13]; /* "XtraStuf.mac:" var is initialized in file pathname.c */
+extern int extra_fields; /* do not create extra fields if false */
+
+static RecurseGlobals theGlobals;
+
+static unsigned long DirLevels = 0;
+static char *buffer;
+extern int verbose; /* 1=report oddities in zip file structure */
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+int procname(char *filename, int caseflag);
+int MatchWild( char *pPat, char *pStr, int case_sens);
+Boolean IsZipFile(char *name);
+
+static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals);
+static Boolean isRegularItem( RecurseGlobals *Globals);
+static void ProcessFiles(RecurseGlobals *Globals,
+ Boolean hasDataFork, Boolean hasResourceFork);
+static void ProcessDirectory(RecurseGlobals *Globals,
+ Boolean IncludeItem, long DirID);
+static void ProcessItem(RecurseGlobals *Globals, long DirID);
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals)
+{
+char buffer2[23];
+
+ /* if maxLevels is zero, we aren't checking levels */
+ if ( (Globals->maxLevels == 0) ||
+ /* if currentLevel < maxLevels, look at this level */
+ (Globals->currentLevel < Globals->maxLevels) )
+ {
+ short index = 1;
+
+ ++Globals->currentLevel; /* go to next level */
+ if (DirLevels < Globals->currentLevel) DirLevels = Globals->currentLevel;
+ sprintf(buffer2,"Globals->currentLevel: %d",Globals->currentLevel);
+
+ do
+ { /* Isn't C great... What I'd give for a "WITH
+ theGlobals DO" about now... */
+
+ /* Get next source item at the current directory level */
+ Globals->cPB.dirInfo.ioFDirIndex = index;
+ Globals->cPB.dirInfo.ioDrDirID = DirID;
+ Globals->result = PBGetCatInfoSync((CInfoPBPtr)&Globals->cPB);
+
+ ShowCounter(false);
+
+ if ( Globals->result == noErr )
+ {
+ ProcessItem(Globals, DirID);
+ } /* if ( Globals->result == noErr ) */
+
+ ++index; /* prepare to get next item */
+ /* time to fall back a level? */
+ } while ( (Globals->result == noErr) && (!Globals->quitFlag) );
+
+ if ( (Globals->result == fnfErr) || /* fnfErr is OK -
+ it only means we hit
+ the end of this level */
+ (Globals->result == afpAccessDenied) ) /* afpAccessDenied is OK,
+ too - it only means we cannot see inside a directory */
+ {
+ Globals->result = noErr;
+ }
+
+ --Globals->currentLevel; /* return to previous level as we leave */
+ }
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr RecurseDirectory(short vRefNum,
+ long thedirID,
+ ConstStr255Param name,
+ unsigned short maxLevels)
+{
+ OSErr result;
+ short theVRefNum;
+ Boolean isDirectory;
+ long DirID;
+
+ /* Get the real directory ID and make sure it is a directory */
+ result = GetDirectoryID(vRefNum, thedirID, name, &DirID, &isDirectory);
+ if ( result == noErr )
+ {
+ if ( isDirectory == true )
+ {
+ /* Get the real vRefNum */
+ result = DetermineVRefNum(name, vRefNum, &theVRefNum);
+ if ( result == noErr )
+ {
+ /* Set up the globals we need to access from
+ the recursive routine. */
+ theGlobals.cPB.hFileInfo.ioNamePtr = theGlobals.itemName;
+ theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
+ theGlobals.itemName[0] = 0;
+ theGlobals.result = noErr;
+ theGlobals.quitFlag = false;
+ theGlobals.maxLevels = maxLevels;
+ theGlobals.currentLevel = 0; /* start at level 0 */
+
+ /* Here we go into recursion land... */
+ RecurseDirectoryLevel(DirID, &theGlobals);
+
+ result = theGlobals.result; /* set the result */
+ }
+ }
+ else
+ {
+ result = dirNFErr; /* a file was passed instead
+ of a directory */
+ }
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpRecurseDirectory(const FSSpec *spec,
+ unsigned short maxLevels)
+{
+ OSErr rc;
+
+ theGlobals.vRefNum = spec->vRefNum;
+
+ /* make room for pathnames */
+ theGlobals.itemName = (unsigned char *) StrCalloc(NAME_MAX);
+ theGlobals.FullPath = StrCalloc(NAME_MAX);
+ buffer = StrCalloc(NAME_MAX);
+
+
+ if ((noisy) && (MacZip.DataForkOnly))
+ printf("\n Warning: Datafork only \n");
+
+ /* reset the count to zero */
+ ShowCounter(true);
+
+ if (noisy) leftStatusString("Build File List; Items done:");
+ if (noisy) printf("\n Collecting Filenames ...");
+ rc = RecurseDirectory(spec->vRefNum, spec->parID, spec->name,maxLevels);
+ printerr("RecurseDirectory:",rc,rc,__LINE__,__FILE__,"");
+
+ if (noisy) printf("\n... done \n\n %6d matched files found \n",
+ MacZip.FoundFiles);
+ if (noisy) printf(" %6d folders found in %d Levels \n",
+ MacZip.FoundDirectories,DirLevels);
+
+ if (MacZip.BytesOfData > (1024*1024))
+ if (noisy) printf(" %4.3f MBytes unzipped size\n\n",
+ (float) MacZip.BytesOfData/(1024*1024));
+ else
+ if (noisy) printf(" %4.3f KBytes unzipped size\n\n",
+ (float) MacZip.BytesOfData/1024);
+
+ /* free all memory of pathnames */
+ theGlobals.itemName = (unsigned char *) StrFree((char *)theGlobals.itemName);
+ theGlobals.FullPath = StrFree(theGlobals.FullPath);
+ buffer = StrFree(buffer);
+
+ return rc;
+}
+
+
+
+
+/*
+* Return true if filename == zipfile
+* After the first match no further check will be done !
+*
+*/
+Boolean IsZipFile(char *filen)
+{
+static firstMatch = false;
+
+if (filen == NULL)
+ firstMatch = false;
+
+if (!firstMatch)
+ {
+ if (stricmp(filen, MacZip.ZipFullPath) == 0)
+ {
+ firstMatch = true;
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+
+static Boolean isRegularItem( RecurseGlobals *Globals)
+{
+Boolean isInvisible = false,
+ isAlias = false,
+ isSystem = false;
+
+isSystem = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+ (1 << 12)) == 0 );
+isInvisible = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+ (1 << 14)) == 0 );
+isAlias = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+ (1 << 15)) == 0);
+
+if (isAlias == true)
+ {
+ return false;
+ }
+
+if (MacZip.IncludeInvisible == true)
+ {
+ return true;
+ }
+
+if ((isSystem == true) ||
+ (isInvisible == true))
+ {
+ return false;
+ }
+
+return true;
+}
+
+
+
+
+static void ProcessFiles(RecurseGlobals *Globals,
+ Boolean hasDataFork, Boolean hasResourceFork)
+{
+ /* some file statistics */
+MacZip.FoundFiles++;
+
+if (hasDataFork == true)
+ {
+ MacZip.BytesOfData =
+ Globals->cPB.hFileInfo.ioFlLgLen +
+ MacZip.BytesOfData;
+ MacZip.CurrentFork = DataFork;
+ MacZip.RawCountOfItems++;
+
+ if (MacZip.DataForkOnly == true)
+ {
+ procname(Globals->FullPath, false);
+ hasResourceFork = false;
+ }
+ else
+ {
+ procname(Real2RfDfFilen(buffer,Globals->FullPath,
+ DataFork, MacZip.MacZipMode,
+ MacZip.DataForkOnly), false);
+ }
+ }
+
+if (hasResourceFork == true)
+ {
+ MacZip.BytesOfData =
+ Globals->cPB.hFileInfo.ioFlRLgLen +
+ MacZip.BytesOfData;
+ MacZip.CurrentFork = ResourceFork;
+ MacZip.RawCountOfItems++;
+
+ procname(Real2RfDfFilen(buffer, Globals->FullPath,
+ ResourceFork, MacZip.MacZipMode,
+ MacZip.DataForkOnly), false);
+ }
+}
+
+
+
+
+static void ProcessDirectory(RecurseGlobals *Globals,
+ Boolean IncludeItem, long DirID)
+{
+OSErr rc;
+
+MacZip.isDirectory = true;
+
+GetFullPathFromID(Globals->FullPath,Globals->vRefNum, DirID,
+ Globals->itemName, &rc);
+
+MacZip.RawCountOfItems++;
+MacZip.FoundDirectories++;
+
+if (MacZip.StoreFoldersAlso)
+ {
+ procname(Globals->FullPath, false);
+ }
+
+ /* We have a directory */
+ if ( !Globals->quitFlag && IncludeItem)
+ {
+ /* Dive again if the IterateFilterProc didn't say "quit" and dir is
+ not an alias */
+ RecurseDirectoryLevel(Globals->cPB.dirInfo.ioDrDirID,
+ Globals);
+ }
+}
+
+
+
+static void ProcessItem(RecurseGlobals *Globals, long DirID)
+{
+OSErr rc;
+Boolean IncludeItem = false, hasDataFork = false;
+Boolean hasResourceFork = false;
+
+IncludeItem = isRegularItem(Globals);
+
+/* Is it a File? */
+if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) == 0 )
+ {
+ PToCCpy(Globals->itemName,MacZip.FileName);
+ MacZip.isDirectory = false;
+
+ hasDataFork = (Globals->cPB.hFileInfo.ioFlLgLen != 0);
+ hasResourceFork = (Globals->cPB.hFileInfo.ioFlRLgLen != 0);
+
+ /* include also files with zero recource- and data-fork */
+ if ((hasDataFork == 0) && (hasResourceFork == 0))
+ hasDataFork = true;
+
+ if ((hasDataFork == 0) &&
+ (hasResourceFork != 0) &&
+ (extra_fields == false))
+ {
+ IncludeItem = false;
+ }
+
+ GetFullPathFromID(Globals->FullPath,Globals->vRefNum,
+ DirID, Globals->itemName, &rc);
+ printerr("GetFullPathFromID:",rc,rc,__LINE__,
+ __FILE__,MacZip.FileName);
+
+ if (IncludeItem && /* don't include the zipfile itself */
+ (!IsZipFile(Globals->FullPath)) )
+ {
+ if (MATCH(MacZip.Pattern, MacZip.FileName, false) == true)
+ {
+ ProcessFiles(Globals, hasDataFork, hasResourceFork);
+ } /* if (MatchWild( MacZip.FileName,MacZip.Pattern ) ==
+ true) */
+ } /* if (!IsZipFile(Globals->FullPath)) */
+ } /* Is it a File? */
+
+/* Is it a directory? */
+if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+ {
+ ProcessDirectory(Globals,IncludeItem, DirID);
+ } /* Is it a directory? */
+}
diff --git a/macos/source/recurse.h b/macos/source/recurse.h
new file mode 100644
index 0000000..cfbc4b0
--- /dev/null
+++ b/macos/source/recurse.h
@@ -0,0 +1,129 @@
+/*
+** IterateDirectory: File Manager directory iterator routines.
+**
+** by Jim Luther
+**
+** File: IterateDirectory.h
+**
+** Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc.
+** All rights reserved.
+**
+** You may incorporate this sample code into your applications without
+** restriction, though the sample code has been provided "AS IS" and the
+** responsibility for its operation is 100% yours.
+**
+** IterateDirectory is designed to drop into the MoreFiles sample code
+** library I wrote while in Apple Developer Technical Support
+*/
+
+#ifndef __RECURSEDIRECTORY__
+#define __RECURSEDIRECTORY__
+
+#include <Types.h>
+#include <Files.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*****************************************************************************/
+
+pascal OSErr RecurseDirectory(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ unsigned short maxLevels );
+/* Iterate (scan) through a directory's content.
+ The IterateDirectory function performs a recursive iteration (scan) of
+ the specified directory and calls your IterateFilterProc function once
+ for each file and directory found.
+
+ The maxLevels parameter lets you control how deep the recursion goes.
+ If maxLevels is 1, IterateDirectory only scans the specified directory;
+ if maxLevels is 2, IterateDirectory scans the specified directory and
+ one subdirectory below the specified directory; etc. Set maxLevels to
+ zero to scan all levels.
+
+ The yourDataPtr parameter can point to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ vRefNum input: Volume specification.
+ dirID input: Directory ID.
+ name input: Pointer to object name, or nil when dirID
+ specifies a directory that's the object.
+ maxLevels input: Maximum number of directory levels to scan or
+ zero to scan all directory levels.
+ iterateFilter input: A pointer to the routine you want called once
+ for each file and directory found by
+ IterateDirectory.
+ yourDataPtr input: A pointer to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ Result Codes
+ noErr 0 No error
+ nsvErr -35 No such volume
+ ioErr -36 I/O error
+ bdNamErr -37 Bad filename
+ fnfErr -43 File not found
+ paramErr -50 No default volume or iterateFilter was NULL
+ dirNFErr -120 Directory not found or incomplete pathname
+ or a file was passed instead of a directory
+ afpAccessDenied -5000 User does not have the correct access
+ afpObjectTypeErr -5025 Directory not found or incomplete pathname
+
+ __________
+
+ See also: RecurseFilterProcPtr, FSpRecurseDirectory
+*/
+
+/*****************************************************************************/
+
+pascal OSErr FSpRecurseDirectory(const FSSpec *spec,
+ unsigned short maxLevels);
+/* Iterate (scan) through a directory's content.
+ The FSpIterateDirectory function performs a recursive iteration (scan)
+ of the specified directory and calls your IterateFilterProc function once
+ for each file and directory found.
+
+ The maxLevels parameter lets you control how deep the recursion goes.
+ If maxLevels is 1, FSpIterateDirectory only scans the specified directory;
+ if maxLevels is 2, FSpIterateDirectory scans the specified directory and
+ one subdirectory below the specified directory; etc. Set maxLevels to
+ zero to scan all levels.
+
+ The yourDataPtr parameter can point to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ spec input: An FSSpec record specifying the directory to scan.
+ maxLevels input: Maximum number of directory levels to scan or
+ zero to scan all directory levels.
+ iterateFilter input: A pointer to the routine you want called once
+ for each file and directory found by
+ FSpIterateDirectory.
+ yourDataPtr input: A pointer to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ Result Codes
+ noErr 0 No error
+ nsvErr -35 No such volume
+ ioErr -36 I/O error
+ bdNamErr -37 Bad filename
+ fnfErr -43 File not found
+ paramErr -50 No default volume or iterateFilter was NULL
+ dirNFErr -120 Directory not found or incomplete pathname
+ afpAccessDenied -5000 User does not have the correct access
+ afpObjectTypeErr -5025 Directory not found or incomplete pathname
+
+ __________
+
+ See also: RecurseFilterProcPtr, RecurseDirectory
+*/
+
+
+
+/*****************************************************************************/
+
+
+
+#endif /* __RECURSEDIRECTORY__ */
diff --git a/macos/source/unixlike.c b/macos/source/unixlike.c
new file mode 100644
index 0000000..4eb55da
--- /dev/null
+++ b/macos/source/unixlike.c
@@ -0,0 +1,313 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ unixlike.c
+
+ Macintosh-specific routines to emulate unixfunctions.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include "zip.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <sound.h>
+
+#include "unixlike.h"
+#include "helpers.h"
+#include "pathname.h"
+#include "macstuff.h"
+#include "macglob.h"
+#include "mactime.h"
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+extern MacZipGlobals MacZip;
+extern int errno;
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MacStat --
+ *
+ * This function replaces the library version of stat. The stat
+ * function provided by most Mac compiliers is rather broken and
+ * incomplete.
+ *
+ * Results:
+ * See stat documentation.
+ *
+ * Side effects:
+ * See stat documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int Zmacstat(const char *Fname, struct stat *buf)
+{
+ OSErr err, rc;
+ short fullPathLength;
+ Handle hFullPath;
+ char path[NAME_MAX], path2[NAME_MAX];
+ HVolumeParam vpb;
+ static unsigned long count_of_files = 0;
+
+ AssertStr(Fname,Fname)
+ Assert_it(buf,"","")
+
+ UserStop();
+
+ memset(buf, 0, sizeof(buf)); /* zero out all fields */
+
+ RfDfFilen2Real(path2, Fname, MacZip.MacZipMode, MacZip.DataForkOnly,
+ &MacZip.CurrentFork);
+ GetCompletePath(path, path2, &MacZip.fileSpec, &err);
+ err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+ printerr("GetCompletePath:", err, err, __LINE__, __FILE__, path);
+
+ if (err != noErr) {
+ errno = err;
+ return -1;
+ }
+
+ /* Collect here some more information, it's not related to Macstat.
+ (note: filespec gets changed later in this function) */
+ /* clear string-buffer */
+ memset(MacZip.FullPath, 0x00, sizeof(MacZip.FullPath));
+ rc = FSpGetFullPath(&MacZip.fileSpec, &fullPathLength, &hFullPath);
+ strncpy(MacZip.FullPath, *hFullPath, fullPathLength);
+ DisposeHandle(hFullPath); /* we don't need it any more */
+ /* Collect some more information not related to Macstat */
+
+
+ /*
+ * Fill the fpb & vpb struct up with info about file or directory.
+ */
+
+ FSpGetDirectoryID(&MacZip.fileSpec, &MacZip.dirID, &MacZip.isDirectory);
+ vpb.ioVRefNum = MacZip.fpb.hFileInfo.ioVRefNum = MacZip.fileSpec.vRefNum;
+ vpb.ioNamePtr = MacZip.fpb.hFileInfo.ioNamePtr = MacZip.fileSpec.name;
+
+ if (MacZip.isDirectory) {
+ MacZip.fpb.hFileInfo.ioDirID = MacZip.fileSpec.parID;
+ /*
+ * Directories are executable by everyone.
+ */
+ buf->st_mode |= UNX_IXUSR | UNX_IXGRP | UNX_IXOTH | UNX_IFDIR;
+ } else {
+ MacZip.fpb.hFileInfo.ioDirID = MacZip.dirID;
+ }
+
+ MacZip.fpb.hFileInfo.ioFDirIndex = 0;
+ err = PBGetCatInfoSync((CInfoPBPtr)&MacZip.fpb);
+
+ if (err == noErr) {
+ vpb.ioVolIndex = 0;
+ err = PBHGetVInfoSync((HParmBlkPtr)&vpb);
+ if (err == noErr && buf != NULL) {
+ /*
+ * Files are always readable by everyone.
+ */
+ buf->st_mode |= UNX_IRUSR | UNX_IRGRP | UNX_IROTH;
+
+ /*
+ * Use the Volume Info & File Info to fill out stat buf.
+ */
+ if (MacZip.fpb.hFileInfo.ioFlAttrib & 0x10) {
+ buf->st_mode |= UNX_IFDIR;
+ buf->st_nlink = 2;
+ } else {
+ buf->st_nlink = 1;
+ if (MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) {
+ buf->st_mode |= UNX_IFLNK;
+ } else {
+ buf->st_mode |= UNX_IFREG;
+ }
+ }
+
+ if (MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType == 'APPL') {
+ /*
+ * Applications are executable by everyone.
+ */
+ buf->st_mode |= UNX_IXUSR | UNX_IXGRP | UNX_IXOTH;
+ }
+ if ((MacZip.fpb.hFileInfo.ioFlAttrib & 0x01) == 0){
+ /*
+ * If not locked, then everyone has write acces.
+ */
+ buf->st_mode |= UNX_IWUSR | UNX_IWGRP | UNX_IWOTH;
+ }
+
+ buf->st_ino = MacZip.fpb.hFileInfo.ioDirID;
+ buf->st_dev = MacZip.fpb.hFileInfo.ioVRefNum;
+ buf->st_uid = -1;
+ buf->st_gid = -1;
+ buf->st_rdev = 0;
+
+ if (MacZip.CurrentFork == ResourceFork)
+ buf->st_size = MacZip.fpb.hFileInfo.ioFlRLgLen;
+ else
+ buf->st_size = MacZip.fpb.hFileInfo.ioFlLgLen;
+
+ buf->st_blksize = vpb.ioVAlBlkSiz;
+ buf->st_blocks = (buf->st_size + buf->st_blksize - 1)
+ / buf->st_blksize;
+
+ /*
+ * The times returned by the Mac file system are in the
+ * local time zone. We convert them to GMT so that the
+ * epoch starts from GMT. This is also consistent with
+ * what is returned from "clock seconds".
+ */
+ if (!MacZip.isDirectory) {
+ MacZip.CreatDate = MacZip.fpb.hFileInfo.ioFlCrDat;
+ MacZip.ModDate = MacZip.fpb.hFileInfo.ioFlMdDat;
+ MacZip.BackDate = MacZip.fpb.hFileInfo.ioFlBkDat;
+ } else {
+ MacZip.CreatDate = MacZip.fpb.dirInfo.ioDrCrDat;
+ MacZip.ModDate = MacZip.fpb.dirInfo.ioDrMdDat;
+ MacZip.BackDate = MacZip.fpb.dirInfo.ioDrBkDat;
+ }
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ {
+ MacZip.HaveGMToffset = false;
+ MacZip.Md_UTCoffs = 0L;
+ MacZip.Cr_UTCoffs = 0L;
+ MacZip.Bk_UTCoffs = 0L;
+ }
+ else
+#endif
+ {
+ /* Do not use GMT offsets when Md_UTCoffs calculation
+ * fails, since this time stamp is used for time
+ * comparisons in Zip and UnZip operations.
+ * We do not bother when GMT offset calculation fails for
+ * any other time stamp value. Instead we simply assume
+ * a default value of 0.
+ */
+ MacZip.HaveGMToffset =
+ GetGMToffsetMac(MacZip.ModDate, &MacZip.Md_UTCoffs);
+ if (MacZip.HaveGMToffset) {
+ GetGMToffsetMac(MacZip.CreatDate, &MacZip.Cr_UTCoffs);
+ GetGMToffsetMac(MacZip.BackDate, &MacZip.Bk_UTCoffs);
+ } else {
+ MacZip.Cr_UTCoffs = 0L;
+ MacZip.Bk_UTCoffs = 0L;
+ }
+ }
+#ifdef DEBUG_TIME
+ {
+ printf("\nZmacstat: MacZip.HaveGMToffset: %d",
+ MacZip.HaveGMToffset);
+ printf("\nZmacstat: Mac modif: %lu local -> UTOffset: %d",
+ MacZip.ModDate, MacZip.Md_UTCoffs);
+ printf("\nZmacstat: Mac creat: %lu local -> UTOffset: %d",
+ MacZip.CreatDate, MacZip.Cr_UTCoffs);
+ printf("\nZmacstat: Mac back: %lu local -> UTOffset: %d",
+ MacZip.BackDate, MacZip.Bk_UTCoffs);
+ }
+#endif /* DEBUG_TIME */
+
+
+ buf->st_mtime = MacFtime2UnixFtime(MacZip.ModDate);
+ buf->st_ctime = MacFtime2UnixFtime(MacZip.CreatDate);
+ buf->st_atime = buf->st_mtime;
+
+#ifdef DEBUG_TIME
+ {
+ printf("\nZmacstat: Unix modif: %lu UTC; Mac: %lu local",
+ buf->st_mtime, MacZip.ModDate);
+ printf("\nZmacstat: Unix creat: %lu UTC; Mac: %lu local\n",
+ buf->st_ctime, MacZip.CreatDate);
+ }
+#endif /* DEBUG_TIME */
+
+ if (noisy)
+ {
+ if (MacZip.StatingProgress)
+ {
+ count_of_files++;
+ InformProgress(MacZip.RawCountOfItems, count_of_files );
+ }
+ else
+ count_of_files = 0;
+ }
+ }
+ }
+
+ if (err != noErr) {
+ errno = err;
+ }
+
+ MacZip.isMacStatValid = true;
+ return (err == noErr ? 0 : -1);
+}
+
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * chmod --
+ *
+ * Results:
+ * See chmod documentation.
+ *
+ * Side effects:
+ * See chmod documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int chmod(char *path, int mode)
+{
+ HParamBlockRec hpb;
+ OSErr err;
+
+ hpb.fileParam.ioNamePtr = C2PStr(path);
+ hpb.fileParam.ioVRefNum = 0;
+ hpb.fileParam.ioDirID = 0;
+
+ if (mode & 0200) {
+ err = PBHRstFLockSync(&hpb);
+ } else {
+ err = PBHSetFLockSync(&hpb);
+ }
+
+ if (err != noErr) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/macos/source/unixlike.h b/macos/source/unixlike.h
new file mode 100644
index 0000000..e61a354
--- /dev/null
+++ b/macos/source/unixlike.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * Directory Operations for Mac based on BSD 4.3 <macdir.h>
+ * By Jason Linhart, January 1997
+ */
+
+#ifndef _UNIXLIKE_H
+#define _UNIXLIKE_H 1
+
+#include <stat.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX 2048
+#endif
+
+#define UNX_IFMT 0170000 /* Unix file type mask */
+#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */
+#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */
+#define UNX_IFREG 0100000 /* Unix regular file */
+#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */
+#define UNX_IFDIR 0040000 /* Unix directory */
+#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */
+#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */
+
+#define UNX_ISUID 04000 /* Unix set user id on execution */
+#define UNX_ISGID 02000 /* Unix set group id on execution */
+#define UNX_ISVTX 01000 /* Unix directory permissions control */
+#define UNX_ENFMT UNX_ISGID /* Unix record locking enforcement flag */
+
+#define UNX_IRWXU 00700 /* Unix read, write, execute: owner */
+#define UNX_IRUSR 00400 /* Unix read permission: owner */
+#define UNX_IWUSR 00200 /* Unix write permission: owner */
+#define UNX_IXUSR 00100 /* Unix execute permission: owner */
+
+#define UNX_IRWXG 00070 /* Unix read, write, execute: group */
+#define UNX_IRGRP 00040 /* Unix read permission: group */
+#define UNX_IWGRP 00020 /* Unix write permission: group */
+#define UNX_IXGRP 00010 /* Unix execute permission: group */
+
+#define UNX_IRWXO 00007 /* Unix read, write, execute: other */
+#define UNX_IROTH 00004 /* Unix read permission: other */
+#define UNX_IWOTH 00002 /* Unix write permission: other */
+#define UNX_IXOTH 00001 /* Unix execute permission: other */
+
+/* historical file modes */
+#define S_IREAD 0x100
+#define S_IWRITE 0x80
+#define S_IEXEC 0x40
+
+
+#define isatty(arg) 1
+
+
+#define EINVAL 22 /* Invalid argument */
+#define ENAMETOOLONG 63 /* File name too long */
+
+
+struct dirent {
+ char d_name[NAME_MAX];
+};
+
+/*
+ * The following definitions are usually found in fcntl.h.
+ * However, MetroWerks has screwed that file up a couple of times
+ * and all we need are the defines.
+ */
+#define O_APPEND 0x0100 /* open the file in append mode */
+#define O_CREAT 0x0200 /* create the file if it doesn't exist */
+#define O_EXCL 0x0400 /* if the file exists don't create it again */
+#define O_TRUNC 0x0800 /* truncate the file after opening it */
+
+
+int Zmacstat (const char *path, struct stat *buf);
+int chmod(char *path, int mode);
+
+
+#include "macstuff.h"
+
+#endif /* _UNIXLIKE_H */
diff --git a/macos/source/zip_rc.hqx b/macos/source/zip_rc.hqx
new file mode 100644
index 0000000..99e0d25
--- /dev/null
+++ b/macos/source/zip_rc.hqx
@@ -0,0 +1,43 @@
+(This file must be converted with BinHex 4.0)
+:#RTTF#jbBbjcDA3!8dP84&0*9#%!N!3([`#3"&(E8dP8)3!"!!!([h*-BA8#Q3#
+3!aDCQ3d!"RTTF#jbB`!!&[Bi"2[rG!"-5QS!N!1!!*!%"32,j+m2!*!Drj!%8P0
+53e*6483"",#mXHDaqlGG!!!GmJ#3"JFj!*!%6Mi!N!MGc!`!P@6pq1R*k4&+Z,d
+p"5$(b(-Upcc#j%EiHCfjPTq%8h+X8d)MR$`rF[b9Vh`pTLc2jqZ9r'RNq9VN1'&
+'MMmj6Sk6#5HFc0J4lN8iHFU2--,*K%Z1NIR+#1XNR("#bE-)2I+FF$*G@H6BL+`
+*!&6IV1ml1d+22#-$4UEm*#01"T`m*4`Ji(03ThM'$-EBilf-V8-e6Q8bXEVD@Xi
+2bilcmGEY"lV6QGjZrK)I1CKZ$BfR4pSbLD'f`F'qVPKb+*(-*V2CPLfaGj1CE+a
+Z+-$kpr4hpHrCf@d%f66E!A2P-rA6phmUj)QrdYP4r[6)H+cZF"hRV``NHSG5`b!
+F6-0YBZ$!JH&%#frIb,2TmH4`LVGN4c1(%U1Q8#cf)P44dU"#-`D)I($H4I5qc[j
+NJLI5)qpN5)Ic[S(-`-&1H(U2L*U'-H`1Y1p&qc#*YVk4(RNUbp(ae(#'R,B[d%B
+(Nd40$id1C`FhmUlKNBmbkAf$Sra8qpDYcm0,H%GIhbiej(!EESbmC+a*'3dqdlC
+j)%*H#+!,D!K4#J#3!$9H-J)mB*6L!50R"%"&hi6DD*61[-qq22%f1hkXPq@r)'`
+(1hjQJ19cKP'bY0#60RQ3!&kd,r))mj-X,LBCCa&CeiX#f`ibZ$9##+[1HUJ34G5
+584+#&@p9i[UDj-&PD2rAi0qYdMpMQ""M8FLBT`#FUMje-i6rVXl2qI`jK@XY#eH
++%JH[5(`6,qEcH@K,(FfA4rZDNG,4mp60fALH@TT,SC!!5Sf0$HHP31&mP"AfKN)
+K-!N[&XjM@##`1I,(a"V"#L%@#U9'*'lT-5CaU8GqpLTFkUP"%klmfMLJ1QpH5r2
+djNdfhIXJFIqqN!!&1QHe$jUlHF`jZ2I41X8k$@ZbKF1C2"Cq6YZaF(Z+5Yra&63
+"alCh62Vm6N(RqR90&)#m`cE3mILqV`@qBmcQkf0"9Ei%#**RRRpcS0DmV!N6DB-
+&#R112Ym4-1d)GJ(R0,i,0!TEJ!%$#Mj$SFqp80)XU4&"+j!!DmFJk)S2*[(KNMR
+mHApd)4Im@I2aqEBrpd,EVi3ehd@qETI[eprhmmlp0UGjqhe`q#[[Ljk#GDclAll
+[P91j$d[[ir`4X1LcbmVcI$8cCd49rY*`E2l+F1l-Uk0CV,edY8%d('d@pD*qVRk
+L@64FE9KlU9Q%E`3$i@+cD"BSp)'26f,8K%[iL[#3!$-h&aDPY5L2CJBBpF5Kh5k
++ASJVqckQ9kG`*C95rEka+29B5U+f"eYIqF&ZC()P-%GbHXQ44)a!l[Z9q3[c5Z!
+aN!!pGHT"X#q,IJ$8lG#i224dkNXMhd,#3I"ap4JkEk@YlrKEp1r14erRqIYVJY@
+RbX4G0GVTc4A5A20`[E`GcX60GGI#0@$KHMqfFB9BIV4&%kr6+kH*J`(FR3lKcJj
+pNqpN!JiZ-`'&1jQ!a*e-31RCQB$%R8c!dY1CJ19(C`+@AjGIa[qCCq8qH,K8FA%
+LH$LpGbZiFpp0ehUR[lZTL-[HU3T8q*FVkd5&AaDBjrX##ha2S$UImK6,r-Z9MDM
+#PaVqNfUH+VqmXplAGpG!G`k,I&I!i[ZC`J,Iba3@rEQC`J,Iba5@rFQGIhNq5h`
+r-lM2ArAJIYjp(jEjYX!5he+i`cIhZRrjYq)%rjNh@"K4Ej!!V8&p!,8@0C*$l3L
+bk#`f"%i9DMaRk,i*YC&aj0dFH6G(hXf4Gh2Nh4ajYp5aY(5[I@a#hBBDeh9E'*X
+Kq3q,)QS*99$0SCj&R68Va[9Ie6lJ9444KDk%dDE9%CrPQhJ,hbD#)RJ8936RJK1
+bjb%HMTILXr&#r&Um++SIZ#*1fAP1hM-c'CG*VekG*BkGApkj'DZA13GkPA1JPcN
+(iC4c%*m@1&[2l0@LLCK%pFUBG%kj4M@2,@pY&UjA+*Y2#Zil5%pF&GI[LBAVh-2
+$3I"aCG,5ekC[qL[MlZ1QRP32Ga5YQFY`Cf-[rZ!JX+GrCir-1R)J6J!jdY[ekRU
+IXFT6',*jNmH[B69Hq&&6$N-NlS3K8Xm03mM2+VTKb253!iSqNDRHIKqNq$hqV6$
+%pVF8KPMc@68N$0Q#[KXH1UJL$1P'',*PpB``C"5M'eXG)JbTfDal(BB!AfdN$-'
+cjq2P-%6bli8Kq,pej"NCErJr%NGk[[Pkpa44M+pBl4Mq$SC![ij'pZ[3j20d)N[
+i$qR%J5hSI`01r3hJcl+!m54`kMY9f'+N1PrYaRqe4SCq@E8Hr)$%dK,,5@`LdR2
+b$cBKPr+"5-q*AH`)BBm-4AUqlG-DHk"a9QQ`Yi"0+Beefb-pTlj6'Z(2`,ZS0"j
++!KY9'SpQ-0f,5U2Q'(Lr+Sd(h`3fV65DpX2VT0+)[!EHKdUMS4ABTdVMX4IJG8T
+T'*pJ6K'P8IXk0+iTMFB8I'L[i9r!Qp6c`!dlH9,2idGJTp9PD'b(MjH9AZ0cQ02
+TqYdI$#8c2*2-$Kr+**,r!`#3!dm4!!!:
diff --git a/macos/zipup.h b/macos/zipup.h
new file mode 100644
index 0000000..ce2af4a
--- /dev/null
+++ b/macos/zipup.h
@@ -0,0 +1,25 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# include <fcntl.h>
+#endif
+
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+
+typedef int ftype;
+
+
+#define zopen(n,p) MacOpen(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
+
+
diff --git a/man/zip.1 b/man/zip.1
new file mode 100644
index 0000000..0c2fce0
--- /dev/null
+++ b/man/zip.1
@@ -0,0 +1,2840 @@
+.\" =========================================================================
+.\" Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+.\"
+.\" See the accompanying file LICENSE, version 2007-Mar-4 or later
+.\" (the contents of which are also included in zip.h) for terms of use.
+.\" If, for some reason, all these files are missing, the Info-ZIP license
+.\" also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+.\" ==========================================================================
+.\"
+.\" zip.1 by Mark Adler, Jean-loup Gailly and R. P. C. Rodgers
+.\" updated by E. Gordon for Zip 3.0 (8 May 2005, 24 December 2006,
+.\" 4 February 2007, 27 May 2007, 4 June 2007 by EG; 12 June 2007 by CS;
+.\" 30 August 2007, 27 April 2008, 25 May 2008, 27 May 2008 by EG,
+.\" 7 June 2008 by SMS and EG; 12 June 2008 by EG)
+.\"
+.TH ZIP 1L "16 June 2008 (v3.0)" Info-ZIP
+.SH NAME
+zip \- package and compress (archive) files
+.SH SYNOPSIS
+.B zip
+.RB [\- aABcdDeEfFghjklLmoqrRSTuvVwXyz!@$ ]
+[\-\-longoption ...]
+.RB [\- b " path]"
+.RB [\- n " suffixes]"
+.RB [\- t " date]"
+.RB [\- tt " date]"
+[\fIzipfile\fR [\fIfile\fR \.\|.\|.]]
+[\fB-xi\fR list]
+.PP
+.B zipcloak
+(see separate man page)
+.PP
+.B zipnote
+(see separate man page)
+.PP
+.B zipsplit
+(see separate man page)
+.PP
+Note: Command line processing in
+.I zip
+has been changed to support long options and handle all
+options and arguments more consistently. Some old command
+lines that depend on command line inconsistencies may no longer
+work.
+.SH DESCRIPTION
+.I zip
+is a compression and file packaging utility for Unix, VMS, MSDOS,
+OS/2, Windows 9x/NT/XP, Minix, Atari, Macintosh, Amiga, and Acorn
+RISC OS. It is analogous to a combination of the Unix commands
+.IR tar (1)
+and
+.IR compress (1)
+and is compatible with PKZIP (Phil Katz's ZIP for MSDOS systems).
+.LP
+A companion program
+.RI ( unzip (1L))
+unpacks
+.I zip
+archives.
+The
+.I zip
+and
+.IR unzip (1L)
+programs can work with archives produced by PKZIP (supporting
+most PKZIP features up to PKZIP version 4.6),
+and PKZIP and PKUNZIP can work with archives produced by
+\fIzip\fP (with some exceptions, notably streamed archives,
+but recent changes in the zip file standard may facilitate
+better compatibility).
+.I zip
+version 3.0 is compatible with PKZIP 2.04 and also supports
+the Zip64 extensions of PKZIP 4.5 which allow archives
+as well as files to exceed the previous 2 GB limit (4 GB in
+some cases). \fIzip\fP also now supports \fBbzip2\fP compression
+if the \fBbzip2\fP library is included when \fIzip\fP is compiled.
+Note that PKUNZIP 1.10 cannot extract files produced by
+PKZIP 2.04 or
+\fIzip\ 3.0\fP. You must use PKUNZIP 2.04g or
+\fIunzip\ 5.0p1\fP (or later versions) to extract them.
+.PP
+See the \fBEXAMPLES\fP section at the bottom of this page
+for examples of some typical uses of \fIzip\fP.
+.PP
+\fBLarge\ Archives\ and\ Zip64.\fP
+.I zip
+automatically uses the Zip64 extensions when files larger than 4 GB are
+added to an archive, an archive containing Zip64 entries is updated
+(if the resulting archive still needs Zip64),
+the size of the archive will exceed 4 GB, or when the
+number of entries in the archive will exceed about 64K.
+Zip64 is also used for archives streamed from standard input as the size
+of such archives are not known in advance, but the option \fB\-fz\-\fP can
+be used to force \fIzip\fP to create PKZIP 2 compatible archives (as long
+as Zip64 extensions are not needed). You must use a PKZIP 4.5
+compatible unzip, such as \fIunzip\ 6.0\fP or later, to extract files
+using the Zip64 extensions.
+.PP
+In addition, streamed archives, entries encrypted with standard encryption,
+or split archives created with the pause option may not be compatible with
+PKZIP as data descriptors are used
+and PKZIP at the time of this writing does not support data descriptors
+(but recent changes in the PKWare published zip standard now include some
+support for the data descriptor format \fIzip\fP uses).
+
+.PP
+\fBMac OS X.\fP Though previous Mac versions had their own \fIzip\fP port,
+\fIzip\fP supports Mac OS X as part of the Unix port and most Unix features
+apply. References to "MacOS" below generally refer to MacOS versions older
+than OS X. Support for some Mac OS features in the Unix Mac OS X port, such
+as resource forks, is expected in the next \fIzip\fP release.
+
+.PP
+For a brief help on \fIzip\fP and \fIunzip\fP,
+run each without specifying any parameters on the command line.
+
+.SH "USE"
+.PP
+The program is useful for packaging a set of files for distribution;
+for archiving files;
+and for saving disk space by temporarily
+compressing unused files or directories.
+.LP
+The
+.I zip
+program puts one or more compressed files into a single
+.I zip
+archive,
+along with information about the files
+(name, path, date, time of last modification, protection,
+and check information to verify file integrity).
+An entire directory structure can be packed into a
+.I zip
+archive with a single command.
+Compression ratios of 2:1 to 3:1 are common for text files.
+.I zip
+has one compression method (deflation) and can also store files without
+compression. (If \fBbzip2\fP support is added, \fIzip\fP can also
+compress using \fBbzip2\fP compression, but such entries require a
+reasonably modern unzip to decompress. When \fBbzip2\fP compression
+is selected, it replaces deflation as the default method.)
+.I zip
+automatically chooses the better of the two (deflation or store or, if
+\fBbzip2\fP is selected, \fBbzip2\fP or store) for each file to be
+compressed.
+.LP
+\fBCommand\ format.\fP The basic command format is
+.IP
+\fBzip\fR options archive inpath inpath ...
+.LP
+where \fBarchive\fR is a new or existing \fIzip\fR archive
+and \fBinpath\fR is a directory or file path optionally including wildcards.
+When given the name of an existing
+.I zip
+archive,
+.I zip
+will replace identically named entries in the
+.I zip
+archive (matching the relative names as stored in
+the archive) or add entries for new names.
+For example,
+if
+.I foo.zip
+exists and contains
+.I foo/file1
+and
+.IR foo/file2 ,
+and the directory
+.I foo
+contains the files
+.I foo/file1
+and
+.IR foo/file3 ,
+then:
+.IP
+\fCzip -r foo.zip foo\fP
+.LP
+or more concisely
+.IP
+\fCzip -r foo foo\fP
+.LP
+will replace
+.I foo/file1
+in
+.I foo.zip
+and add
+.I foo/file3
+to
+.IR foo.zip .
+After this,
+.I foo.zip
+contains
+.IR foo/file1 ,
+.IR foo/file2 ,
+and
+.IR foo/file3 ,
+with
+.I foo/file2
+unchanged from before.
+.LP
+So if before the zip command is executed \fIfoo.zip\fP has:
+.IP
+\fC foo/file1 foo/file2
+.LP
+and directory foo has:
+.IP
+\fC file1 file3\fP
+.LP
+then \fIfoo.zip\fP will have:
+.IP
+\fC foo/file1 foo/file2 foo/file3\fP
+.LP
+where \fIfoo/file1\fP is replaced and
+\fIfoo/file3\fP is new.
+.LP
+\fB\-@\ file\ lists.\fP If a file list is specified as
+\fB\-@\fP
+[Not on MacOS],
+.I zip
+takes the list of input files from standard input instead of from
+the command line. For example,
+.IP
+\fCzip -@ foo\fP
+.LP
+will store the files listed one per line on stdin in \fIfoo.zip\fP.
+.LP
+Under Unix,
+this option can be used to powerful effect in conjunction with the
+\fIfind\fP\ (1)
+command.
+For example,
+to archive all the C source files in the current directory and
+its subdirectories:
+.IP
+\fCfind . -name "*.[ch]" -print | zip source -@\fP
+.LP
+(note that the pattern must be quoted to keep the shell from expanding it).
+.LP
+\fBStreaming\ input\ and\ output.\fP
+.I zip
+will also accept a single dash ("-") as the zip file name, in which case it
+will write the zip file to standard output, allowing the output to be piped
+to another program. For example:
+.IP
+\fCzip -r - . | dd of=/dev/nrst0 obs=16k\fP
+.LP
+would write the zip output directly to a tape with the specified block size
+for the purpose of backing up the current directory.
+.LP
+.I zip
+also accepts a single dash ("-") as the name of a file to be compressed, in
+which case it will read the file from standard input, allowing zip to take
+input from another program. For example:
+.IP
+\fCtar cf - . | zip backup -\fP
+.LP
+would compress the output of the tar command for the purpose of backing up
+the current directory. This generally produces better compression than
+the previous example using the -r option because
+.I zip
+can take advantage of redundancy between files. The backup can be restored
+using the command
+.IP
+\fCunzip -p backup | tar xf -\fP
+.LP
+When no zip file name is given and stdout is not a terminal,
+.I zip
+acts as a filter, compressing standard input to standard output.
+For example,
+.IP
+\fCtar cf - . | zip | dd of=/dev/nrst0 obs=16k\fP
+.LP
+is equivalent to
+.IP
+\fCtar cf - . | zip - - | dd of=/dev/nrst0 obs=16k\fP
+.LP
+.I zip
+archives created in this manner can be extracted with the program
+.I funzip
+which is provided in the
+.I unzip
+package, or by
+.I gunzip
+which is provided in the
+.I gzip
+package (but some
+.I gunzip
+may not support this if
+.I zip
+used the Zip64 extensions). For example:
+.IP
+\fPdd if=/dev/nrst0 ibs=16k | funzip | tar xvf -\fC
+.LP
+The stream can also be saved to a file and
+.I unzip
+used.
+.LP
+If Zip64 support for large files and archives is enabled and
+\fIzip\fR is used as a filter, \fIzip\fR creates a Zip64 archive
+that requires a PKZIP 4.5 or later compatible unzip to read it. This is
+to avoid amgibuities in the zip file structure as defined in the current
+zip standard (PKWARE AppNote) where the decision to use Zip64 needs to
+be made before data is written for the entry, but for a stream the size
+of the data is not known at that point. If the data is known to be smaller
+than 4 GB, the option \fB\-fz\-\fP can be used to prevent use of Zip64,
+but \fIzip\fP will exit with an error if Zip64 was in fact needed.
+\fIzip\ 3\fR and \fIunzip\ 6\fR and later can read archives with Zip64
+entries. Also, \fIzip\fP removes the Zip64 extensions if not needed
+when archive entries are copied (see the \fB\-U\fP (\fB\-\-copy\fP)
+option).
+.LP
+When directing the output to another file, note that all options should be
+before the redirection including \fB-x\fP. For example:
+.IP
+\fPzip archive "*.h" "*.c" -x donotinclude.h orthis.h > tofile\fC
+.LP
+\fBZip\ files.\fP When changing an existing
+.I zip
+archive,
+.I zip
+will write a temporary file with the new contents,
+and only replace the old one when the process of creating the new version
+has been completed without error.
+.LP
+If the name of the
+.I zip
+archive does not contain an extension, the extension
+\fB.zip\fP
+is added. If the name already contains an extension other than
+\fB.zip\fP,
+the existing extension is kept unchanged. However, split archives
+(archives split over multiple files) require the \fB.zip\fP extension
+on the last split.
+.PP
+\fBScanning\ and\ reading\ files.\fP
+When \fIzip\fP starts, it scans for files to process (if needed). If
+this scan takes longer than about 5 seconds, \fIzip\fP will display
+a "Scanning files" message and start displaying progress dots every 2 seconds
+or every so many entries processed, whichever takes longer. If there is more
+than 2 seconds between dots it could indicate that finding each file is taking
+time and could mean a slow network connection for example.
+(Actually the initial file scan is
+a two-step process where the directory scan is followed by a sort and these
+two steps are separated with a space in the dots. If updating an existing
+archive, a space also appears between the existing file scan and the new
+file scan.) The scanning files dots are not controlled by the \fB\-ds\fP
+dot size option, but the dots are turned off by the \fB\-q\fP quiet option. The
+\fB\-sf\fP show files option can be used to scan for files and get the list of
+files scanned without actually processing them.
+.LP
+If \fIzip\fR is not able to read a file, it
+issues a warning but
+continues. See the \fB\-MM\fP option below for more on how \fIzip\fP handles
+patterns that are not matched and files that are not readable.
+If some files were skipped, a
+warning is issued at the end of the zip operation noting how many files
+were read and how many skipped.
+.PP
+\fBCommand\ modes.\fP \fIzip\fP now supports two distinct types of command
+modes, \fBexternal\fP and \fBinternal\fP. The \fBexternal\fP modes
+(add, update, and freshen) read files from the file system (as well as from an
+existing archive) while the \fBinternal\fP modes (delete and copy) operate
+exclusively on entries in an existing archive.
+.LP
+.TP
+.BI add\ \ \ \ \ \
+Update existing entries and add new files. If the archive does not exist
+create it. This is the default mode.
+.TP
+.BI update\ \fP(\fB\-u\fP)
+Update existing entries if newer on the file system and add new files. If
+the archive does not exist issue warning then create a new archive.
+.TP
+.BI freshen\ \fP(\fB\-f\fP)
+Update existing entries of an archive if newer on the file system.
+Does not add new files to the archive.
+.TP
+.BI delete\ \fP(\fB\-d\fP)
+Select entries in an existing archive and delete them.
+.TP
+.BI copy\ \fP(\fB\-U\fP)
+Select entries in an existing archive and copy them to a new archive.
+This new mode is similar to \fBupdate\fP but command line patterns
+select entries in the existing archive rather than files from
+the file system and it uses the \fB\-\-out\fP option to write the
+resulting archive to a new file rather than update the existing
+archive, leaving the original archive unchanged.
+.LP
+The new File Sync option (\fB\-FS\fP) is also considered a new mode,
+though it is similar to \fBupdate\fP. This mode synchronizes the
+archive with the files on the OS, only replacing files in the
+archive if the file time or size of the OS file is different, adding
+new files, and deleting entries from the archive where there is
+no matching file. As this mode can delete entries from the archive,
+consider making a backup copy of the archive.
+
+Also see \fB\-DF\fP for creating difference archives.
+
+See each option description below for details and the \fBEXAMPLES\fP section
+below for examples.
+.PP
+\fBSplit\ archives.\fP \fIzip\fP version 3.0 and later can create split
+archives. A
+\fBsplit archive\fP is a standard zip archive split over multiple
+files. (Note that split archives are not just archives split in to
+pieces, as the offsets of entries are now based on the start of each
+split. Concatenating the pieces together will invalidate these offsets,
+but \fIunzip\fP can usually deal with it. \fIzip\fP will usually refuse
+to process such a spliced archive unless the \fB\-FF\fP fix option is
+used to fix the offsets.)
+.LP
+One use of split archives is storing a large archive on multiple
+removable media.
+For a split archive with 20 split files the files are typically named (replace
+ARCHIVE with the name of your archive) ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19,
+ARCHIVE.zip. Note that the last file is the \fB.zip\fP file. In contrast,
+\fBspanned archives\fP are the original multi-disk archive generally requiring
+floppy disks and using volume labels to store disk numbers. \fIzip\fP supports
+split archives but not spanned archives, though a procedure exists for converting
+split archives of the right size to spanned archives. The reverse is also true,
+where each file of a spanned archive can be copied in order to files with the
+above names to create a split archive.
+.LP
+Use \fB\-s\fP to set the split size and create a split archive. The size is
+given as a number followed optionally by one of k (kB), m (MB), g (GB), or t (TB)
+(the default is m). The \fB\-sp\fP option can be used to pause \fIzip\fP between
+splits to allow changing removable media, for example, but read the descriptions
+and warnings for both \fB\-s\fP and \fB\-sp\fP below.
+.LP
+Though \fIzip\fP does not update split archives, \fIzip\fP provides the new
+option \fB\-O\fP (\fB\-\-output\-file\fP or \fB\-\-out\fP) to allow split archives
+to be updated and saved in a new archive. For example,
+.IP
+\fCzip inarchive.zip foo.c bar.c \-\-out outarchive.zip\fP
+.LP
+reads archive \fBinarchive.zip\fP, even if split, adds the files \fBfoo.c\fP and
+\fBbar.c\fP, and writes the resulting archive to \fBoutarchive.zip\fP. If
+\fBinarchive.zip\fP is split then \fBoutarchive.zip\fP defaults to the same
+split size. Be aware that if \fBoutarchive.zip\fP and any split files that are
+created with it already exist, these are always overwritten as needed without
+warning. This may be changed in the future.
+.PP
+\fBUnicode.\fP Though the zip standard requires storing paths in an archive using
+a specific character set, in practice zips have stored paths in archives in whatever
+the local character set is. This creates problems when an archive is created or
+updated on a system using one character set and then extracted on another system
+using a different character set. When compiled with Unicode support enabled on
+platforms that support wide characters, \fIzip\fP now stores, in addition to the
+standard local path for backward compatibility, the UTF-8 translation of the path.
+This provides a common universal character set for storing paths that allows these
+paths to be fully extracted on other systems that support Unicode and to match as
+close as possible on systems that don't.
+
+On Win32 systems where paths are internally stored as Unicode but represented in
+the local character set, it's possible that some paths will be skipped during a
+local character set directory scan. \fIzip\fP with Unicode support now can read
+and store these paths. Note that Win 9x systems and FAT file systems don't fully
+support Unicode.
+
+Be aware that console windows on Win32 and Unix, for example, sometimes don't
+accurately show all characters due to how each operating system switches in
+character sets for display. However, directory navigation tools should show the
+correct paths if the needed fonts are loaded.
+.PP
+\fBCommand line format.\fP This version of
+.I zip
+has updated command line processing and support for long options.
+.PP
+Short options take the form
+.IP
+\fC-s[-][s[-]...][value][=value][\ value]\fP
+.LP
+where s is a one or two character short option. A short option
+that takes a value is last in an argument and anything after it is
+taken as the value. If the option can be negated and "-" immediately
+follows the option, the option is negated.
+Short options can also be given as separate arguments
+.IP
+\fC-s[-][value][=value][\ value]\ -s[-][value][=value][\ value]\ ...\fP
+.LP
+Short options in general take values either as part of the same
+argument or as the following argument. An optional = is also supported.
+So
+.IP
+\fC-ttmmddyyyy\fP
+.LP
+and
+.IP
+\fC-tt=mmddyyyy\fP
+.LP
+and
+.IP
+\fC-tt mmddyyyy\fP
+.LP
+all work. The \fB\-x\fP and \fB\-i\fP options accept lists of values
+and use a slightly different format described below. See the
+\fB\-x\fP and \fB\-i\fP options.
+.PP
+Long options take the form
+.IP
+\fC--longoption[-][=value][ value]\fP
+.LP
+where the option starts with --, has a multicharacter name, can
+include a trailing dash to negate the option (if the option
+supports it), and can have a value (option argument) specified by
+preceeding it with = (no spaces). Values can also follow the
+argument. So
+.IP
+\fC--before-date=mmddyyyy\fP
+.LP
+and
+.IP
+\fC--before-date mmddyyyy\fP
+.LP
+both work.
+
+Long option names can be shortened to the shortest unique
+abbreviation. See the option descriptions below for which
+support long options. To avoid confusion, avoid abbreviating
+a negatable option with an embedded dash ("-") at the dash
+if you plan to negate it (the parser would consider
+a trailing dash, such as for the option \fB\-\-some\-option\fP using
+\fB\-\-some\-\fP as the option, as part of the name rather
+than a negating dash). This may be changed to force the last
+dash in \fB\-\-some\-\fP to be negating in the future.
+.SH "OPTIONS"
+.TP
+.PD 0
+.BI \-a
+.TP
+.PD
+.B \-\-ascii
+[Systems using EBCDIC] Translate file to ASCII format.
+
+.TP
+.PD 0
+.B \-A
+.TP
+.PD
+.B \-\-adjust-sfx
+Adjust self-extracting executable archive.
+A self-extracting executable archive is created by prepending
+the SFX stub to an existing archive. The
+.B \-A
+option tells
+.I zip
+to adjust the entry offsets stored
+in the archive to take into account this "preamble" data.
+.LP
+Note: self-extracting archives for the Amiga are a special case.
+At present, only the Amiga port of \fIzip\fP is capable of adjusting
+or updating these without corrupting them. -J can be used to remove
+the SFX stub if other updates need to be made.
+
+.TP
+.PD 0
+.B \-AC
+.TP
+.PD
+.B \-\-archive-clear
+[WIN32] Once archive is created (and tested if \fB\-T\fP is used,
+which is recommended), clear the archive bits of files processed. WARNING:
+Once the bits are cleared they are cleared. You may want to use the
+\fB\-sf\fP show files option to store the list of files processed in case
+the archive operation must be repeated. Also consider using
+the \fB\-MM\fP must match option. Be sure to check out \fB\-DF\fP as a
+possibly better way to do incremental backups.
+
+.TP
+.PD 0
+.B \-AS
+.TP
+.PD
+.B \-\-archive-set
+[WIN32] Only include files that have the archive bit set. Directories
+are not stored when \fB\-AS\fP is used, though by default the paths
+of entries, including directories, are stored as usual and can be used
+by most unzips to recreate directories.
+
+The archive bit is set by the operating system when a file is modified
+and, if used with \fB\-AC\fP, \fB\-AS\fP can provide an
+incremental backup capability. However, other applications can
+modify the archive bit and it may not be a reliable indicator of
+which files have changed since the last archive operation. Alternative
+ways to create incremental backups are using \fB\-t\fP to use file dates,
+though this won't catch old files copied to directories being archived,
+and \fB\-DF\fP to create a differential archive.
+
+.TP
+.PD 0
+.B \-B
+.TP
+.PD
+.B \-\-binary
+[VM/CMS and MVS] force file to be read binary (default is text).
+
+.TP
+.B \-B\fRn
+[TANDEM] set Edit/Enscribe formatting options with n defined as
+.RS
+bit 0: Don't add delimiter (Edit/Enscribe)
+.RE
+.RS
+bit 1: Use LF rather than CR/LF as delimiter (Edit/Enscribe)
+.RE
+.RS
+bit 2: Space fill record to maximum record length (Enscribe)
+.RE
+.RS
+bit 3: Trim trailing space (Enscribe)
+.RE
+.RS
+bit 8: Force 30K (Expand) large read for unstructured files
+.RE
+
+.TP
+.PD 0
+.BI \-b\ \fRpath
+.TP
+.PD
+.B \-\-temp-path\ \fRpath
+Use the specified
+.I path
+for the temporary
+.I zip
+archive. For example:
+.RS
+.IP
+\fCzip -b /tmp stuff *\fP
+.RE
+.IP
+will put the temporary
+.I zip
+archive in the directory
+.IR /tmp ,
+copying over
+.I stuff.zip
+to the current directory when done. This option is useful when
+updating an existing archive and the file system containing this
+old archive does not have enough space to hold both old and new archives
+at the same time. It may also be useful when streaming in some
+cases to avoid the need for data descriptors. Note that using
+this option may require \fIzip\fP take additional time to copy
+the archive file when done to the destination file system.
+
+.TP
+.PD 0
+.B \-c
+.TP
+.PD
+.B \-\-entry-comments
+Add one-line comments for each file.
+File operations (adding, updating) are done first,
+and the user is then prompted for a one-line comment for each file.
+Enter the comment followed by return, or just return for no comment.
+
+.TP
+.PD 0
+.B \-C
+.TP
+.PD
+.B \-\-preserve-case
+[VMS] Preserve case all on VMS. Negating this option
+(\fB\-C-\fP) downcases.
+
+.TP
+.PD 0
+.B \-C2
+.TP
+.PD
+.BI \-\-preserve-case-2
+[VMS] Preserve case ODS2 on VMS. Negating this option
+(\fB\-C2-\fP) downcases.
+
+.TP
+.PD 0
+.B \-C5
+.TP
+.PD
+.B \-\-preserve-case-5
+[VMS] Preserve case ODS5 on VMS. Negating this option
+(\fB\-C5-\fP) downcases.
+
+.TP
+.PD 0
+.B \-d
+.TP
+.PD
+.B \-\-delete
+Remove (delete) entries from a
+.I zip
+archive.
+For example:
+.RS
+.IP
+\fCzip -d foo foo/tom/junk foo/harry/\\* \\*.o\fP
+.RE
+.IP
+will remove the entry
+.IR foo/tom/junk ,
+all of the files that start with
+.IR foo/harry/ ,
+and all of the files that end with
+.B \&.o
+(in any path).
+Note that shell pathname expansion has been inhibited with backslashes,
+so that
+.I zip
+can see the asterisks,
+enabling
+.I zip
+to match on the contents of the
+.I zip
+archive instead of the contents of the current directory.
+(The backslashes are not used on MSDOS-based platforms.)
+Can also use quotes to escape the asterisks as in
+.RS
+.IP
+\fCzip -d foo foo/tom/junk "foo/harry/*" "*.o"\fP
+.RE
+.IP
+Not escaping the asterisks on a system where the shell expands
+wildcards could result in the asterisks being converted to a
+list of files in the current directory and that list used to
+delete entries from the archive.
+.IP
+Under MSDOS,
+.B \-d
+is case sensitive when it matches names in the
+.I zip
+archive.
+This requires that file names be entered in upper case if they were
+zipped by PKZIP on an MSDOS system. (We considered making this
+case insensitive on systems where paths were case insensitive,
+but it is possible the archive came from a system where case does
+matter and the archive could include both \fBBar\fP and \fBbar\fP
+as separate files in the archive.) But see the new option \fB\-ic\fP
+to ignore case in the archive.
+
+.TP
+.PD 0
+.B \-db
+.TP
+.PD
+.B \-\-display-bytes
+Display running byte counts showing the bytes zipped and the bytes to go.
+
+.TP
+.PD 0
+.B \-dc
+.TP
+.PD
+.B \-\-display-counts
+Display running count of entries zipped and entries to go.
+
+.TP
+.PD 0
+.B \-dd
+.TP
+.PD
+.B \-\-display-dots
+Display dots while each entry is zipped (except on ports that have their own
+progress indicator). See \fB-ds\fR below for setting dot size. The default is
+a dot every 10 MB of input file processed. The \fB-v\fR option
+also displays dots (previously at a much higher rate than this but now \fB\-v\fP
+also defaults to 10 MB) and this rate is also controlled by \fB-ds\fR.
+
+.TP
+.PD 0
+.B \-df
+.TP
+.PD
+.B \-\-datafork
+[MacOS] Include only data-fork of files zipped into the archive.
+Good for exporting files to foreign operating-systems.
+Resource-forks will be ignored at all.
+
+.TP
+.PD 0
+.B \-dg
+.TP
+.PD
+.B \-\-display-globaldots
+Display progress dots for the archive instead of for each file. The command
+.RS
+.IP
+ zip -qdgds 10m
+.RE
+.IP
+will turn off most output except dots every 10 MB.
+
+.TP
+.PD 0
+.B \-ds\ \fRsize
+.TP
+.PD
+.B \-\-dot-size\ \fRsize
+Set amount of input file processed for each dot displayed. See \fB-dd\fR to
+enable displaying dots. Setting this option implies \fB-dd\fR. Size is
+in the format nm where n is a number and m is a multiplier. Currently m can
+be k (KB), m (MB), g (GB), or t (TB), so if n is 100 and m is k, size would be
+100k which is 100 KB. The default is 10 MB.
+.IP
+The \fB-v\fR option also displays dots and now defaults to
+10 MB also. This rate is also controlled by this option. A size of 0 turns dots off.
+.IP
+This option does not control the dots from the "Scanning files" message as
+\fIzip\fP scans for input files. The dot size for that is fixed at 2 seconds
+or a fixed number of entries, whichever is longer.
+
+.TP
+.PD 0
+.B \-du
+.TP
+.PD
+.B \-\-display-usize
+Display the uncompressed size of each entry.
+
+.TP
+.PD 0
+.B \-dv
+.TP
+.PD
+.B \-\-display-volume
+Display the volume (disk) number each entry is being read from,
+if reading an existing archive, and being written to.
+
+.TP
+.PD 0
+.B \-D
+.TP
+.PD
+.B \-\-no-dir-entries
+Do not create entries in the
+.I zip
+archive for directories. Directory entries are created by default so that
+their attributes can be saved in the zip archive.
+The environment variable ZIPOPT can be used to change the default options. For
+example under Unix with sh:
+.RS
+.IP
+ZIPOPT="-D"; export ZIPOPT
+.RE
+.IP
+(The variable ZIPOPT can be used for any option, including \fB\-i\fP and \fB\-x\fP
+using a new option format detailed below, and can include several options.) The option
+.B \-D
+is a shorthand
+for
+.B \-x
+"*/" but the latter previously could not be set as default in the ZIPOPT
+environment variable as the contents of ZIPOPT gets inserted near the beginning
+of the command line and the file list had to end at the end of the line.
+.IP
+This version of
+.I zip
+does allow
+.B \-x
+and
+.B \-i
+options in ZIPOPT if the form
+.IP
+\fC
+.BR \-x \ file\ file\ ... \ @\fP
+.IP
+is used, where the @ (an argument that is just @) terminates
+the list.
+
+.TP
+.PD 0
+.B \-DF
+.TP
+.PD
+.B \-\-difference-archive
+Create an archive that contains all new and changed files since
+the original archive was created. For this to work, the input
+file list and current directory must be the same as during the
+original \fIzip\fP operation.
+.IP
+For example, if the existing archive was created using
+.RS
+.IP
+\fCzip -r foofull .
+.RE
+.IP
+from the \fIbar\fP directory, then the command
+.RS
+.IP
+\fCzip -r foofull . -DF --out foonew
+.RE
+.IP
+also from the \fIbar\fP directory creates the archive \fIfoonew\fP
+with just the files not in \fIfoofull\fP and the files where
+the size or file time of the files do not match those in \fIfoofull\fP.
+
+Note that the timezone environment variable TZ should be set according to
+the local timezone in order for this option to work correctly. A
+change in timezone since the original archive was created could
+result in no times matching and all files being included.
+
+A possible approach to backing up a directory might be to create
+a normal archive of the contents of the directory as a full
+backup, then use this option to create incremental backups.
+
+.TP
+.PD 0
+.B \-e
+.TP
+.PD
+.B \-\-encrypt
+Encrypt the contents of the
+.I zip
+archive using a password which is entered on the terminal in response
+to a prompt
+(this will not be echoed; if standard error is not a tty,
+.I zip
+will exit with an error).
+The password prompt is repeated to save the user from typing errors.
+
+.TP
+.PD 0
+.B \-E
+.TP
+.PD
+.B \-\-longnames
+[OS/2] Use the .LONGNAME Extended Attribute (if found) as filename.
+
+.TP
+.PD 0
+.B \-f
+.TP
+.PD
+.B \-\-freshen
+Replace (freshen) an existing entry in the
+.I zip
+archive only if it has been modified more recently than the
+version already in the
+.I zip
+archive;
+unlike the update option
+.RB ( \-u )
+this will not add files that are not already in the
+.I zip
+archive.
+For example:
+.RS
+.IP
+\fCzip -f foo\fP
+.RE
+.IP
+This command should be run from the same directory from which the original
+.I zip
+command was run, since paths stored in
+.I zip
+archives are always relative.
+.IP
+Note that the timezone environment variable TZ should be set according to
+the local timezone in order for the
+\fB\-f\fP, \fB\-u\fP and \fB\-o\fP
+options to work correctly.
+.IP
+The reasons behind this are somewhat subtle but have to do with the differences
+between the Unix-format file times (always in GMT) and most of the other
+operating systems (always local time) and the necessity to compare the two.
+A typical TZ value is ``MET-1MEST'' (Middle European time with automatic
+adjustment for ``summertime'' or Daylight Savings Time).
+.IP
+The format is TTThhDDD, where TTT is the time zone such as MET, hh is the
+difference between GMT and local time such as -1 above, and DDD is
+the time zone when daylight savings time is in effect. Leave off
+the DDD if there is no daylight savings time. For the US Eastern
+time zone EST5EDT.
+
+.TP
+.PD 0
+.B \-F
+.TP
+.B \-\-fix\ \ \ \ \ \
+.TP
+.B \-FF
+.TP
+.PD
+.B \-\-fixfix\ \
+Fix the
+.I zip
+archive. The \fB\-F\fP option can be used if some portions of the archive
+are missing, but requires a reasonably intact central directory.
+The input archive is scanned as usual, but \fIzip\fP will ignore
+some problems. The resulting archive should be valid, but any
+inconsistent entries will be left out.
+.IP
+When doubled as in
+\fB\-FF\fP,
+the archive is scanned from the beginning and \fIzip\fP scans for special
+signatures to identify the limits between the archive members. The
+single
+.B \-F
+is more reliable if the archive is not too much damaged, so try this
+option first.
+.IP
+If the archive is too damaged or the end has been truncated, you
+must use \fB\-FF\fP. This is a change from \fIzip\ 2.32\fP, where
+the \fB\-F\fP option is able to read a truncated archive. The
+\fB\-F\fP option now more reliably fixes archives with minor
+damage and the \fB\-FF\fP option is needed to fix archives where
+\fB\-F\fP might have been sufficient before.
+.IP
+Neither option will recover archives that have been incorrectly
+transferred in ascii mode instead of binary. After the repair, the
+.B \-t
+option of
+.I unzip
+may show that some files have a bad CRC. Such files cannot be recovered;
+you can remove them from the archive using the
+.B \-d
+option of
+\fIzip\fP.
+.IP
+Note that \fB\-FF\fP may have trouble fixing archives that include an
+embedded zip archive that was stored (without compression) in the archive
+and, depending on the damage, it may find the entries in the embedded
+archive rather than the archive itself. Try \fB\-F\fP first as it
+does not have this problem.
+.IP
+The format of the fix commands have changed. For example, to fix
+the damaged archive \fIfoo.zip\fP,
+.RS
+.IP
+\fCzip -F foo --out foofix
+.RE
+.IP
+tries to read the entries normally, copying good entries to the
+new archive \fIfoofix.zip\fP. If this doesn't work, as when the
+archive is truncated, or if some entries you know are in the archive
+are missed, then try
+.RS
+.IP
+\fCzip -FF foo --out foofixfix
+.RE
+.IP
+and compare the resulting archive to the archive created by \fB\-F\fP. The
+\fB\-FF\fP option may create an inconsistent archive. Depending on
+what is damaged, you can then use the \fB\-F\fP option to fix that archive.
+.IP
+A split archive with missing split files can be fixed using
+\fB\-F\fP if you have the last split of the archive (the \fB\.zip\fP file).
+If this file is missing, you must use \fB\-FF\fP to fix the archive,
+which will prompt you for the splits you have.
+.IP
+Currently the fix options can't recover entries that have a bad checksum
+or are otherwise damaged.
+
+.TP
+.PD 0
+.B \-FI
+.TP
+.PD
+.B \-\-fifo
+[Unix] Normally \fIzip\fP skips reading any FIFOs (named pipes) encountered, as
+\fIzip\fP can hang if the FIFO is not being fed. This option tells \fIzip\fP to
+read the contents of any FIFO it finds.
+
+.TP
+.PD 0
+.B \-FS
+.TP
+.PD
+.B \-\-filesync
+Synchronize the contents of an archive with the files on the OS.
+Normally when an archive is updated, new files are added and changed
+files are updated but files that no longer exist on the OS are not
+deleted from the archive. This option enables a new mode that checks
+entries in the archive against the file system. If the file time and
+file size of the entry matches that of the OS file, the entry is
+copied from the old archive instead of being read from the file system
+and compressed. If the OS file has changed, the entry is read and
+compressed as usual. If the entry in the archive does not match a
+file on the OS, the entry is deleted. Enabling this option should
+create archives that are the same as new archives, but since existing
+entries are copied instead of compressed, updating an existing archive
+with \fB\-FS\fP can be much faster than creating a new archive. Also
+consider using \fB\-u\fP for updating an archive.
+.IP
+For this option to work, the archive should be updated from the same
+directory it was created in so the relative paths match. If few files
+are being copied from the old archive, it may be faster to create a
+new archive instead.
+.IP
+Note that the timezone environment variable TZ should be set according to
+the local timezone in order for this option to work correctly. A
+change in timezone since the original archive was created could
+result in no times matching and recompression of all files.
+.IP
+This option deletes files from the archive. If you need to preserve
+the original archive, make a copy of the archive first or use the
+\fB\-\-out\fP option to output the updated archive to a new file.
+Even though it may be slower, creating a new archive with a new archive
+name is safer, avoids mismatches between archive and OS paths, and
+is preferred.
+
+.TP
+.PD 0
+.B \-g
+.TP
+.PD
+.B \-\-grow \ \ \ \ \ \
+Grow (append to) the specified
+.I zip
+archive, instead of creating a new one. If this operation fails,
+.I zip
+attempts to restore the archive to its original state. If the restoration
+fails, the archive might become corrupted. This option is ignored when
+there's no existing archive or when at least one archive member must be
+updated or deleted.
+
+.TP
+.PD 0
+.B \-h
+.TP
+.PD 0
+.B \-?
+.TP
+.PD
+.B \-\-help \ \ \ \ \ \
+Display the
+.I zip
+help information (this also appears if
+.I zip
+is run with no arguments).
+
+.TP
+.PD 0
+.B \-h2
+.TP
+.PD
+.B \-\-more-help
+Display extended help including more on command line format, pattern matching, and
+more obscure options.
+
+.TP
+.PD 0
+.B \-i\ \fRfiles
+.TP
+.PD
+.B \-\-include\ \fRfiles
+Include only the specified files, as in:
+.RS
+.IP
+\fCzip -r foo . -i \\*.c\fP
+.RE
+.IP
+which will include only the files that end in
+.IR \& .c
+in the current directory and its subdirectories. (Note for PKZIP
+users: the equivalent command is
+.RS
+.IP
+\fCpkzip -rP foo *.c\fP
+.RE
+.IP
+PKZIP does not allow recursion in directories other than the current one.)
+The backslash avoids the shell filename substitution, so that the
+name matching is performed by
+.I zip
+at all directory levels.
+[This is for Unix and other systems where \\ escapes the
+next character. For other systems where the shell does not
+process * do not use \\ and the above is
+.RS
+.IP
+\fCzip -r foo . -i *.c\fP
+.RE
+.IP
+Examples are for Unix unless otherwise specified.] So to include dir,
+a directory directly under the current directory, use
+.RS
+.IP
+\fCzip -r foo . -i dir/\\*
+.RE
+.IP
+or
+.RS
+.IP
+\fCzip -r foo . -i "dir/*"
+.RE
+.IP
+to match paths such as dir/a and dir/b/file.c [on
+ports without wildcard expansion in the shell such as MSDOS and Windows
+.RS
+.IP
+\fCzip -r foo . -i dir/*
+.RE
+.IP
+is used.] Note that currently the trailing / is needed
+for directories (as in
+.RS
+.IP
+\fCzip -r foo . -i dir/
+.RE
+.IP
+to include directory dir).
+.IP
+The long option form of the first example is
+.RS
+.IP
+\fCzip -r foo . --include \\*.c
+.RE
+.IP
+and does the same thing as the short option form.
+.IP
+Though the command syntax used to require \fB-i\fR at
+the end of the command line, this version actually
+allows \fB\-i\fP (or \fB\-\-include\fP) anywhere. The
+list of files terminates at the next argument starting
+with \fB-\fR, the end of the command line, or the list
+terminator \fB@\fR (an argument that is just @). So
+the above can be given as
+.RS
+.IP
+zip -i \\*.c @ -r foo .\fP
+.RE
+.IP
+for example. There must be a space between
+the option and the first file of a list. For just
+one file you can use the single value form
+.RS
+.IP
+\fCzip -i\\*.c -r foo .\fP
+.RE
+.IP
+(no space between option and value) or
+.RS
+.IP
+\fCzip --include=\\*.c -r foo .\fP
+.RE
+.IP
+as additional examples. The single value forms are
+not recommended because they can be confusing and,
+in particular, the \fB\-ifile\fP format can cause
+problems if the first letter of \fBfile\fP combines with
+\fBi\fP to form a two-letter option starting with
+\fBi\fP. Use \fB\-sc\fP to see how your command line
+will be parsed.
+.IP
+Also possible:
+.RS
+.IP
+\fCzip -r foo . -i@include.lst\fP
+.RE
+.IP
+which will only include the files in the current directory and its
+subdirectories that match the patterns in the file include.lst.
+.IP
+Files to \fB\-i\fR and \fB\-x\fR are patterns matching internal archive paths. See
+\fB-R\fR for more on patterns.
+
+.TP
+.PD 0
+.B \-I
+.TP
+.PD
+.B \-\-no-image
+[Acorn RISC OS] Don't scan through Image files. When used, \fIzip\fP will not
+consider Image files (eg. DOS partitions or Spark archives when SparkFS
+is loaded) as directories but will store them as single files.
+
+For example, if you have SparkFS loaded, zipping a Spark archive will result
+in a zipfile containing a directory (and its content) while using the 'I'
+option will result in a zipfile containing a Spark archive. Obviously this
+second case will also be obtained (without the 'I' option) if SparkFS isn't
+loaded.
+
+.TP
+.PD 0
+.B \-ic
+.TP
+.PD
+.B \-\-ignore-case
+[VMS, WIN32] Ignore case when matching archive entries. This option is
+only available on systems where the case of files is ignored. On systems
+with case-insensitive file systems, case is normally ignored when matching files
+on the file system but is not ignored for -f (freshen), -d (delete), -U (copy),
+and similar modes when matching against archive entries (currently -f
+ignores case on VMS) because archive entries can be from systems where
+case does matter and names that are the same except for case can exist
+in an archive. The \fB\-ic\fR option makes all matching case insensitive.
+This can result in multiple archive entries matching a command line pattern.
+
+.TP
+.PD 0
+.B \-j
+.TP
+.PD
+.B \-\-junk-paths
+Store just the name of a saved file (junk the path), and do not store
+directory names. By default,
+.I zip
+will store the full path (relative to the current directory).
+
+.TP
+.PD 0
+.B \-jj
+.TP
+.PD
+.B \-\-absolute-path
+[MacOS] record Fullpath (+ Volname). The complete path including
+volume will be stored. By default the relative path will be stored.
+
+.TP
+.PD 0
+.B \-J
+.TP
+.PD
+.B \-\-junk-sfx
+Strip any prepended data (e.g. a SFX stub) from the archive.
+.TP
+.PD 0
+.B \-k
+.TP
+.PD
+.B \-\-DOS-names
+Attempt to convert the names and paths to conform to MSDOS,
+store only the MSDOS attribute (just the user write attribute from Unix),
+and mark the entry as made under MSDOS (even though it was not);
+for compatibility with PKUNZIP under MSDOS which cannot handle certain
+names such as those with two dots.
+.TP
+.PD 0
+.B \-l
+.TP
+.PD
+.B \-\-to-crlf
+Translate the Unix end-of-line character LF into the
+MSDOS convention CR LF. This option should not be used on binary files.
+This option can be used on Unix if the zip file is intended for PKUNZIP
+under MSDOS. If the input files already contain CR LF, this option adds
+an extra CR. This is to ensure that
+\fBunzip -a\fP
+on Unix will get back an exact copy of the original file,
+to undo the effect of
+\fBzip -l\fP. See \fB-ll\fR for how binary files are handled.
+.TP
+.PD 0
+.B \-la
+.TP
+.PD
+.B \-\-log-append
+Append to existing logfile. Default is to overwrite.
+.TP
+.PD 0
+.B \-lf\ \fPlogfilepath
+.TP
+.PD
+.B \-\-logfile-path\ \fPlogfilepath
+Open a logfile at the given path. By default any existing file at that location
+is overwritten, but the \fB\-la\fP option will result in an existing file being
+opened and the new log information appended to any existing information.
+Only warnings and errors are written to the log unless the \fB\-li\fP option is
+also given, then all information messages are also written to the log.
+.TP
+.PD 0
+.B \-li
+.TP
+.PD
+.B \-\-log-info
+Include information messages, such as file names being zipped, in the log.
+The default is to only include the command line, any warnings and errors, and
+the final status.
+.TP
+.PD 0
+.B \-ll
+.TP
+.PD
+.B \-\-from-crlf
+Translate the MSDOS end-of-line CR LF into Unix LF.
+This option should not be used on binary files.
+This option can be used on MSDOS if the zip file is intended for unzip
+under Unix. If the file is converted and the file is later determined
+to be binary a warning is issued and the file is probably
+corrupted. In this release if \fB-ll\fR detects binary in the first buffer
+read from a file, \fIzip\fR now issues a warning and skips line end
+conversion on the file. This check seems to catch all binary files
+tested, but the original check remains and if a converted file is
+later determined to be binary that warning is still issued. A new algorithm
+is now being used for binary detection that should allow line end conversion
+of text files in \fBUTF-8\fR and similar encodings.
+.TP
+.PD 0
+.B \-L
+.TP
+.PD
+.B \-\-license
+Display the
+.I zip
+license.
+.TP
+.PD 0
+.B \-m
+.TP
+.PD
+.B \-\-move \ \ \
+Move the specified files into the
+.I zip
+archive; actually,
+this deletes the target directories/files after making the specified
+.I zip
+archive. If a directory becomes empty after removal of the files, the
+directory is also removed. No deletions are done until
+.I zip
+has created the archive without error.
+This is useful for conserving disk space,
+but is potentially dangerous so it is recommended to use it in
+combination with
+.B \-T
+to test the archive before removing all input files.
+.TP
+.PD 0
+.B \-MM
+.TP
+.PD
+.B \-\-must-match
+All input patterns must match at least one file and all input files
+found must be readable. Normally when an input pattern does not match
+a file the "name not matched" warning is issued and when an input file
+has been found but later is missing or not readable a missing or not
+readable warning is issued. In either case
+.I zip
+continues creating the archive, with missing or unreadable new files
+being skipped and files already in the archive remaining unchanged.
+After the archive is created, if any files were not readable
+.I zip
+returns the OPEN error code (18 on most systems) instead of the normal
+success return (0 on most systems). With \fB\-MM\fP set,
+.I zip
+exits as soon as an input pattern is not matched (whenever the
+"name not matched" warning would be issued) or when an input file is
+not readable. In either case \fIzip\fR exits with an OPEN error
+and no archive is created.
+.IP
+This option is useful when a known list of files is to be zipped so
+any missing or unreadable files will result in an error. It is less
+useful when used with wildcards, but \fIzip\fR will still exit with an
+error if any input pattern doesn't match at least one file and if any
+matched files are unreadable. If you want to create the archive
+anyway and only need to know if files were skipped, don't use
+.B \-MM
+and just check the return code. Also \fB\-lf\fP could be useful.
+.TP
+.PD 0
+.BI \-n\ \fRsuffixes
+.TP
+.PD
+.B \-\-suffixes\ \fRsuffixes
+Do not attempt to compress files named with the given
+\fBsuffixes\fR.
+Such files are simply stored (0% compression) in the output zip file,
+so that
+.I zip
+doesn't waste its time trying to compress them.
+The suffixes are separated by
+either colons or semicolons. For example:
+.RS
+.IP
+\fCzip -rn .Z:.zip:.tiff:.gif:.snd foo foo\fP
+.RE
+.IP
+will copy everything from
+.I foo
+into
+.IR foo.zip ,
+but will store any files that end in
+.IR .Z ,
+.IR .zip ,
+.IR .tiff ,
+.IR .gif ,
+or
+.I .snd
+without trying to compress them
+(image and sound files often have their own specialized compression methods).
+By default,
+.I zip
+does not compress files with extensions in the list
+.I .Z:.zip:.zoo:.arc:.lzh:.arj.
+Such files are stored directly in the output archive.
+The environment variable ZIPOPT can be used to change the default options. For
+example under Unix with csh:
+.RS
+.IP
+setenv ZIPOPT "-n .gif:.zip"
+.RE
+.IP
+To attempt compression on all files, use:
+.RS
+.IP
+zip -n : foo
+.RE
+.IP
+The maximum compression option
+.B \-9
+also attempts compression on all files regardless of extension.
+.IP
+On Acorn RISC OS systems the suffixes are actually filetypes (3 hex digit
+format). By default, \fIzip\fP does not compress files with filetypes in the list
+DDC:D96:68E (i.e. Archives, CFS files and PackDir files).
+.TP
+.PD 0
+.B \-nw
+.TP
+.PD
+.B \-\-no-wild
+Do not perform internal wildcard processing (shell processing of wildcards is still done
+by the shell unless the arguments are escaped). Useful if a list of paths is being
+read and no wildcard substitution is desired.
+.TP
+.PD 0
+.B \-N
+.TP
+.PD
+.B \-\-notes
+[Amiga, MacOS] Save Amiga or MacOS filenotes as zipfile comments. They can be
+restored by using the -N option of \fIunzip\fP. If -c is used also, you are
+prompted for comments only for those files that do not have filenotes.
+.TP
+.PD 0
+.B \-o
+.TP
+.PD
+.B \-\-latest-time
+Set the "last modified" time of the
+.I zip
+archive to the latest (oldest) "last modified" time
+found among the entries in the
+.I zip
+archive.
+This can be used without any other operations, if desired.
+For example:
+.IP
+\fCzip -o foo\fP
+.IP
+will change the last modified time of
+\fBfoo.zip\fP
+to the latest time of the entries in
+.BR foo.zip .
+.TP
+.PD 0
+.B \-O \fPoutput-file
+.TP
+.PD
+.B \-\-output-file \fPoutput-file
+Process the archive changes as usual, but instead of updating the existing archive,
+output the new archive to output-file. Useful for updating an archive
+without changing the existing archive and the input archive must be a different file
+than the output archive.
+
+This option can be used to create updated split archives.
+It can also be used with \fB\-U\fP to copy entries from an existing archive to a new
+archive. See the \fBEXAMPLES\fP section below.
+
+Another use is converting \fIzip\fP files from one split size to another. For instance,
+to convert an archive with 700 MB CD splits to one with 2 GB DVD splits, can use:
+.RS
+.IP
+zip -s 2g cd-split.zip --out dvd-split.zip
+.RE
+.IP
+which uses copy mode. See \fB\-U\fP below. Also:
+.RS
+.IP
+zip -s 0 split.zip --out unsplit.zip
+.RE
+.IP
+will convert a split archive to a single-file archive.
+
+Copy mode will convert stream entries (using data descriptors and which
+should be compatible with most unzips) to normal entries (which should
+be compatible
+with all unzips), except if standard encryption was used. For archives
+with encrypted entries, \fIzipcloak\fP will decrypt the entries and convert
+them to normal entries.
+.TP
+.PD 0
+.B \-p
+.TP
+.PD
+.B \-\-paths
+Include relative file paths as part of the names of files stored in the archive.
+This is the default. The \fB\-j\fP option junks the paths and just stores the
+names of the files.
+.TP
+.PD 0
+.B \-P\ \fRpassword
+.TP
+.PD
+.B \-\-password\ \fRpassword
+Use \fIpassword\fP to encrypt zipfile entries (if any). \fBTHIS IS
+INSECURE!\fP Many multi-user operating systems provide ways for any user to
+see the current command line of any other user; even on stand-alone systems
+there is always the threat of over-the-shoulder peeking. Storing the plaintext
+password as part of a command line in an automated script is even worse.
+Whenever possible, use the non-echoing, interactive prompt to enter passwords.
+(And where security is truly important, use strong encryption such as Pretty
+Good Privacy instead of the relatively weak standard encryption provided by
+zipfile utilities.)
+.TP
+.PD 0
+.B \-q
+.TP
+.PD
+.B \-\-quiet
+Quiet mode;
+eliminate informational messages and comment prompts.
+(Useful, for example, in shell scripts and background tasks).
+.TP
+.PD 0
+.BI \-Q\fRn
+.TP
+.PD
+.B \-\-Q\-flag\ \fRn
+[QDOS] store information about the file in the file header with n defined as
+.RS
+bit 0: Don't add headers for any file
+.RE
+.RS
+bit 1: Add headers for all files
+.RE
+.RS
+bit 2: Don't wait for interactive key press on exit
+.RE
+.TP
+.PD 0
+.B \-r
+.TP
+.PD
+.B \-\-recurse\-paths
+Travel the directory structure recursively;
+for example:
+.RS
+.IP
+zip -r foo.zip foo
+.RE
+.IP
+or more concisely
+.RS
+.IP
+zip -r foo foo
+.RE
+.IP
+In this case, all the files and directories in
+.B foo
+are saved in a
+.I zip
+archive named \fBfoo.zip\fP,
+including files with names starting with \fB"."\fP,
+since the recursion does not use the shell's file-name substitution mechanism.
+If you wish to include only a specific subset of the files in directory
+\fBfoo\fP
+and its subdirectories, use the
+\fB\-i\fP
+option to specify the pattern of files to be included.
+You should not use
+\fB\-r\fP
+with the name \fB".*"\fP,
+since that matches \fB".."\fP
+which will attempt to zip up the parent directory
+(probably not what was intended).
+.IP
+Multiple source directories are allowed as in
+.RS
+.IP
+\fCzip -r foo foo1 foo2\fP
+.RE
+.IP
+which first zips up \fBfoo1\fP and then \fBfoo2\fP, going down each directory.
+.IP
+Note that while wildcards to \fB-r\fR are typically resolved while recursing down
+directories in the file system, any \fB-R\fN, \fB-x\fR, and \fB-i\fR wildcards
+are applied to internal archive pathnames once the directories are scanned.
+To have wildcards apply to files in subdirectories when recursing on
+Unix and similar systems where the shell does wildcard substitution, either
+escape all wildcards or put all arguments with wildcards in quotes. This lets
+\fIzip\fR see the wildcards and match files in subdirectories using them as
+it recurses.
+.TP
+.PD 0
+.B \-R
+.TP
+.PD
+.B \-\-recurse\-patterns
+Travel the directory structure recursively starting at the
+current directory;
+for example:
+.RS
+.IP
+\fCzip -R foo "*.c"\fP
+.RE
+.IP
+In this case, all the files matching \fB*.c\fP in the tree starting at the
+current directory are stored into a
+.I zip
+archive named
+\fBfoo.zip\fP.
+Note that \fB*.c\fP will match \fBfile.c\fP, \fBa/file.c\fP
+and \fBa/b/.c\fP. More than one pattern can be listed as separate
+arguments.
+Note for PKZIP users: the equivalent command is
+.RS
+.IP
+\fCpkzip -rP foo *.c\fP
+.RE
+.IP
+Patterns are relative file paths as they appear in the archive, or will after
+zipping, and can have optional wildcards in them. For example, given
+the current directory is \fBfoo\fP and under it are directories \fBfoo1\fP and \fBfoo2\fP
+and in \fBfoo1\fP is the file \fBbar.c\fP,
+.RS
+.IP
+\fCzip -R foo/*\fP
+.RE
+.IP
+will zip up \fBfoo\fP, \fBfoo/foo1\fP, \fBfoo/foo1/bar.c\fP, and \fBfoo/foo2\fP.
+.RS
+.IP
+\fCzip -R */bar.c\fP
+.RE
+.IP
+will zip up \fBfoo/foo1/bar.c\fP. See the note for \fB-r\fR on escaping wildcards.
+
+.TP
+.PD 0
+.B \-RE
+.TP
+.PD
+.B \-\-regex
+[WIN32] Before \fIzip\fP \fI3.0\fP, regular expression list matching was
+enabled by default on Windows platforms. Because of confusion resulting
+from the need to escape "[" and "]" in names, it is now off by default for
+Windows so "[" and "]" are just normal characters in names. This option
+enables [] matching again.
+
+.TP
+.PD 0
+.B \-s\ \fPsplitsize
+.TP
+.PD
+.B \-\-split\-size\ \fPsplitsize
+Enable creating a split archive and set the split size. A split archive is an archive
+that could be split over many files. As the archive is created, if the size of the
+archive reaches the specified split size, that split is closed and the next split
+opened. In general all splits but the last will be the split size and the last
+will be whatever is left. If the entire archive is smaller than the split size a
+single-file archive is created.
+
+Split archives are stored in numbered files. For example, if the output
+archive is named \fBarchive\fP and three splits are required, the resulting
+archive will be in the three files \fBarchive.z01\fP, \fBarchive.z02\fP, and
+\fBarchive.zip\fP. Do not change the numbering of these files or the archive
+will not be readable as these are used to determine the order the splits are read.
+
+Split size is a number optionally followed by a multiplier. Currently the
+number must be an integer. The multiplier can currently be one of
+\fBk\fP (kilobytes), \fBm\fP (megabytes), \fBg\fP (gigabytes), or \fBt\fP
+(terabytes). As 64k is the minimum split size, numbers without multipliers
+default to megabytes. For example, to create a split archive called \fBfoo\fP
+with the contents of the \fBbar\fP directory with splits of 670 MB that might
+be useful for burning on CDs, the command:
+.RS
+.IP
+zip -s 670m -r foo bar
+.RE
+.IP
+could be used.
+
+Currently the old splits of a split archive are not excluded from a new
+archive, but they can be specifically excluded. If possible, keep
+the input and output archives out of the path being zipped when creating
+split archives.
+
+Using \fB\-s\fP without \fB\-sp\fP as above creates all the splits where
+\fBfoo\fP is being written, in this case the current directory. This split
+mode updates the splits as the archive is being created, requiring all
+splits to remain writable, but creates split archives that are readable by
+any unzip that supports split archives. See \fB\-sp\fP below for enabling
+split pause mode which allows splits to be written directly to removable
+media.
+
+The option \fB\-sv\fP can be used to enable verbose splitting and provide details of
+how the splitting is being done. The \fB\-sb\fP option can be used to ring the bell
+when \fIzip\fP pauses for the next split destination.
+
+Split archives cannot be updated, but see the \fB\-O\fP (\fB\-\-out\fP) option for
+how a split archive can be updated as it is copied to a new archive.
+A split archive can also be converted into a single-file archive using a
+split size of 0 or negating the \fB\-s\fP option:
+.RS
+.IP
+zip -s 0 split.zip --out single.zip
+.RE
+.IP
+Also see \fB\-U\fP (\fB\-\-copy\fP) for more on using copy mode.
+.TP
+.PD 0
+.B \-sb
+.TP
+.PD
+.B \-\-split\-bell
+If splitting and using split pause mode, ring the bell when \fIzip\fP pauses
+for each split destination.
+.TP
+.PD 0
+.B \-sc
+.TP
+.PD
+.B \-\-show\-command
+Show the command line starting \fIzip\fP as processed and exit. The new command parser
+permutes the arguments, putting all options and any values associated with them
+before any non-option arguments. This allows an option to appear anywhere in the
+command line as long as any values that go with the option go with it. This option
+displays the command line as \fIzip\fP sees it, including any arguments from
+the environment such as from the \fBZIPOPT\fP variable. Where allowed, options later
+in the command line can override options earlier in the command line.
+.TP
+.PD 0
+.B \-sf
+.TP
+.PD
+.B \-\-show\-files
+Show the files that would be operated on, then exit. For instance, if creating
+a new archive, this will list the files that would be added. If the option is
+negated, \fB\-sf\-\fP, output only to an open log file. Screen display is
+not recommended for large lists.
+.TP
+.PD 0
+.B \-so
+.TP
+.PD
+.B \-\-show\-options
+Show all available options supported by \fIzip\fP as compiled on the current system.
+As this command reads the option table, it should include all options. Each line
+includes the short option (if defined), the long option (if defined), the format
+of any value that goes with the option, if the option can be negated, and a
+small description. The value format can be no value, required value, optional
+value, single character value, number value, or a list of values. The output of
+this option is not intended to show how to use any option but only
+show what options are available.
+.TP
+.PD 0
+.B \-sp
+.TP
+.PD
+.B \-\-split\-pause
+If splitting is enabled with \fB\-s\fP, enable split pause mode. This
+creates split archives as \fB\-s\fP does, but stream writing is used so each
+split can be closed as soon as it is written and \fIzip\fP will pause between each
+split to allow changing split destination or media.
+
+Though this split mode allows writing splits directly to removable media, it
+uses stream archive format that may not be readable by some unzips. Before
+relying on splits created with \fB\-sp\fP, test a split archive with the unzip
+you will be using.
+
+To convert a stream split archive (created with \fB\-sp\fP) to a standard archive
+see the \fB\-\-out\fP option.
+.TP
+.PD 0
+.B \-su
+.TP
+.PD
+.B \-\-show\-unicode
+As \fB\-sf\fP, but also show Unicode version of the path if exists.
+.TP
+.PD 0
+.B \-sU
+.TP
+.PD
+.B \-\-show\-just\-unicode
+As \fB\-sf\fP, but only show Unicode version of the path if exists, otherwise show
+the standard version of the path.
+.TP
+.PD 0
+.B \-sv
+.TP
+.PD
+.B \-\-split\-verbose
+Enable various verbose messages while splitting, showing how the splitting is being
+done.
+.TP
+.PD 0
+.B \-S
+.TP
+.PD
+.B \-\-system-hidden
+[MSDOS, OS/2, WIN32 and ATARI] Include system and hidden files.
+.RS
+[MacOS] Includes finder invisible files, which are ignored otherwise.
+.RE
+.TP
+.PD 0
+.BI \-t\ \fRmmddyyyy
+.TP
+.PD
+.B \-\-from\-date\ \fRmmddyyyy
+Do not operate on files modified prior to the specified date,
+where
+.B mm
+is the month (00-12),
+.B dd
+is the day of the month (01-31),
+and
+.B yyyy
+is the year.
+The
+.I ISO\ 8601
+date format
+.B yyyy\-mm\-dd
+is also accepted.
+For example:
+.RS
+.IP
+\fCzip -rt 12071991 infamy foo\fP
+
+\fCzip -rt 1991-12-07 infamy foo\fP
+.RE
+.IP
+will add all the files in
+.B foo
+and its subdirectories that were last modified on or after 7 December 1991,
+to the
+.I zip
+archive
+.BR infamy.zip .
+.TP
+.PD 0
+.BI \-tt\ \fRmmddyyyy
+.TP
+.PD
+.B \-\-before\-date\ \fRmmddyyyy
+Do not operate on files modified after or at the specified date,
+where
+.B mm
+is the month (00-12),
+.B dd
+is the day of the month (01-31),
+and
+.B yyyy
+is the year.
+The
+.I ISO\ 8601
+date format
+.B yyyy\-mm\-dd
+is also accepted.
+For example:
+.RS
+.IP
+\fCzip -rtt 11301995 infamy foo\fP
+
+\fCzip -rtt 1995-11-30 infamy foo\fP
+.RE
+.IP
+will add all the files in
+.B foo
+and its subdirectories that were last modified before 30 November 1995,
+to the
+.I zip
+archive
+.BR infamy.zip .
+.TP
+.PD 0
+.B \-T
+.TP
+.PD
+.B \-\-test\ \ \ \
+Test the integrity of the new zip file. If the check fails, the old zip file
+is unchanged and (with the
+.B -m
+option) no input files are removed.
+.TP
+.PD 0
+.B \-TT\ \fPcmd
+.TP
+.PD
+.B \-\-unzip-command\ \fPcmd
+Use command cmd instead of 'unzip -tqq' to test an archive when the \fB\-T\fP
+option is used. On Unix, to use a copy of unzip in the current directory instead
+of the standard system unzip, could use:
+.IP
+\fC zip archive file1 file2 -T -TT "./unzip -tqq"\fP
+.IP
+In cmd, {} is replaced by the name of the temporary archive, otherwise the name
+of the archive is appended to the end of the command.
+The return code is checked for success (0 on Unix).
+.TP
+.PD 0
+.B \-u
+.TP
+.PD
+.B \-\-update
+Replace (update) an existing entry in the
+.I zip
+archive only if it has been modified more recently
+than the version already in the
+.I zip
+archive.
+For example:
+.RS
+.IP
+\fCzip -u stuff *\fP
+.RE
+.IP
+will add any new files in the current directory,
+and update any files which have been modified since the
+.I zip
+archive
+.I stuff.zip
+was last created/modified (note that
+.I zip
+will not try to pack
+.I stuff.zip
+into itself when you do this).
+.IP
+Note that the
+.B \-u
+option with no input file arguments acts like the
+.B \-f
+(freshen) option.
+.TP
+.PD 0
+.B \-U
+.TP
+.PD
+.B \-\-copy\-entries
+Copy entries from one archive to another. Requires the \fB\-\-out\fP
+option to specify a different output file than the input archive. Copy
+mode is the reverse of \fB\-d\fP delete. When delete is being used
+with \fB\-\-out\fP, the selected entries are deleted from the archive
+and all other entries are copied to the new archive, while copy mode
+selects the files to include in the new archive. Unlike \fB\-u\fP
+update, input patterns on the command line are matched against archive
+entries only and not the file system files. For instance,
+.RS
+.IP
+\fCzip inarchive "*.c" --copy --out outarchive\fP
+.RE
+.IP
+copies entries with names ending in \fB\.c\fP from \fBinarchive\fP
+to \fBoutarchive\fP. The wildcard must be escaped on some systems
+to prevent the shell from substituting names of files from the
+file system which may have no relevance to the entries in the archive.
+
+If no input files appear on the command line and \fB\-\-out\fP is
+used, copy mode is assumed:
+.RS
+.IP
+\fCzip inarchive --out outarchive\fP
+.RE
+.IP
+This is useful for changing split size for instance. Encrypting
+and decrypting entries is not yet supported using copy mode. Use
+\fIzipcloak\fP for that.
+.TP
+.PD 0
+.B \-UN\ \fRv
+.TP
+.PD
+.B \-\-unicode\ \fRv
+Determine what \fIzip\fP should do with Unicode file names.
+\fIzip\ 3.0\fP, in addition to the standard file path, now
+includes the UTF\-8 translation of the path if the entry path
+is not entirely 7-bit ASCII. When an entry
+is missing the Unicode path, \fIzip\fP reverts back to the
+standard file path. The problem with using the standard path
+is this path is in the local character set of the zip that created
+the entry, which may contain characters that are not valid in
+the character set being used by the unzip. When \fIzip\fP is
+reading an archive, if an entry also has a Unicode path,
+\fIzip\fP now defaults to using the Unicode path to recreate
+the standard path using the current local character set.
+
+This option can be used to determine what \fIzip\fP should do
+with this path if there is a mismatch between the stored standard path
+and the stored UTF-8 path (which can happen if the standard path was
+updated). In all cases, if there is a mismatch it is
+assumed that the standard path is more current and
+\fIzip\fP uses that. Values for \fBv\fP are
+.RS
+.IP
+q \- quit if paths do not match
+.IP
+w \- warn, continue with standard path
+.IP
+i \- ignore, continue with standard path
+.IP
+n \- no Unicode, do not use Unicode paths
+.RE
+.IP
+The default is to warn and continue.
+
+Characters that are not valid in the current character set are
+escaped as \fB#Uxxxx\fP and \fB#Lxxxxxx\fP, where x is an
+ASCII character for a hex digit. The first is used if a 16-bit
+character number is sufficient to represent the Unicode character
+and the second if the character needs more than 16 bits to
+represent it's Unicode character code. Setting \fB\-UN\fP to
+.RS
+.IP
+e \- escape
+.RE
+.IP
+as in
+.RS
+.IP
+\fCzip archive -sU -UN=e\fP
+.RE
+.IP
+forces \fIzip\fP to escape all characters that are not printable 7-bit
+ASCII.
+
+Normally \fIzip\fP stores UTF\-8 directly in the standard path field
+on systems where UTF\-8 is the current character set and stores the
+UTF\-8 in the new extra fields otherwise. The option
+.RS
+.IP
+u \- UTF\-8
+.RE
+.IP
+as in
+.RS
+.IP
+\fCzip archive dir -r -UN=UTF8\fP
+.RE
+.IP
+forces \fIzip\fP to store UTF\-8 as native in the archive. Note that
+storing UTF\-8 directly is the default on Unix systems that support it.
+This option could be useful on Windows systems where the escaped
+path is too large to be a valid path and the UTF\-8 version of the
+path is smaller, but native UTF\-8 is not backward compatible on
+Windows systems.
+
+.TP
+.PD 0
+.B \-v
+.TP
+.PD
+.B \-\-verbose
+Verbose mode or print diagnostic version info.
+.IP
+Normally, when applied to real operations, this option enables the display of a
+progress indicator during compression (see \fB-dd\fR for more on dots) and
+requests verbose diagnostic info about zipfile structure oddities.
+.IP
+However, when
+.B \-v
+is the only command line argument a diagnostic screen is printed instead. This
+should now work even if stdout is redirected to a file, allowing easy saving
+of the information for sending with bug reports to Info-ZIP. The version
+screen provides the help screen header with program name, version, and release
+date, some pointers to the Info-ZIP home and distribution sites, and shows
+information about the target environment (compiler type and version, OS
+version, compilation date and the enabled optional features used to create the
+.I zip
+executable).
+.TP
+.PD 0
+.B \-V
+.TP
+.PD
+.B \-\-VMS\-portable
+[VMS] Save VMS file attributes.
+(Files are truncated at EOF.) When a -V archive is unpacked on a
+non-VMS system, some file types (notably Stream_LF
+text files and pure binary files like fixed-512)
+should be extracted intact. Indexed files and file
+types with embedded record sizes (notably variable-length record types)
+will probably be seen as corrupt elsewhere.
+.TP
+.PD 0
+.B \-VV
+.TP
+.PD
+.B \-\-VMS\-specific
+[VMS] Save VMS file attributes, and all allocated
+blocks in a file, including any data beyond EOF.
+Useful for moving ill-formed files among VMS systems. When a -VV archive is
+unpacked on a non-VMS system, almost all files will appear corrupt.
+.TP
+.PD 0
+.B \-w
+.TP
+.PD
+.B \-\-VMS\-versions
+[VMS] Append the version number of the files to the name,
+including multiple versions of files. Default is to use only
+the most recent version of a specified file.
+.TP
+.PD 0
+.B \-ww
+.TP
+.PD
+.B \-\-VMS\-dot\-versions
+[VMS] Append the version number of the files to the name,
+including multiple versions of files, using the \.nnn format.
+Default is to use only the most recent version of a specified
+file.
+.TP
+.PD 0
+.BI \-ws
+.TP
+.PD
+.B \-\-wild\-stop\-dirs
+Wildcards match only at a directory level. Normally \fIzip\fP handles
+paths as strings and given the paths
+.RS
+.IP
+/foo/bar/dir/file1.c
+.IP
+/foo/bar/file2.c
+.RE
+.IP
+an input pattern such as
+.RS
+.IP
+/foo/bar/*
+.RE
+.IP
+normally would match both paths, the * matching \fBdir/file1.c\fP
+and \fBfile2.c\fP. Note that in the first case a directory
+boundary (/) was crossed in the match. With \fB\-ws\fP no
+directory bounds will be included in the match, making
+wildcards local to a specific directory level. So, with
+\fB\-ws\fP enabled, only the second path would be matched.
+
+When using \fB\-ws\fP, use ** to match across directory boundaries as
+* does normally.
+.TP
+.PD 0
+.BI \-x\ \fRfiles
+.TP
+.PD
+.B \-\-exclude\ \fRfiles
+Explicitly exclude the specified files, as in:
+.RS
+.IP
+\fCzip -r foo foo -x \\*.o\fP
+.RE
+.IP
+which will include the contents of
+.B foo
+in
+.B foo.zip
+while excluding all the files that end in
+\fB.o\fP.
+The backslash avoids the shell filename substitution, so that the
+name matching is performed by
+.I zip
+at all directory levels.
+.IP
+Also possible:
+.RS
+.IP
+\fCzip -r foo foo -x@exclude.lst\fP
+.RE
+.IP
+which will include the contents of
+.B foo
+in
+.B foo.zip
+while excluding all the files that match the patterns in the file
+\fBexclude.lst\fP.
+.IP
+The long option forms of the above are
+.RS
+.IP
+\fCzip -r foo foo --exclude \\*.o\fP
+.RE
+.IP
+and
+.RS
+.IP
+\fCzip -r foo foo --exclude @exclude.lst\fP
+.RE
+.IP
+Multiple patterns can be specified, as in:
+.RS
+.IP
+\fCzip -r foo foo -x \\*.o \\*.c\fP
+.RE
+.IP
+If there is no space between \fB\-x\fP and
+the pattern, just one value is assumed (no list):
+.RS
+.IP
+\fCzip -r foo foo -x\\*.o\fP
+.RE
+.IP
+.IP
+See \fB-i\fR for more on include and exclude.
+.TP
+.PD 0
+.B \-X
+.TP
+.PD
+.B \-\-no\-extra
+Do not save extra file attributes (Extended Attributes on OS/2, uid/gid
+and file times on Unix). The zip format uses extra fields to include
+additional information for each entry. Some extra fields are specific
+to particular systems while others are applicable to all systems.
+Normally when \fIzip\fP reads entries from an existing archive, it
+reads the extra fields it knows, strips the rest, and adds
+the extra fields applicable to that system. With \fB\-X\fP, \fIzip\fP strips
+all old fields and only includes the Unicode and Zip64 extra fields
+(currently these two extra fields cannot be disabled).
+
+Negating this option, \fB\-X\-\fP, includes all the default extra fields,
+but also copies over any unrecognized extra fields.
+.TP
+.PD 0
+.B \-y
+.TP
+.PD
+.B \-\-symlinks
+For UNIX and VMS (V8.3 and later), store symbolic links as such in the
+.I zip
+archive, instead of compressing and storing the file referred to by
+the link. This can avoid multiple copies of files being included in
+the archive as \fIzip\fP recurses the directory trees and accesses
+files directly and by links.
+.TP
+.PD 0
+.B \-z
+.TP
+.PD
+.B \-\-archive\-comment
+Prompt for a multi-line comment for the entire
+.I zip
+archive.
+The comment is ended by a line containing just a period,
+or an end of file condition (^D on Unix, ^Z on MSDOS, OS/2, and VMS).
+The comment can be taken from a file:
+.RS
+.IP
+\fCzip -z foo < foowhat\fP
+.RE
+.TP
+.PD 0
+.B \-Z\ \fRcm
+.TP
+.PD
+.B \-\-compression\-method\ \fRcm
+Set the default compression method. Currently the main methods supported
+by \fIzip\fP are \fBstore\fP and \fBdeflate\fP. Compression method
+can be set to:
+
+\fBstore\fP \- Setting the compression method to \fBstore\fP forces
+\fIzip\fP to store entries with no compression. This is generally
+faster than compressing entries, but results in no space savings.
+This is the same as using \fB\-0\fP (compression level zero).
+
+\fBdeflate\fP \- This is the default method for \fIzip\fP. If \fIzip\fP
+determines that storing is better than deflation, the entry will be
+stored instead.
+
+\fBbzip2\fP \- If \fBbzip2\fP support is compiled in, this compression
+method also becomes available. Only some modern unzips currently support
+the \fBbzip2\fP compression method, so test the unzip you will be using
+before relying on archives using this method (compression method 12).
+
+For example, to add \fBbar.c\fP to archive \fBfoo\fP using \fBbzip2\fP
+compression:
+.RS
+.IP
+zip -Z bzip2 foo bar.c
+.RE
+.IP
+The compression method can be abbreviated:
+.RS
+.IP
+zip -Zb foo bar.c
+.RE
+.IP
+.TP
+.PD 0
+.BI \-#
+.TP
+.PD
+.B (\-0, \-1, \-2, \-3, \-4, \-5, \-6, \-7, \-8, \-9)
+Regulate the speed of compression using the specified digit
+.BR # ,
+where
+.B \-0
+indicates no compression (store all files),
+.B \-1
+indicates the fastest compression speed (less compression)
+and
+.B \-9
+indicates the slowest compression speed (optimal compression, ignores
+the suffix list). The default compression level is
+.BR \-6.
+
+Though still being worked, the intention is this setting will control
+compression speed for all compression methods. Currently only
+deflation is controlled.
+.TP
+.PD 0
+.B \-!
+.TP
+.PD
+.B \-\-use\-privileges
+[WIN32] Use priviliges (if granted) to obtain all aspects of WinNT security.
+.TP
+.PD 0
+.B \-@
+.TP
+.PD
+.B \-\-names\-stdin
+Take the list of input files from standard input. Only one filename per line.
+.TP
+.PD 0
+.B \-$
+.TP
+.PD
+.B \-\-volume\-label
+[MSDOS, OS/2, WIN32] Include the volume label for the drive holding
+the first file to be compressed. If you want to include only the volume
+label or to force a specific drive, use the drive name as first file name,
+as in:
+.RS
+.IP
+\fCzip -$ foo a: c:bar\fP
+.RE
+.IP
+.SH "EXAMPLES"
+The simplest example:
+.IP
+\fCzip stuff *\fP
+.LP
+creates the archive
+.I stuff.zip
+(assuming it does not exist)
+and puts all the files in the current directory in it, in compressed form
+(the
+\fB\&.zip\fP
+suffix is added automatically, unless the archive name contains
+a dot already;
+this allows the explicit specification of other suffixes).
+.LP
+Because of the way the shell on Unix does filename substitution,
+files starting with "." are not included;
+to include these as well:
+.IP
+\fCzip stuff .* *\fP
+.LP
+Even this will not include any subdirectories from the current directory.
+.LP
+To zip up an entire directory, the command:
+.IP
+\fCzip -r foo foo\fP
+.LP
+creates the archive
+.IR foo.zip ,
+containing all the files and directories in the directory
+.I foo
+that is contained within the current directory.
+.LP
+You may want to make a
+.I zip
+archive that contains the files in
+.IR foo ,
+without recording the directory name,
+.IR foo .
+You can use the
+.B \-j
+option to leave off the paths,
+as in:
+.IP
+\fCzip -j foo foo/*\fP
+.LP
+If you are short on disk space,
+you might not have enough room to hold both the original directory
+and the corresponding compressed
+.I zip
+archive.
+In this case, you can create the archive in steps using the
+.B \-m
+option.
+If
+.I foo
+contains the subdirectories
+.IR tom ,
+.IR dick ,
+and
+.IR harry ,
+you can:
+.IP
+\fCzip -rm foo foo/tom\fP
+.br
+\fCzip -rm foo foo/dick\fP
+.br
+\fCzip -rm foo foo/harry\fP
+.LP
+where the first command creates
+.IR foo.zip ,
+and the next two add to it.
+At the completion of each
+.I zip
+command,
+the last created archive is deleted,
+making room for the next
+.I zip
+command to function.
+
+
+
+.LP
+Use \fB\-s\fP to set the split size and create a split archive. The size is given as
+a number followed optionally by one of k (kB), m (MB), g (GB), or t (TB).
+The command
+.IP
+\fCzip -s 2g -r split.zip foo\fP
+.LP
+creates a split archive of the directory foo with splits no bigger than 2\ GB each. If
+foo contained 5\ GB of contents and the contents were stored in the split archive without
+compression (to make this example simple), this would create three splits, split.z01 at 2\ GB,
+split.z02 at 2\ GB, and split.zip at a little over 1\ GB.
+.LP
+The \fB\-sp\fP option can be used to pause \fIzip\fP between splits to allow changing
+removable media, for example, but read the descriptions and warnings for both \fB\-s\fP
+and \fB\-sp\fP below.
+.LP
+Though \fIzip\fP does not update split archives, \fIzip\fP provides the new option \fB\-O\fP
+(\fB\-\-output\-file\fP) to allow split archives to be updated and saved in a new archive. For example,
+.IP
+\fCzip inarchive.zip foo.c bar.c \-\-out outarchive.zip\fP
+.LP
+reads archive \fBinarchive.zip\fP, even if split, adds the files \fBfoo.c\fP and
+\fBbar.c\fP, and writes the resulting archive to \fBoutarchive.zip\fP. If
+\fBinarchive.zip\fP is split then \fBoutarchive.zip\fP defaults
+to the same split size. Be aware that \fBoutarchive.zip\fP and any split files
+that are created with it are always overwritten without warning. This may be changed
+in the future.
+
+
+
+
+.SH "PATTERN MATCHING"
+This section applies only to Unix.
+Watch this space for details on MSDOS and VMS operation.
+However, the special wildcard characters \fB*\fR and \fB[]\fR below apply
+to at least MSDOS also.
+.LP
+The Unix shells (\fIsh\fP, \fIcsh\fP, \fIbash\fP, and others) normally
+do filename substitution (also called "globbing") on command arguments.
+Generally the special characters are:
+.TP
+.B ?
+match any single character
+.TP
+.B *
+match any number of characters (including none)
+.TP
+.B []
+match any character in the range indicated within the brackets
+(example: [a\-f], [0\-9]). This form of wildcard matching
+allows a user to specify a list of characters between square brackets and
+if any of the characters match the expression matches. For example:
+.RS
+.IP
+\fCzip archive "*.[hc]"\fP
+.RE
+.IP
+would archive all files in the current directory that end in
+\fB.h\fP or \fB.c\fP.
+
+Ranges of characters are supported:
+.RS
+.IP
+\fCzip archive "[a\-f]*"\fP
+.RE
+.IP
+would add to the archive all files starting with "a" through "f".
+
+Negation is also supported, where any character in that position not in
+the list matches. Negation is supported by adding \fB!\fP or \fB^\fP
+to the beginning of the list:
+.RS
+.IP
+\fCzip archive "*.[!o]"\fP
+.RE
+.IP
+matches files that don't end in ".o".
+
+On WIN32, [] matching needs to be turned on with the -RE option to avoid
+the confusion that names with [ or ] have caused.
+
+.LP
+When these characters are encountered
+(without being escaped with a backslash or quotes),
+the shell will look for files relative to the current path
+that match the pattern,
+and replace the argument with a list of the names that matched.
+.LP
+The
+.I zip
+program can do the same matching on names that are in the
+.I zip
+archive being modified or,
+in the case of the
+.B \-x
+(exclude) or
+.B \-i
+(include) options, on the list of files to be operated on, by using
+backslashes or quotes to tell the shell not to do the name expansion.
+In general, when
+.I zip
+encounters a name in the list of files to do, it first looks for the name in
+the file system. If it finds it, it then adds it to the list of files to do.
+If it does not find it, it looks for the name in the
+.I zip
+archive being modified (if it exists), using the pattern matching characters
+described above, if present. For each match, it will add that name to the
+list of files to be processed, unless this name matches one given
+with the
+.B \-x
+option, or does not match any name given with the
+.B \-i
+option.
+.LP
+The pattern matching includes the path,
+and so patterns like \\*.o match names that end in ".o",
+no matter what the path prefix is.
+Note that the backslash must precede every special character (i.e. ?*[]),
+or the entire argument must be enclosed in double quotes ("").
+.LP
+In general, use backslashes or double quotes for paths
+that have wildcards to make
+.I zip
+do the pattern matching for file paths, and always for
+paths and strings that have spaces or wildcards for
+\fB\-\i\fP, \fB\-x\fP, \fB\-R\fP, \fB\-d\fP, and \fB\-U\fP
+and anywhere \fIzip\fP needs to process the wildcards.
+.SH "ENVIRONMENT"
+.LP
+The following environment variables are read and used by
+.I zip
+as described.
+.TP
+.B ZIPOPT\ \
+contains default options that will be used when running
+\fIzip\fR. The contents of this environment variable will get
+added to the command line just after the \fBzip\fR command.
+.TP
+.B ZIP\ \ \ \ \
+[Not on RISC OS and VMS] see ZIPOPT
+.TP
+.B Zip$Options
+[RISC OS] see ZIPOPT
+.TP
+.B Zip$Exts
+[RISC OS] contains extensions separated by a : that will cause
+native filenames with one of the specified extensions to
+be added to the zip file with basename and extension swapped.
+.TP
+.B ZIP_OPTS
+[VMS] see ZIPOPT
+.SH "SEE ALSO"
+compress(1),
+shar(1L),
+tar(1),
+unzip(1L),
+gzip(1L)
+.SH DIAGNOSTICS
+The exit status (or error level) approximates the exit codes defined by PKWARE
+and takes on the following values, except under VMS:
+.RS
+.IP 0
+normal; no errors or warnings detected.
+.IP 2
+unexpected end of zip file.
+.IP 3
+a generic error in the zipfile format was detected. Processing may have
+completed successfully anyway; some broken zipfiles created by other
+archivers have simple work-arounds.
+.IP 4
+\fIzip\fP was unable to allocate memory for one or more buffers during
+program initialization.
+.IP 5
+a severe error in the zipfile format was detected. Processing probably
+failed immediately.
+.IP 6
+entry too large to be processed (such as input files larger than 2 GB when
+not using Zip64 or trying to read an existing archive that is too large) or
+entry too large to be split with \fIzipsplit\fP
+.IP 7
+invalid comment format
+.IP 8
+\fIzip\fP -T failed or out of memory
+.IP 9
+the user aborted \fIzip\fP prematurely with control-C (or similar)
+.IP 10
+\fIzip\fP encountered an error while using a temp file
+.IP 11
+read or seek error
+.IP 12
+\fIzip\fP has nothing to do
+.IP 13
+missing or empty zip file
+.IP 14
+error writing to a file
+.IP 15
+\fIzip\fP was unable to create a file to write to
+.IP 16
+bad command line parameters
+.IP 18
+\fIzip\fP could not open a specified file to read
+.IP 19
+\fIzip\fP was compiled with options not supported on this system
+.RE
+.PP
+VMS interprets standard Unix (or PC) return values as other, scarier-looking
+things, so \fIzip\fP instead maps them into VMS-style status codes. In
+general, \fIzip\fP sets VMS Facility = 1955 (0x07A3), Code = 2* Unix_status,
+and an appropriate Severity (as specified in ziperr.h). More details are
+included in the VMS-specific documentation. See [.vms]NOTES.TXT and
+[.vms]vms_msg_gen.c.
+.PD
+.SH BUGS
+.I zip
+3.0 is not compatible with PKUNZIP 1.10. Use
+.I zip
+1.1 to produce
+.I zip
+files which can be extracted by PKUNZIP 1.10.
+.PP
+.I zip
+files produced by
+.I zip
+3.0 must not be
+.I updated
+by
+.I zip
+1.1 or PKZIP 1.10, if they contain
+encrypted members or if they have been produced in a pipe or on a non-seekable
+device. The old versions of
+.I zip
+or PKZIP would create an archive with an incorrect format.
+The old versions can list the contents of the zip file
+but cannot extract it anyway (because of the new compression algorithm).
+If you do not use encryption and use regular disk files, you do
+not have to care about this problem.
+.LP
+Under VMS,
+not all of the odd file formats are treated properly.
+Only stream-LF format
+.I zip
+files are expected to work with
+.IR zip .
+Others can be converted using Rahul Dhesi's BILF program.
+This version of
+.I zip
+handles some of the conversion internally.
+When using Kermit to transfer zip files from VMS to MSDOS, type "set
+file type block" on VMS. When transfering from MSDOS to VMS, type
+"set file type fixed" on VMS. In both cases, type "set file type
+binary" on MSDOS.
+.LP
+Under some older VMS versions, \fIzip\fP may hang for file
+specifications that use DECnet syntax
+.I foo::*.*.
+.LP
+On OS/2, zip cannot match some names, such as those including an
+exclamation mark or a hash sign. This is a bug in OS/2 itself: the
+32-bit DosFindFirst/Next don't find such names. Other programs such
+as GNU tar are also affected by this bug.
+.LP
+Under OS/2, the amount of Extended Attributes displayed by DIR is (for
+compatibility) the amount returned by the 16-bit version of
+DosQueryPathInfo(). Otherwise OS/2 1.3 and 2.0 would report different
+EA sizes when DIRing a file.
+However, the structure layout returned by the 32-bit DosQueryPathInfo()
+is a bit different, it uses extra padding bytes and link pointers (it's
+a linked list) to have all fields on 4-byte boundaries for portability
+to future RISC OS/2 versions. Therefore the value reported by
+.I zip
+(which uses this 32-bit-mode size) differs from that reported by DIR.
+.I zip
+stores the 32-bit format for portability, even the 16-bit
+MS-C-compiled version running on OS/2 1.3, so even this one shows the
+32-bit-mode size.
+.SH AUTHORS
+Copyright (C) 1997-2008 Info-ZIP.
+.LP
+Currently distributed under the Info-ZIP license.
+.LP
+Copyright (C) 1990-1997 Mark Adler, Richard B. Wales, Jean-loup Gailly,
+Onno van der Linden, Kai Uwe Rommel, Igor Mandrichenko, John Bush and
+Paul Kienitz.
+.LP
+Original copyright:
+.LP
+Permission is granted to any individual or institution to use, copy, or
+redistribute this software so long as all of the original files are included,
+that it is not sold for profit, and that this copyright notice
+is retained.
+.LP
+LIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
+PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES
+RESULTING FROM THE USE OF THIS SOFTWARE.
+.LP
+Please send bug reports and comments using the web page at:
+.IR www.info-zip.org .
+For bug reports, please include the version of
+.IR zip
+(see \fIzip\ \-h\fR),
+the make options used to compile it (see \fIzip\ \-v\fR),
+the machine and operating system in use,
+and as much additional information as possible.
+.SH ACKNOWLEDGEMENTS
+Thanks to R. P. Byrne for his
+.I Shrink.Pas
+program, which inspired this project,
+and from which the shrink algorithm was stolen;
+to Phil Katz for placing in the public domain the
+.I zip
+file format, compression format, and .ZIP filename extension, and for
+accepting minor changes to the file format; to Steve Burg for
+clarifications on the deflate format; to Haruhiko Okumura and Leonid
+Broukhis for providing some useful ideas for the compression
+algorithm; to Keith Petersen, Rich Wales, Hunter Goatley and Mark
+Adler for providing a mailing list and
+.I ftp
+site for the Info-ZIP group to use; and most importantly, to the
+Info-ZIP group itself (listed in the file
+.IR infozip.who )
+without whose tireless testing and bug-fixing efforts a portable
+.I zip
+would not have been possible.
+Finally we should thank (blame) the first Info-ZIP moderator,
+David Kirschbaum,
+for getting us into this mess in the first place.
+The manual page was rewritten for Unix by R. P. C. Rodgers and
+updated by E. Gordon for \fIzip\fR 3.0.
+.\" end of file
diff --git a/man/zipcloak.1 b/man/zipcloak.1
new file mode 100644
index 0000000..8260b98
--- /dev/null
+++ b/man/zipcloak.1
@@ -0,0 +1,111 @@
+.TH zipcloak 1 "v3.0 of 8 May 2008"
+.SH NAME
+zipcloak \- encrypt entries in a zipfile
+
+.SH SYNOPSIS
+.I zipcloak
+.RB [ \-d ]
+.RB [ \-b\ path ]
+.RB [ \-h ]
+.RB [ \-v ]
+.RB [ \-L ]
+zipfile
+
+.SH ARGUMENTS
+.in +13
+.ti -13
+zipfile Zipfile to encrypt entries in
+
+.SH OPTIONS
+.TP
+.PD 0
+.B \-b\ \fPpath
+.TP
+.PD
+.B \-\-temp\-path \fPpath
+Use the directory given by path for the temporary zip file.
+
+.TP
+.PD 0
+.B \-d
+.TP
+.PD
+.B \-\-decrypt
+Decrypt encrypted entries (copy if given wrong password).
+
+.TP
+.PD 0
+.B \-h
+.TP
+.PD
+.B \-\-help\
+Show a short help.
+
+.TP
+.PD 0
+.B \-L
+.TP
+.PD
+.B \-\-license
+Show software license.
+
+.TP
+.PD 0
+.B \-O\ \fPpath
+.TP
+.PD
+.B \-\-output\-file\ \fPzipfile
+Write output to new archive zipfile, leaving original archive as is.
+
+.TP
+.PD 0
+.B \-q
+.TP
+.PD
+.B \-\-quiet
+Quiet operation. Suppresses some informational messages.
+
+.TP
+.PD 0
+.B \-v
+.TP
+.PD
+.B \-\-version
+Show version information.
+
+.SH DESCRIPTION
+.I zipcloak
+encrypts all unencrypted entries in the zipfile. This is the default action.
+
+.TP
+The \-d option is used to decrypt encrypted entries in the zipfile.
+
+.TP
+\fIzipcloak \fBuses original zip encryption which is considered weak.
+
+.TP
+Note:
+The encryption code of this program is not copyrighted and is put in
+the public domain. It was originally written in Europe and can be freely
+distributed from any country including the U.S.A. (Previously if this
+program was imported into the U.S.A, it could not be re-exported from
+the U.S.A to another country.) See the file README.CR included in the
+source distribution for more on this. Otherwise, the Info-ZIP license
+applies.
+
+.SH EXAMPLES
+To be added.
+
+.SH BUGS
+Large files (> 2 GB) and large archives not yet supported.
+
+Split archives not yet supported. A work around is to convert the
+split archive to a single-file archive using \fIzip\fP and then
+use \fIzipcloak\fP on the single-file archive. If needed, the
+resulting archive can then be split again using \fIzip\fP.
+
+
+.SH SEE ALSO
+zip(1), unzip(1)
+.SH AUTHOR
+Info-ZIP
diff --git a/man/zipnote.1 b/man/zipnote.1
new file mode 100644
index 0000000..fb4d18b
--- /dev/null
+++ b/man/zipnote.1
@@ -0,0 +1,85 @@
+.TH zipnote 1 "v3.0 of 8 May 2008"
+.SH NAME
+zipnote \- write the comments in zipfile to stdout, edit comments and rename files in zipfile
+
+.SH SYNOPSIS
+.I zipnote
+.RB [ \-w ]
+.RB [ \-b\ path ]
+.RB [ \-h ]
+.RB [ \-v ]
+.RB [ \-L ]
+zipfile
+
+.SH ARGUMENTS
+.in +13
+.ti -13
+zipfile Zipfile to read comments from or edit.
+
+.SH OPTIONS
+.TP
+.BI \-w
+Write comments to a zipfile from stdin (see below).
+.TP
+.BI \-b\ \fRpath
+Use path for the temporary zip file.
+.TP
+.BI \-h
+Show a short help.
+.TP
+.BI \-v
+Show version information.
+.TP
+.BI \-L
+Show software license.
+
+.SH DESCRIPTION
+.I zipnote
+writes the comments in a zipfile to stdout. This is the default mode. A second mode
+allows updating the comments in a zipfile as well as allows changing the names
+of the files in the zipfile. These modes are described below.
+
+.SH EXAMPLES
+To write all comments in a zipfile to stdout use for example
+.LP
+.nf
+ zipnote foo.zip > foo.tmp
+.fi
+.LP
+This writes all comments in the zipfile
+.I foo.zip
+to the file
+.I foo.tmp
+in a specific format.
+
+.LP
+If desired, this file can then be edited to change the comments and then used
+to update the zipfile.
+.LP
+.nf
+ zipnote -w foo.zip < foo.tmp
+.fi
+.LP
+The names of the files in the zipfile can also be changed in this way. This is done by
+following lines like
+.nf
+ "@ name"
+.fi
+in the created temporary file (called
+.I foo.tmp
+here) with lines like
+.nf
+ "@=newname"
+.fi
+and then using the -w option as above.
+
+.SH BUGS
+The temporary file format is rather specific and zipnote is rather picky about it.
+It should be easier to change file names in a script.
+
+Does not yet support large (> 2 GB) or split archives.
+
+.SH SEE ALSO
+zip(1), unzip(1)
+.SH AUTHOR
+Info-ZIP
diff --git a/man/zipsplit.1 b/man/zipsplit.1
new file mode 100644
index 0000000..4a4de64
--- /dev/null
+++ b/man/zipsplit.1
@@ -0,0 +1,69 @@
+.TH zipnote 1 "v3.0 of 8 May 2008"
+.SH NAME
+zipsplit \- split a zipfile into smaller zipfiles
+
+.SH SYNOPSIS
+.I zipsplit
+.RB [ \-t ]
+.RB [ \-i ]
+.RB [ \-p ]
+.RB [ \-s ]
+.RB [ \-n\ size ]
+.RB [ \-r\ room ]
+.RB [ \-b\ path ]
+.RB [ \-h ]
+.RB [ \-v ]
+.RB [ \-L ]
+zipfile
+
+.SH ARGUMENTS
+.in +13
+.ti -13
+zipfile Zipfile to split.
+
+.SH OPTIONS
+.TP
+.BI \-t
+Report how many files it will take, but don't make them.
+.TP
+.BI \-i
+Make index (zipsplit.idx) and count its size against first zip file.
+.TP
+.BI \-n\ \fRsize
+Make zip files no larger than "size" (default = 36000).
+.TP
+.BI \-r\ \fRroom
+Leave room for "room" bytes on the first disk (default = 0).
+.TP
+.BI \-b\ \fRpath
+Use path for the output zip files.
+.TP
+.BI \-p
+Pause between output zip files.
+.TP
+.BI \-s
+Do a sequential split even if it takes more zip files.
+.TP
+.BI \-h
+Show a short help.
+.TP
+.BI \-v
+Show version information.
+.TP
+.BI \-L
+Show software license.
+
+.SH DESCRIPTION
+.I zipsplit
+reads a zipfile and splits it into smaller zipfiles.
+
+.SH EXAMPLES
+To be filled in.
+
+.SH BUGS
+Does not yet support large (> 2 GB) or split archives.
+
+.SH SEE ALSO
+zip(1), unzip(1)
+.SH AUTHOR
+Info-ZIP
diff --git a/match.S b/match.S
new file mode 100644
index 0000000..eb8f735
--- /dev/null
+++ b/match.S
@@ -0,0 +1,407 @@
+/*
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2004-May-22 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/*
+ * match.s by Jean-loup Gailly. Translated to 32 bit code by Kai Uwe Rommel.
+ * The 68020 version has been written by Francesco Potorti` <pot@cnuce.cnr.it>
+ * with adaptations by Carsten Steger <stegerc@informatik.tu-muenchen.de>,
+ * Andreas Schwab <schwab@lamothe.informatik.uni-dortmund.de> and
+ * Kristoffer Eriksson <ske@pkmab.se>
+ */
+
+/* This file is NOT used in conjunction with zlib. */
+#ifndef USE_ZLIB
+
+/* Preprocess with -DNO_UNDERLINE if your C compiler does not prefix
+ * external symbols with an underline character '_'.
+ */
+#if defined(NO_UNDERLINE) || defined(__ELF__)
+# define _prev prev
+# define _window window
+# define _match_start match_start
+# define _prev_length prev_length
+# define _good_match good_match
+# define _nice_match nice_match
+# define _strstart strstart
+# define _max_chain_length max_chain_length
+
+# define _match_init match_init
+# define _longest_match longest_match
+#endif
+
+#ifdef DYN_ALLOC
+ error: DYN_ALLOC not yet supported in match.s
+#endif
+
+/* Use 16-bytes alignment if your assembler supports it. Warning: gas
+ * uses a log(x) parameter (.align 4 means 16-bytes alignment). On SVR4
+ * the parameter is a number of bytes.
+ */
+#ifndef ALIGNMENT
+# define ALIGNMENT 4
+#endif
+
+
+#ifndef WSIZE
+# define WSIZE 32768
+#endif
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_DIST (WSIZE - MIN_LOOKAHEAD)
+
+#if defined(i386) || defined(_I386) || defined(_i386) || defined(__i386)
+
+/* This version is for 386 Unix or OS/2 in 32 bit mode.
+ * Warning: it uses the AT&T syntax: mov source,dest
+ * This file is only optional. If you want to force the C version,
+ * add -DNO_ASM to CFLAGS in Makefile and set OBJA to an empty string.
+ * If you have reduced WSIZE in (g)zip.h, then make sure this is
+ * assembled with an equivalent -DWSIZE=<whatever>.
+ * This version assumes static allocation of the arrays (-DDYN_ALLOC not used).
+ */
+
+ .file "match.S"
+
+ .globl _match_init
+ .globl _longest_match
+
+ .text
+
+_match_init:
+ ret
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+ .align ALIGNMENT
+
+_longest_match: /* int longest_match(cur_match) */
+
+#define cur_match 20(%esp)
+ /* return address */ /* esp+16 */
+ push %ebp /* esp+12 */
+ push %edi /* esp+8 */
+ push %esi /* esp+4 */
+ push %ebx /* esp */
+
+/*
+ * match equ esi
+ * scan equ edi
+ * chain_length equ ebp
+ * best_len equ ebx
+ * limit equ edx
+ */
+ mov cur_match,%esi
+ mov _strstart,%edx
+ mov _max_chain_length,%ebp /* chain_length = max_chain_length */
+ mov %edx,%edi
+ sub $(MAX_DIST),%edx /* limit = strstart-MAX_DIST */
+ cld /* string ops increment si and di */
+ jae limit_ok
+ sub %edx,%edx /* limit = NIL */
+limit_ok:
+ add $2+_window,%edi /* edi = offset(window+strstart+2) */
+ mov _prev_length,%ebx /* best_len = prev_length */
+ movw -2(%edi),%cx /* cx = scan[0..1] */
+ movw -3(%ebx,%edi),%ax /* ax = scan[best_len-1..best_len] */
+ cmp _good_match,%ebx /* do we have a good match already? */
+ jb do_scan
+ shr $2,%ebp /* chain_length >>= 2 */
+ jmp do_scan
+
+ .align ALIGNMENT
+long_loop:
+/* at this point, edi == scan+2, esi == cur_match */
+ movw -3(%ebx,%edi),%ax /* ax = scan[best_len-1..best_len] */
+ movw -2(%edi),%cx /* cx = scan[0..1] */
+short_loop:
+/*
+ * at this point, di == scan+2, si == cur_match,
+ * ax = scan[best_len-1..best_len] and cx = scan[0..1]
+ */
+ and $(WSIZE-1), %esi
+ dec %ebp /* --chain_length */
+ movw _prev(,%esi,2),%si /* cur_match = prev[cur_match] */
+ /* top word of esi is still 0 */
+ jz the_end
+ cmp %edx,%esi /* cur_match <= limit ? */
+ jbe the_end
+do_scan:
+ cmpw _window-1(%ebx,%esi),%ax/* check match at best_len-1 */
+ jne short_loop
+ cmpw _window(%esi),%cx /* check min_match_length match */
+ jne short_loop
+
+ add $2+_window,%esi /* si = match */
+ mov $((MAX_MATCH>>1)-1),%ecx/* scan for at most MAX_MATCH bytes */
+ mov %edi,%eax /* ax = scan+2 */
+ repe; cmpsw /* loop until mismatch */
+ je maxmatch /* match of length MAX_MATCH? */
+mismatch:
+ movb -2(%edi),%cl /* mismatch on first or second byte? */
+ xchg %edi,%eax /* edi = scan+2, eax = end of scan */
+ subb -2(%esi),%cl /* cl = 0 if first bytes equal */
+ sub %edi,%eax /* eax = len */
+ sub $2+_window,%esi /* esi = cur_match + len */
+ sub %eax,%esi /* esi = cur_match */
+ subb $1,%cl /* set carry if cl == 0 (cannot use DEC) */
+ adc $0,%eax /* eax = carry ? len+1 : len */
+ cmp %ebx,%eax /* len > best_len ? */
+ jle long_loop
+ mov %esi,_match_start /* match_start = cur_match */
+ mov %eax,%ebx /* ebx = best_len = len */
+#ifdef FULL_SEARCH
+ cmp $(MAX_MATCH),%eax /* len >= MAX_MATCH ? */
+#else
+ cmp _nice_match,%eax /* len >= nice_match ? */
+#endif
+ jl long_loop
+the_end:
+ mov %ebx,%eax /* result = eax = best_len */
+ pop %ebx
+ pop %esi
+ pop %edi
+ pop %ebp
+ ret
+ .align ALIGNMENT
+maxmatch:
+ cmpsb
+ jmp mismatch
+
+#else /* !(i386 || _I386 || _i386 || __i386) */
+
+/* ======================== 680x0 version ================================= */
+
+#if defined(m68k)||defined(mc68k)||defined(__mc68000__)||defined(__MC68000__)
+# ifndef mc68000
+# define mc68000
+# endif
+#endif
+
+#if defined(__mc68020__) || defined(__MC68020__) || defined(sysV68)
+# ifndef mc68020
+# define mc68020
+# endif
+#endif
+
+#if defined(mc68020) || defined(mc68000)
+
+#if (defined(mc68020) || defined(NeXT)) && !defined(UNALIGNED_OK)
+# define UNALIGNED_OK
+#endif
+
+#ifdef sysV68 /* Try Motorola Delta style */
+
+# define GLOBAL(symbol) global symbol
+# define TEXT text
+# define FILE(filename) file filename
+# define invert_maybe(src,dst) dst,src
+# define imm(data) &data
+# define reg(register) %register
+
+# define addl add.l
+# define addql addq.l
+# define blos blo.b
+# define bhis bhi.b
+# define bras bra.b
+# define clrl clr.l
+# define cmpmb cmpm.b
+# define cmpw cmp.w
+# define cmpl cmp.l
+# define lslw lsl.w
+# define lsrl lsr.l
+# define movel move.l
+# define movew move.w
+# define moveb move.b
+# define moveml movem.l
+# define subl sub.l
+# define subw sub.w
+# define subql subq.l
+
+# define IndBase(bd,An) (bd,An)
+# define IndBaseNdxl(bd,An,Xn) (bd,An,Xn.l)
+# define IndBaseNdxw(bd,An,Xn) (bd,An,Xn.w)
+# define predec(An) -(An)
+# define postinc(An) (An)+
+
+#else /* default style (Sun 3, NeXT, Amiga, Atari) */
+
+# define GLOBAL(symbol) .globl symbol
+# define TEXT .text
+# define FILE(filename) .even
+# define invert_maybe(src,dst) src,dst
+# if defined(sun) || defined(mc68k)
+# define imm(data) #data
+# else
+# define imm(data) \#data
+# endif
+# define reg(register) register
+
+# define blos bcss
+# if defined(sun) || defined(mc68k)
+# define movel movl
+# define movew movw
+# define moveb movb
+# endif
+# define IndBase(bd,An) An@(bd)
+# define IndBaseNdxl(bd,An,Xn) An@(bd,Xn:l)
+# define IndBaseNdxw(bd,An,Xn) An@(bd,Xn:w)
+# define predec(An) An@-
+# define postinc(An) An@+
+
+#endif /* styles */
+
+#define Best_Len reg(d0) /* unsigned */
+#define Cur_Match reg(d1) /* Ipos */
+#define Loop_Counter reg(d2) /* int */
+#define Scan_Start reg(d3) /* unsigned short */
+#define Scan_End reg(d4) /* unsigned short */
+#define Limit reg(d5) /* IPos */
+#define Chain_Length reg(d6) /* unsigned */
+#define Scan_Test reg(d7)
+#define Scan reg(a0) /* *uch */
+#define Match reg(a1) /* *uch */
+#define Prev_Address reg(a2) /* *Pos */
+#define Scan_Ini reg(a3) /* *uch */
+#define Match_Ini reg(a4) /* *uch */
+#define Stack_Pointer reg(sp)
+
+ GLOBAL (_match_init)
+ GLOBAL (_longest_match)
+
+ TEXT
+
+ FILE ("match.S")
+
+_match_init:
+ rts
+
+/*-----------------------------------------------------------------------
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ */
+
+/* int longest_match (cur_match) */
+
+#ifdef UNALIGNED_OK
+# define pushreg 15928 /* d2-d6/a2-a4 */
+# define popreg 7292
+#else
+# define pushreg 16184 /* d2-d7/a2-a4 */
+# define popreg 7420
+#endif
+
+_longest_match:
+ movel IndBase(4,Stack_Pointer),Cur_Match
+ moveml imm(pushreg),predec(Stack_Pointer)
+ movel _max_chain_length,Chain_Length
+ movel _prev_length,Best_Len
+ movel imm(_prev),Prev_Address
+ movel imm(_window+MIN_MATCH),Match_Ini
+ movel _strstart,Limit
+ movel Match_Ini,Scan_Ini
+ addl Limit,Scan_Ini
+ subw imm(MAX_DIST),Limit
+ bhis L__limit_ok
+ clrl Limit
+L__limit_ok:
+ cmpl invert_maybe(_good_match,Best_Len)
+ blos L__length_ok
+ lsrl imm(2),Chain_Length
+L__length_ok:
+ subql imm(1),Chain_Length
+#ifdef UNALIGNED_OK
+ movew IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+ movew IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+ moveb IndBase(-MIN_MATCH,Scan_Ini),Scan_Start
+ lslw imm(8),Scan_Start
+ moveb IndBase(-MIN_MATCH+1,Scan_Ini),Scan_Start
+ moveb IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+ lslw imm(8),Scan_End
+ moveb IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+ bras L__do_scan
+
+L__long_loop:
+#ifdef UNALIGNED_OK
+ movew IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+#else
+ moveb IndBaseNdxw(-MIN_MATCH-1,Scan_Ini,Best_Len),Scan_End
+ lslw imm(8),Scan_End
+ moveb IndBaseNdxw(-MIN_MATCH,Scan_Ini,Best_Len),Scan_End
+#endif
+
+L__short_loop:
+ lslw imm(1),Cur_Match
+ movew IndBaseNdxl(0,Prev_Address,Cur_Match),Cur_Match
+ cmpw invert_maybe(Limit,Cur_Match)
+ dbls Chain_Length,L__do_scan
+ bras L__return
+
+L__do_scan:
+ movel Match_Ini,Match
+ addl Cur_Match,Match
+#ifdef UNALIGNED_OK
+ cmpw invert_maybe(IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_End)
+ bne L__short_loop
+ cmpw invert_maybe(IndBase(-MIN_MATCH,Match),Scan_Start)
+ bne L__short_loop
+#else
+ moveb IndBaseNdxw(-MIN_MATCH-1,Match,Best_Len),Scan_Test
+ lslw imm(8),Scan_Test
+ moveb IndBaseNdxw(-MIN_MATCH,Match,Best_Len),Scan_Test
+ cmpw invert_maybe(Scan_Test,Scan_End)
+ bne L__short_loop
+ moveb IndBase(-MIN_MATCH,Match),Scan_Test
+ lslw imm(8),Scan_Test
+ moveb IndBase(-MIN_MATCH+1,Match),Scan_Test
+ cmpw invert_maybe(Scan_Test,Scan_Start)
+ bne L__short_loop
+#endif
+
+ movew imm((MAX_MATCH-MIN_MATCH+1)-1),Loop_Counter
+ movel Scan_Ini,Scan
+L__scan_loop:
+ cmpmb postinc(Match),postinc(Scan)
+ dbne Loop_Counter,L__scan_loop
+
+ subl Scan_Ini,Scan
+ addql imm(MIN_MATCH-1),Scan
+ cmpl invert_maybe(Best_Len,Scan)
+ bls L__short_loop
+ movel Scan,Best_Len
+ movel Cur_Match,_match_start
+#ifdef FULL_SEARCH
+ cmpl invert_maybe(imm(MAX_MATCH),Best_Len)
+#else
+ cmpl invert_maybe(_nice_match,Best_Len)
+#endif
+ blos L__long_loop
+L__return:
+ moveml postinc(Stack_Pointer),imm(popreg)
+ rts
+
+#else
+ error: this asm version is for 386 or 680x0 only
+#endif /* mc68000 || mc68020 */
+#endif /* i386 || _I386 || _i386 || __i386 */
+
+#endif /* !USE_ZLIB */
diff --git a/msdos/README.DOS b/msdos/README.DOS
new file mode 100644
index 0000000..0b9a57b
--- /dev/null
+++ b/msdos/README.DOS
@@ -0,0 +1,132 @@
+README.DOS
+
+Some notes about the supplied MSDOS executables and their compilers:
+
+A) The 32-bit DOS executables "zip.exe" and the auxilary utilities
+ "zipnote.exe", "zipsplit.exe", "zipcloak.exe" (crypt-enabled distribution
+ only) were compiled with DJGPP v 2.03, using gcc 2.95.3 as compiler.
+ They require a DPMI server to run, e.g.: a DOS command prompt window
+ under WINDOWS 3.x or Windows 9x. To use this program under plain DOS,
+ you should install the free (GPL'ed) DPMI server CWSDPMI.EXE. Look
+ for "csdpmi5b.zip" under "simtelnet/gnu/djgpp/v2misc/" on the SimTelNet
+ home site "ftp.cdrom.com" or any mirror site of the SimtelNet archive.
+
+ We have decided to provide 32-bit rather than 16-bit executables of
+ the auxilary tools for the following reasons:
+ - Nowadays, it has become quite unlikely to find PC computers "in action"
+ that do not at least have an i386 CPU.
+ - the 32-bit versions do not impose additional archive handling limits
+ beyond those defined by the Zip archive format
+ - the 32-bit DJGPP executables can handle long filenames on systems running
+ Windows 95/98/Me and Windows 2K/XP.
+
+B) There are two 16-bit MSDOS executables provided in zcr2?x.zip:
+ zip16.exe regular Zip program, requires ca. 455 KBytes of contiguous
+ free DOS memory or more.
+ zip16-sm.exe a variant that was compiled with the SMALL_MEM option
+ for minimal memory consumption; requires at minimum
+ 322 KBytes of contiguous free DOS memory.
+
+ The SMALL_MEM variant requires much less space for the compression
+ buffers, but at the cost of some compression efficiency.
+ Therefore, we recommend to use the "SMALL_MEM" 16-bit "zip16-sm.exe" only
+ in case of "out of memory" problems (DOS memory is low and/or very large
+ number of archive entries), when the 32-bit program cannot be used for
+ some reason (286 or older; no DPMI server; ...).
+
+C) Hard limits of the Zip archive format:
+ Number of entries in Zip archive: 64 k (2^16 - 1 entries)
+ Compressed size of archive entry: 4 GByte (2^32 - 1 Bytes)
+ Uncompressed size of entry: 4 GByte (2^32 - 1 Bytes)
+ Size of single-volume Zip archive: 4 GByte (2^32 - 1 Bytes)
+ Per-volume size of multi-volume archives: 4 GByte (2^32 - 1 Bytes)
+ Number of parts for multi-volume archives: 64 k (1^16 - 1 parts)
+ Total size of multi-volume archive: 256 TByte (4G * 64k)
+
+ The number of archive entries and of multivolume parts are limited by
+ the structure of the "end-of-central-directory" record, where the these
+ numbers are stored in 2-Byte fields.
+ Some Zip and/or UnZip implementations (for example Info-ZIP's) allow
+ handling of archives with more than 64k entries. (The information
+ from "number of entries" field in the "end-of-central-directory" record
+ is not really neccessary to retrieve the contents of a Zip archive;
+ it should rather be used for consistency checks.)
+
+ Length of an archive entry name: 64 kByte (2^16 - 1)
+ Length of archive member comment: 64 kByte (2^16 - 1)
+ Total length of "extra field": 64 kByte (2^16 - 1)
+ Length of a single e.f. block: 64 kByte (2^16 - 1)
+ Length of archive comment: 64 KByte (2^16 - 1)
+
+ Additional limitation claimed by PKWARE:
+ Size of local-header structure (fixed fields of 30 Bytes + filename
+ local extra field): < 64 kByte
+ Size of central-directory structure (46 Bytes + filename +
+ central extra field + member comment): < 64 kByte
+
+D) Implementation limits of the Zip executables:
+
+ 1. Size limits caused by file I/O and compression handling:
+ Size of Zip archive: 2 GByte (2^31 - 1 Bytes)
+ Compressed size of archive entry: 2 GByte (2^31 - 1 Bytes)
+ Uncompressed size of entry: 2 GByte (2^31 - 1 Bytes),
+ (could/should be 4 GBytes...)
+ Multi-volume archive creation is not supported.
+
+ 2. Limits caused by handling of archive contents lists
+
+ 2.1. Number of archive entries (freshen, update, delete)
+ a) 16-bit executable: 64k (2^16 -1) or 32k (2^15 - 1),
+ (unsigned vs. signed type of size_t)
+ a1) 16-bit executable: <16k ((2^16)/4)
+ (The smaller limit a1) results from the array size limit of
+ the "qsort()" function.)
+ 32-bit executables <1G ((2^32)/4)
+ (usual system limit of the "qsort()" function on 32-bit systems)
+
+ b) stack space needed by qsort to sort list of archive entries
+
+ NOTE: In the current executables, overflows of limits a) and b) are NOT
+ checked!
+
+ c) amount of free memory to hold "central directory information" of
+ all archive entries; one entry needs:
+ 96 bytes (32-bit) resp. 80 bytes (16-bit)
+ + 3 * length of entry name
+ + length of zip entry comment (when present)
+ + length of extra field(s) (when present, e.g.: UT needs 9 bytes)
+ + some bytes for book-keeping of memory allocation
+
+ Conclusion:
+ For systems with limited memory space (MSDOS, small AMIGAs, other
+ environments without virtual memory), the number of archive entries
+ is most often limited by condition c).
+ For example, with approx. 100 kBytes of free memory after loading and
+ initializing the program, a 16-bit DOS Zip cannot process more than 600
+ to 1000 (+) archive entries. (For the 16-bit Windows DLL or the 16-bit
+ OS/2 port, limit c) is less important because Windows or OS/2 executables
+ are not restricted to the 1024k area of real mode memory. These 16-bit
+ ports are limited by conditions a1) and b), say: at maximum approx.
+ 16000 entries!)
+
+
+ 2.2. Number of "new" entries (add operation)
+ In addition to the restrictions above (2.1.), the following limits
+ caused by the handling of the "new files" list apply:
+
+ a) 16-bit executable: <16k ((2^64)/4)
+
+ b) stack size required for "qsort" operation on "new entries" list.
+
+ NOTE: In the current executables, the overflow checks for these limits
+ are missing!
+
+ c) amount of free memory to hold the directory info list for new entries;
+ one entry needs:
+ 24 bytes (32-bit) resp. 22 bytes (16-bit)
+ + 3 * length of filename
+
+
+Please report any problems to: Zip-Bugs@lists.wku.edu
+
+Last updated: 07 July 2001
diff --git a/msdos/crc_i86.asm b/msdos/crc_i86.asm
new file mode 100644
index 0000000..3ad0349
--- /dev/null
+++ b/msdos/crc_i86.asm
@@ -0,0 +1,497 @@
+;===========================================================================
+; Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; Created by Christian Spieler, last modified 07 Jan 2007.
+;
+ TITLE crc_i86.asm
+ NAME crc_i86
+;
+; Optimized 8086 assembler version of the CRC32 calculation loop, intended
+; for real mode Info-ZIP programs (Zip 2.1, UnZip 5.2, and later versions).
+; Supported compilers are Microsoft C (DOS real mode) and Borland C(++)
+; (Turbo C). Watcom C (16bit) should also work.
+; This module was inspired by a similar module for the Amiga (Paul Kienitz).
+;
+; It replaces the `ulg crc32(ulg crc, ZCONST uch *buf, extent len)' function
+; in crc32.c.
+;
+; In March/April 1997, the code has been revised to incorporate Rodney Brown's
+; ideas for optimized access to the data buffer. For 8086 real mode code,
+; the data buffer is now accessed by aligned word-wide read operations.
+; This new optimization may be turned off by defining the macro switch
+; NO_16_BIT_LOADS.
+;
+; In December 1998, the loop branch commands were changed from "loop dest"
+; into "dec cx; jnz dest". On modern systems (486 and newer), the latter
+; code is usually much faster (e.g. 1 clock cycle compared to 5 for "loop"
+; on Pentium MMX). For the 286, the penalty of "dec cx; jnz" is one clock
+; cycle (12 vs. 11 cycles); on an 8088 the cycle counts are 22 (dec cx; jnz)
+; vs. 18 (loop). I decided to optimize for newer CPU models by default, because
+; I expect that old 80286 or 8088 dinosaurier machines may be rarely used
+; nowadays. In case you want optimum performance for these old CPU models
+; you should define the OPTIMIZE_286_88 macro switch on the assembler's
+; command line.
+; Likewise, "jcxz" was replaced by "jz", because the latter is faster on
+; 486 and newer CPUs (without any penalty on 80286 and older CPU models).
+;
+; In January 2007, the "hand-made" memory model setup section has been guarded
+; against redefinition of @CodeSize and @DataSize symbols, to work around a
+; problem with current Open Watcom (version 1.6) wasm assembler.
+;
+; The code in this module should work with all kinds of C memory models
+; (except Borland's __HUGE__ model), as long as the following
+; restrictions are not violated:
+;
+; - The implementation assumes that the char buffer is confined to a
+; 64k segment. The pointer `s' to the buffer must be in a format that
+; all bytes can be accessed by manipulating the offset part, only.
+; This means:
+; + no huge pointers
+; + char buffer size < 64 kByte
+;
+; - Since the buffer size argument `n' is of type `size_t' (= unsigned short)
+; for this routine, the char buffer size is limited to less than 64 kByte,
+; anyway. So, the assumption above should be easily fulfilled.
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used,
+; or only the precomputed CRC_32_Table is needed.
+;
+ifndef USE_ZLIB
+ifndef CRC_TABLE_ONLY
+;
+; Setup of amount of assemble time informational messages:
+;
+ifdef DEBUG
+ VERBOSE_INFO EQU 1
+else
+ ifdef _AS_MSG_
+ VERBOSE_INFO EQU 1
+ else
+ VERBOSE_INFO EQU 0
+ endif
+endif
+;
+; Selection of memory model, and initialization of memory model
+; related macros:
+;
+ifndef __SMALL__
+ ifndef __COMPACT__
+ ifndef __MEDIUM__
+ ifndef __LARGE__
+ ifndef __HUGE__
+; __SMALL__ EQU 1
+ endif
+ endif
+ endif
+ endif
+endif
+
+ifdef __HUGE__
+; .MODEL Huge
+ ifndef @CodeSize
+ @CodeSize EQU 1
+ endif
+ ifndef @DataSize
+ @DataSize EQU 1
+ endif
+ Save_DS EQU 1
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Huge memory model
+ endif
+ endif
+else
+ ifdef __LARGE__
+; .MODEL Large
+ ifndef @CodeSize
+ @CodeSize EQU 1
+ endif
+ ifndef @DataSize
+ @DataSize EQU 1
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Large memory model
+ endif
+ endif
+ else
+ ifdef __COMPACT__
+; .MODEL Compact
+ ifndef @CodeSize
+ @CodeSize EQU 0
+ endif
+ ifndef @DataSize
+ @DataSize EQU 1
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Compact memory model
+ endif
+ endif
+ else
+ ifdef __MEDIUM__
+; .MODEL Medium
+ ifndef @CodeSize
+ @CodeSize EQU 1
+ endif
+ ifndef @DataSize
+ @DataSize EQU 0
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Medium memory model
+ endif
+ endif
+ else
+; .MODEL Small
+ ifndef @CodeSize
+ @CodeSize EQU 0
+ endif
+ ifndef @DataSize
+ @DataSize EQU 0
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Small memory model
+ endif
+ endif
+ endif
+ endif
+ endif
+endif
+
+if @CodeSize
+ LCOD_OFS EQU 2
+else
+ LCOD_OFS EQU 0
+endif
+
+IF @DataSize
+ LDAT_OFS EQU 2
+else
+ LDAT_OFS EQU 0
+endif
+
+ifdef Save_DS
+; (di,si,ds)+(size, return address)
+ SAVE_REGS EQU 6+(4+LCOD_OFS)
+else
+; (di,si)+(size, return address)
+ SAVE_REGS EQU 4+(4+LCOD_OFS)
+endif
+
+;
+; Selection of the supported CPU instruction set and initialization
+; of CPU type related macros:
+;
+ifdef __686
+ Use_286_code EQU 1
+ Align_Size EQU 4 ; dword alignment on Pentium II/III/IV
+ Alig_PARA EQU 1 ; paragraph aligned code segment
+else
+ifdef __586
+ Use_286_code EQU 1
+ Align_Size EQU 4 ; dword alignment on Pentium
+ Alig_PARA EQU 1 ; paragraph aligned code segment
+else
+ifdef __486
+ Use_286_code EQU 1
+ Align_Size EQU 4 ; dword alignment on 32 bit processors
+ Alig_PARA EQU 1 ; paragraph aligned code segment
+else
+ifdef __386
+ Use_286_code EQU 1
+ Align_Size EQU 4 ; dword alignment on 32 bit processors
+ Alig_PARA EQU 1 ; paragraph aligned code segment
+else
+ifdef __286
+ Use_286_code EQU 1
+ Align_Size EQU 2 ; word alignment on 16 bit processors
+ Alig_PARA EQU 0 ; word aligned code segment
+else
+ifdef __186
+ Use_186_code EQU 1
+ Align_Size EQU 2 ; word alignment on 16 bit processors
+ Alig_PARA EQU 0 ; word aligned code segment
+else
+ Align_Size EQU 2 ; word alignment on 16 bit processors
+ Alig_PARA EQU 0 ; word aligned code segment
+endif ;?__186
+endif ;?__286
+endif ;?__386
+endif ;?__486
+endif ;?__586
+endif ;?__686
+
+ifdef Use_286_code
+ .286
+ Have_80x86 EQU 1
+else
+ifdef Use_186_code
+ .186
+ Have_80x86 EQU 1
+else
+ .8086
+ Have_80x86 EQU 0
+endif ;?Use_186_code
+endif ;?Use_286_code
+
+;
+; Declare the segments used in this module:
+;
+if @CodeSize
+if Alig_PARA
+CRC32_TEXT SEGMENT PARA PUBLIC 'CODE'
+else
+CRC32_TEXT SEGMENT WORD PUBLIC 'CODE'
+endif
+CRC32_TEXT ENDS
+else ;!@CodeSize
+if Alig_PARA
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+else
+_TEXT SEGMENT WORD PUBLIC 'CODE'
+endif
+_TEXT ENDS
+endif ;?@CodeSize
+_DATA SEGMENT WORD PUBLIC 'DATA'
+_DATA ENDS
+_BSS SEGMENT WORD PUBLIC 'BSS'
+_BSS ENDS
+DGROUP GROUP _BSS, _DATA
+if @DataSize
+ ASSUME DS: nothing, SS: DGROUP
+else
+ ASSUME DS: DGROUP, SS: DGROUP
+endif
+
+if @CodeSize
+EXTRN _get_crc_table:FAR
+else
+EXTRN _get_crc_table:NEAR
+endif
+
+
+Do_CRC MACRO
+ mov bl,al
+ sub bh,bh
+if Have_80x86
+ shl bx,2
+else
+ shl bx,1
+ shl bx,1
+endif
+ mov al,ah
+ mov ah,dl
+ mov dl,dh
+ sub dh,dh
+ xor ax,WORD PTR [bx][si]
+ xor dx,WORD PTR [bx+2][si]
+ ENDM
+;
+Do_1 MACRO
+if @DataSize
+ xor al,BYTE PTR es:[di]
+else
+ xor al,BYTE PTR [di]
+endif
+ inc di
+ Do_CRC
+ ENDM
+;
+Do_2 MACRO
+ifndef NO_16_BIT_LOADS
+if @DataSize
+ xor ax,WORD PTR es:[di]
+else
+ xor ax,WORD PTR [di]
+endif
+ add di,2
+ Do_CRC
+ Do_CRC
+else
+ Do_1
+ Do_1
+endif
+ ENDM
+;
+Do_4 MACRO
+ Do_2
+ Do_2
+ ENDM
+;
+
+IF @CodeSize
+CRC32_TEXT SEGMENT
+ ASSUME CS: CRC32_TEXT
+else
+_TEXT SEGMENT
+ ASSUME CS: _TEXT
+endif
+; Line 37
+
+;
+;ulg crc32(ulg crc,
+; ZCONST uch *buf,
+; extent len)
+;
+ PUBLIC _crc32
+if @CodeSize
+_crc32 PROC FAR
+else
+_crc32 PROC NEAR
+endif
+if Have_80x86
+ enter WORD PTR 0,0
+else
+ push bp
+ mov bp,sp
+endif
+ push di
+ push si
+if @DataSize
+; crc = 4+LCOD_OFS DWORD (unsigned long)
+; buf = 8+LCOD_OFS DWORD PTR BYTE (uch *)
+; len = 12+LCOD_OFS WORD (unsigned int)
+else
+; crc = 4+LCOD_OFS DWORD (unsigned long)
+; buf = 8+LCOD_OFS WORD PTR BYTE (uch *)
+; len = 10+LCOD_OFS WORD (unsigned int)
+endif
+;
+if @DataSize
+ mov ax,WORD PTR [bp+8+LCOD_OFS] ; buf
+ or ax,WORD PTR [bp+10+LCOD_OFS] ; == NULL ?
+else
+ cmp WORD PTR [bp+8+LCOD_OFS],0 ; buf == NULL ?
+endif
+ jne crc_update
+ sub ax,ax ; crc = 0
+ cwd
+ifndef NO_UNROLLED_LOOPS
+ jmp fine
+else
+ jmp SHORT fine
+endif
+;
+crc_update:
+ call _get_crc_table
+; When used with compilers that conform to the Microsoft/Borland standard
+; C calling convention, model-dependent handling is not needed, because
+; _get_crc_table returns NEAR pointer.
+; But Watcom C is different and does not allow one to assume DS pointing to
+; DGROUP. So, we load DS with DGROUP, to be safe.
+;if @DataSize
+; push ds
+; mov ds,dx
+; ASSUME DS: nothing
+;endif
+ mov si,ax ;crc_table
+if @DataSize
+ push ds
+ mov ax,SEG DGROUP
+ mov ds,ax
+ ASSUME DS: DGROUP
+endif
+;
+ mov ax,WORD PTR [bp+4+LCOD_OFS] ;crc
+ mov dx,WORD PTR [bp+6+LCOD_OFS]
+ not ax
+ not dx
+if @DataSize
+ les di,DWORD PTR [bp+8+LCOD_OFS] ;buf
+ mov cx,WORD PTR [bp+12+LCOD_OFS] ;len
+else
+ mov di,WORD PTR [bp+8+LCOD_OFS] ;buf
+ mov cx,WORD PTR [bp+10+LCOD_OFS] ;len
+endif
+;
+ifndef NO_UNROLLED_LOOPS
+ifndef NO_16_BIT_LOADS
+ test cx,cx
+ jnz start
+ jmp done
+start: test di,1
+ jz is_wordaligned
+ dec cx
+ Do_1
+ mov WORD PTR [bp+10+LDAT_OFS+LCOD_OFS],cx
+is_wordaligned:
+endif ; !NO_16_BIT_LOADS
+if Have_80x86
+ shr cx,2
+else
+ shr cx,1
+ shr cx,1
+endif
+ jz No_Fours
+;
+ align Align_Size ; align destination of branch
+Next_Four:
+ Do_4
+ifndef OPTIMIZE_286_88
+ dec cx ; on 286, "loop Next_Four" needs 11
+ jnz Next_Four ; clocks, one less than this code
+else
+ loop Next_Four
+endif
+;
+No_Fours:
+if @DataSize
+ mov cx,WORD PTR [bp+12+LCOD_OFS] ;len
+else
+ mov cx,WORD PTR [bp+10+LCOD_OFS] ;len
+endif
+ and cx,00003H
+endif ; !NO_UNROLLED_LOOPS
+ jz done
+;
+ align Align_Size ; align destination of branch
+Next_Byte:
+ Do_1
+ifndef OPTIMIZE_286_88
+ dec cx ; on 286, "loop Next_Four" needs 11
+ jnz Next_Byte ; clocks, one less than this code
+else
+ loop Next_Four
+endif
+;
+done:
+if @DataSize
+ pop ds
+; ASSUME DS: DGROUP
+ ASSUME DS: nothing
+endif
+ not ax
+ not dx
+;
+fine:
+ pop si
+ pop di
+if Have_80x86
+ leave
+else
+ mov sp,bp
+ pop bp
+endif
+ ret
+
+_crc32 ENDP
+
+if @CodeSize
+CRC32_TEXT ENDS
+else
+_TEXT ENDS
+endif
+;
+endif ;!CRC_TABLE_ONLY
+endif ;!USE_ZLIB
+;
+END
diff --git a/msdos/makebz2.dj2 b/msdos/makebz2.dj2
new file mode 100644
index 0000000..161f1e3
--- /dev/null
+++ b/msdos/makebz2.dj2
@@ -0,0 +1,148 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# djgpp 2.x
+#
+# This simple modified version of makefile.dj2 adds bzip2 support
+# to Zip for djgpp 2.x and was donated by Robert Riebisch.
+#
+# Given standard djgpp 2.x and bzip2 installations, this should create a
+# version of Zip 3.0 with bzip2 support. Additional information is in
+# bzip2/install.txt.
+#
+# 27 June 2008
+
+VPATH=.;msdos
+# ------------- djgpp -------------
+CPPFLAGS=-I. -DDOS -DASM_CRC -DBZIP2_SUPPORT $(LOCAL_ZIP)
+ASFLAGS=$(CPPFLAGS)
+CFLAGS=-Wall -O2 $(CPPFLAGS)
+UTILFLAGS=-c -DUTIL $(CFLAGS) -o
+CC=gcc
+LD=gcc
+LDFLAGS=-s
+
+# ------------- file packer --------
+# Laszlo Molnar who wrote DJ Packer and Markus F. X. J. Oberhumer who wrote
+# the compression library used by the DJ Packer have collaborated on the
+# Ultimate Packer for eXecutables, which has recently been released. Look
+# for upx???d.zip at http://upx.sourceforge.net
+# As an alternative, look for "djp.exe", now two years old, in the archive
+# mlp107[b,s].zip, found in the same location as csdpmi?[b,s].zip (see below).
+# If you have got an executable packer in your PATH, you may reduce the
+# size of the disk image of the zip*.exe's by uncommenting the lines
+# containing $(DJP) below where the exe's are built.
+#DJP=djp -q
+DJP=upx -qq --best
+
+# variables
+
+#set CRC32 to crc_gcc.o or nothing, depending on whether ASM_CRC is defined:
+CRCA_O = crc_gcc.o
+
+OBJZ = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+ crc32.o $(CRCA_O) globals.o
+OBJI = deflate.o trees.o match.o msdos.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o msdos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o crc32_.o crypt_.o ttyio.o $(OBJU)
+OBJS = zipsplit.o $(OBJU)
+LIBS = -lbz2
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+# rules
+
+.SUFFIXES: # Delete make's default suffix list
+.SUFFIXES: .exe .out .a .ln .o .c .cc .C .p .f .F .y .l .s .S .h
+
+.c.o:
+ $(CC) -c $(CFLAGS) $< -o $@
+
+zips: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.o: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipfile.o: zipfile.c $(ZIP_H) crc32.h
+
+zipup.o: zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+
+fileio.o: fileio.c $(ZIP_H) crc32.h
+
+util.o: util.c $(ZIP_H)
+
+globals.o: globals.c $(ZIP_H)
+
+deflate.o: deflate.c $(ZIP_H)
+
+trees.o: trees.c $(ZIP_H)
+
+crc_gcc.o: crc_i386.S
+ $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+crc32.o: crc32.c $(ZIP_H) crc32.h
+
+crypt.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+
+ttyio.o: ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos.o: msdos/msdos.c $(ZIP_H)
+
+zipcloak.o: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipnote.o: zipnote.c $(ZIP_H) revision.h
+
+zipsplit.o: zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o: zipfile.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ zipfile.c
+
+fileio_.o: fileio.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ fileio.c
+
+util_.o: util.c $(ZIP_H)
+ $(CC) $(UTILFLAGS) $@ util.c
+
+crc32_.o: crc32.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ crc32.c
+
+crypt_.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) $(UTILFLAGS) $@ crypt.c
+
+msdos_.o: msdos/msdos.c $(ZIP_H)
+ $(CC) $(UTILFLAGS) $@ msdos/msdos.c
+
+
+match.o: match.S
+ $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zip.exe: $(OBJZ) $(OBJI)
+ echo $(OBJZ) > zip.rsp
+ echo $(OBJI) >> zip.rsp
+ echo $(LIBS) >> zip.rsp
+ $(LD) $(LDFLAGS) -o $@ @zip.rsp
+ del zip.rsp
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC) -o $@
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN) -o $@
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) -o $@
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+# These stand alone executables require dpmi services to run. When
+# running in a DOS window under windows 3.1 or later, the dpmi server
+# is automatically present. Under DOS, if a dpmi server is not installed,
+# by default the program will look for "cwsdpmi.exe." If found, it will
+# be loaded for the duration of the program.
+# cwsdpmi is a "free" dpmi server written by Charles W. Sandmann
+# (sandman@clio.rice.edu). It may be found, among other sites, on SimTel
+# and its mirrors in the .../vendors/djgpp/v2misc directory.
diff --git a/msdos/makefile.bor b/msdos/makefile.bor
new file mode 100644
index 0000000..88ecde4
--- /dev/null
+++ b/msdos/makefile.bor
@@ -0,0 +1,197 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Borland (Turbo) C++ 1.0 or 2.0.
+# Warning: this file is not suitable for Turbo C 2.0. Use makefile.tc instead.
+
+# To use, do "make -fmakefile.bor"
+
+# WARNING: the small model is not supported.
+# Add -DSMALL_MEM or -DMEDIUM_MEM to the LOC macro if you wish to reduce
+# the memory requirements.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have tasm.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = -DDOS -DNO_SECURE_TESTS $(LOCAL_ZIP)
+
+# Zip requires compact or large memory model.
+# with 2.1, compact model exceeds 64k code segment; use large model
+ZIPMODEL=l # large model for Zip and ZipUtils
+
+# name of Flag to select memory model for assembler compiles, supported
+# values are __SMALL__ , __MEDIUM__ , __COMPACT__ , __LARGE__ :
+ASMODEL=__LARGE__ # keep in sync with ZIPMODEL definition !!
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+CRCA_O = crc_i86.obj
+ASMOBJS = match.obj $(CRCA_O)
+
+ASCPUFLAG = __$(CPU_TYP)86
+!if $(CPU_TYP) != 0
+CC_CPUFLG = -$(CPU_TYP)
+!endif
+
+VPATH=.;msdos
+# ------------- Turbo C++, Borland C++ -------------
+!if $(CC_REV) == 1
+CC = tcc
+!else
+! if !$(CC_REV)
+CC_REV = 3
+! endif
+CC = bcc
+!endif
+
+MODEL=-m$(ZIPMODEL)
+!if $(CC_REV) == 1
+CFLAGS=-w -w-eff -w-def -w-sig -w-cln -a -d -G -O -Z $(CC_CPUFLG) $(MODEL) $(LOC)
+!else
+CFLAGS=-w -w-cln -O2 -Z $(CC_CPUFLG) $(MODEL) $(LOC)
+!endif
+UTILFLAGS=-DUTIL $(CFLAGS) -o
+# for Turbo C++ 1.0, replace bcc with tcc and use the upper version of CFLAGS
+
+AS=tasm
+ASFLAGS=-ml -t -m2 -DDYN_ALLOC -DSS_NEQ_DS -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+
+LD=$(CC)
+LDFLAGS=$(MODEL)
+
+# ------------- Common declarations:
+STRIP=@rem
+# If you don't have UPX, LZEXE, or PKLITE, get one of them. Then define:
+# (NOTE: upx needs a 386 or higher system to run the exe compressor)
+#STRIP=upx --8086 --best
+# or
+#STRIP=lzexe
+# or (if you've registered PKLITE)
+#STRIP=pklite
+# This makes a big difference in .exe size (and possibly load time)
+
+# ------------- Used by install rule
+# set BIN to the directory you want to install the executables to
+BIN = c:\util
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) msdos.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj msdos_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+msdos.obj: msdos/msdos.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) msdos/$*.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$* util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS)$* crypt.c
+
+msdos_.obj: msdos/msdos.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$* msdos/msdos.c
+
+crc_i86.obj: msdos/crc_i86.asm
+ $(AS) $(ASFLAGS) msdos\crc_i86.asm ;
+
+match.obj: msdos/match.asm
+ $(AS) $(ASFLAGS) msdos\match.asm ;
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zip.exe: $(OBJZ) $(OBJI)
+ echo $(OBJZ) > zip.rsp
+ echo $(OBJI) >> zip.rsp
+ $(LD) $(LDFLAGS) @zip.rsp
+ del zip.rsp
+ $(STRIP) zip.exe
+
+zipcloak.exe: $(OBJC)
+ echo $(OBJC) > zipc.rsp
+ $(LD) $(LDFLAGS) @zipc.rsp
+ del zipc.rsp
+ $(STRIP) zipcloak.exe
+
+zipnote.exe: $(OBJN)
+ echo $(OBJN) > zipn.rsp
+ $(LD) $(LDFLAGS) @zipn.rsp
+ del zipn.rsp
+ $(STRIP) zipnote.exe
+
+zipsplit.exe: $(OBJS)
+ echo $(OBJS) > zips.rsp
+ $(LD) $(LDFLAGS) @zips.rsp
+ del zips.rsp
+ $(STRIP) zipsplit.exe
+
+install: $(ZIPS)
+ copy /b *.exe $(BIN)
+
+clean:
+ del *.obj
+ del *.exe
diff --git a/msdos/makefile.dj1 b/msdos/makefile.dj1
new file mode 100644
index 0000000..05137cc
--- /dev/null
+++ b/msdos/makefile.dj1
@@ -0,0 +1,126 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# djgpp 1.x
+VPATH=.;msdos
+# ------------- djgpp -------------
+CPPFLAGS=-I. -DDOS -DASM_CRC $(LOCAL_ZIP)
+ASFLAGS=$(CPPFLAGS)
+CFLAGS=-Wall -O2 -m486 $(CPPFLAGS)
+UTILFLAGS=-c -DUTIL $(CFLAGS) -o
+CC=gcc
+LD=gcc
+LDFLAGS=-s
+
+STRIP=strip
+
+# Change the STUBIFY definition to the upper version if you want to create
+# executables which can be used without any external extender file.
+# >>> NOTE: Either copy the go32 extender into your build directory, or
+# >>> edit the STUBIFY macro and add the correct path to "go32.exe".
+#STUBIFY=coff2exe -s go32.exe
+STUBIFY=coff2exe
+
+# variables
+
+#set CRCA_O to crc_gcc.o or nothing, depending on whether ASM_CRC is defined:
+CRCA_O = crc_gcc.o
+
+OBJZ = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+ crc32.o $(CRCA_O) globals.o
+OBJI = deflate.o trees.o match.o msdos.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o msdos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o crc32_.o crypt_.o ttyio.o $(OBJU)
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+# rules
+
+.SUFFIXES: # Delete make's default suffix list
+.SUFFIXES: .exe .out .a .ln .o .c .cc .C .p .f .F .y .l .s .S .h
+
+.c.o:
+ $(CC) -c $(CFLAGS) $< -o $@
+
+zips: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.o: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipfile.o: zipfile.c $(ZIP_H) crc32.h
+
+zipup.o: zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+
+fileio.o: fileio.c $(ZIP_H)
+
+util.o: util.c $(ZIP_H)
+
+globals.o: globals.c $(ZIP_H)
+
+deflate.o: deflate.c $(ZIP_H)
+
+trees.o: trees.c $(ZIP_H)
+
+crc_gcc.o: crc_i386.S
+ $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+crc32.o: crc32.c $(ZIP_H) crc32.h
+
+crypt.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+
+ttyio.o: ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos.o: msdos/msdos.c $(ZIP_H)
+
+zipcloak.o: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipnote.o: zipnote.c $(ZIP_H) revision.h
+
+zipsplit.o: zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o: zipfile.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ zipfile.c
+
+fileio_.o: fileio.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ fileio.c
+
+util_.o: util.c $(ZIP_H)
+ $(CC) $(UTILFLAGS) $@ util.c
+
+crc32_.o: crc32.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ crc32.c
+
+crypt_.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) $(UTILFLAGS) $@ crypt.c
+
+msdos_.o: msdos/msdos.c $(ZIP_H)
+ $(CC) $(UTILFLAGS) $@ msdos/msdos.c
+
+match.o: match.S
+ $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zip.exe: $(OBJZ) $(OBJI)
+ echo $(OBJZ) > zip.rsp
+ echo $(OBJI) >> zip.rsp
+ $(LD) $(LDFLAGS) -o zip @zip.rsp
+ del zip.rsp
+ $(STRIP) zip
+ $(STUBIFY) zip
+ del zip
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC) -o zipcloak
+ $(STRIP) zipcloak
+ $(STUBIFY) zipcloak
+ del zipcloak
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN) -o zipnote
+ $(STRIP) zipnote
+ $(STUBIFY) zipnote
+ del zipnote
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) -o zipsplit
+ $(STRIP) zipsplit
+ $(STUBIFY) zipsplit
+ del zipsplit
diff --git a/msdos/makefile.dj2 b/msdos/makefile.dj2
new file mode 100644
index 0000000..39192ee
--- /dev/null
+++ b/msdos/makefile.dj2
@@ -0,0 +1,136 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# djgpp 2.x
+VPATH=.;msdos
+# ------------- djgpp -------------
+CPPFLAGS=-I. -DDOS -DASM_CRC $(LOCAL_ZIP)
+ASFLAGS=$(CPPFLAGS)
+CFLAGS=-Wall -O2 $(CPPFLAGS)
+UTILFLAGS=-c -DUTIL $(CFLAGS) -o
+CC=gcc
+LD=gcc
+LDFLAGS=-s
+
+# ------------- file packer --------
+# Laszlo Molnar who wrote DJ Packer and Markus F. X. J. Oberhumer who wrote
+# the compression library used by the DJ Packer have collaborated on the
+# Ultimate Packer for eXecutables, which has recently been released. Look
+# for upx???d.zip at http://upx.sourceforge.net
+# As an alternative, look for "djp.exe", now two years old, in the archive
+# mlp107[b,s].zip, found in the same location as csdpmi?[b,s].zip (see below).
+# If you have got an executable packer in your PATH, you may reduce the
+# size of the disk image of the zip*.exe's by uncommenting the lines
+# containing $(DJP) below where the exe's are built.
+#DJP=djp -q
+DJP=upx -qq --best
+
+# variables
+
+#set CRC32 to crc_gcc.o or nothing, depending on whether ASM_CRC is defined:
+CRCA_O = crc_gcc.o
+
+OBJZ = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+ crc32.o $(CRCA_O) globals.o
+OBJI = deflate.o trees.o match.o msdos.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o msdos_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o crc32_.o crypt_.o ttyio.o $(OBJU)
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+# rules
+
+.SUFFIXES: # Delete make's default suffix list
+.SUFFIXES: .exe .out .a .ln .o .c .cc .C .p .f .F .y .l .s .S .h
+
+.c.o:
+ $(CC) -c $(CFLAGS) $< -o $@
+
+zips: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.o: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipfile.o: zipfile.c $(ZIP_H) crc32.h
+
+zipup.o: zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+
+fileio.o: fileio.c $(ZIP_H) crc32.h
+
+util.o: util.c $(ZIP_H)
+
+globals.o: globals.c $(ZIP_H)
+
+deflate.o: deflate.c $(ZIP_H)
+
+trees.o: trees.c $(ZIP_H)
+
+crc_gcc.o: crc_i386.S
+ $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+crc32.o: crc32.c $(ZIP_H) crc32.h
+
+crypt.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+
+ttyio.o: ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos.o: msdos/msdos.c $(ZIP_H)
+
+zipcloak.o: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+
+zipnote.o: zipnote.c $(ZIP_H) revision.h
+
+zipsplit.o: zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o: zipfile.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ zipfile.c
+
+fileio_.o: fileio.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ fileio.c
+
+util_.o: util.c $(ZIP_H)
+ $(CC) $(UTILFLAGS) $@ util.c
+
+crc32_.o: crc32.c $(ZIP_H) crc32.h
+ $(CC) $(UTILFLAGS) $@ crc32.c
+
+crypt_.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) $(UTILFLAGS) $@ crypt.c
+
+msdos_.o: msdos/msdos.c $(ZIP_H)
+ $(CC) $(UTILFLAGS) $@ msdos/msdos.c
+
+
+match.o: match.S
+ $(CC) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zip.exe: $(OBJZ) $(OBJI)
+ echo $(OBJZ) > zip.rsp
+ echo $(OBJI) >> zip.rsp
+ $(LD) $(LDFLAGS) -o $@ @zip.rsp
+ del zip.rsp
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC) -o $@
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN) -o $@
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS) -o $@
+# stubedit $@ dpmi=cwsdpmi.exe
+# $(DJP) $@
+
+# These stand alone executables require dpmi services to run. When
+# running in a DOS window under windows 3.1 or later, the dpmi server
+# is automatically present. Under DOS, if a dpmi server is not installed,
+# by default the program will look for "cwsdpmi.exe." If found, it will
+# be loaded for the duration of the program.
+# cwsdpmi is a "free" dpmi server written by Charles W. Sandmann
+# (sandman@clio.rice.edu). It may be found, among other sites, on SimTel
+# and its mirrors in the .../vendors/djgpp/v2misc directory.
diff --git a/msdos/makefile.emx b/msdos/makefile.emx
new file mode 100644
index 0000000..3a50b5b
--- /dev/null
+++ b/msdos/makefile.emx
@@ -0,0 +1,169 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+# using emx 0.9c for DOS.
+# By Kai-Uwe Rommel, Chr. Spieler, E-Yen Tan (and others).
+# Last updated 7th January 2007.
+#
+# This Makefile is a stripped down version of win32/Makefile.emx that
+# builds executables applying the default MSDOS emx setup. For variant
+# targets (using zlib), and cross-compilation for WIN32 or OS/2, take a
+# look into "win32/makefile.emx" resp. "os2/makefile.os2".
+#
+# Supported Make utilities:
+# - Microsoft/IBM nmake (e.g. from MSC 6.0 or newer)
+# - dmake 3.8 or higher
+# - GNU make, at least version 3.68 (GNUish 16-bit port, RSXNT Make 3.75 in a
+# Win95/WinNT DOS box, DJGPP v1.12 Make 3.71, some versions of DJGPP v2.x
+# 32-bit Make; current DJGPP v2.01 Make 3.76.1 does NOT work)
+# - NOT watcom make
+# The "smart" Make utilities mentioned below are Christian Spieler's
+# enhanced version of GNUish 16-bit Make (3.74) and his adaption of these
+# GNU Make sources to EMX (32-bit).
+
+# Supported 32-bit C Compilers for MSDOS:
+# - GNU gcc (emx kit 0.9c or newer, 32-bit)
+
+# Supported Assemblers:
+# - GNU as with GNU gcc
+
+
+# To use, enter "make/nmake/dmake -f msdos/makefile.emx"
+# (this makefile depends on its name being "msdos/makefile.emx").
+
+# emx 0.9c, gcc, a.out format, for MS-DOS
+CC=gcc -O2 -m486 -Wall
+CFLAGS=-DDOS -DMSDOS -DASM_CRC
+AS=gcc
+ASFLAGS=-Di386
+LDFLAGS=-o ./
+LDFLAGS2=-s -Zsmall-conv
+OUT=-o
+OBJ=.o
+CRCA_O=crc_gcc.o
+OBJA=matchgcc.o
+OBJZS=msdos.o
+OBJUS=msdos_.o
+OSDEP_H=msdos/osdep.h
+ZIPUP_H=msdos/zipup.h
+
+#default settings for target dependent macros:
+DIRSEP = /
+AS_DIRSEP = /
+RM = del
+LOCAL_OPTS = $(LOCAL_ZIP)
+CCFLAGS = $(CFLAGS) $(LOCAL_OPTS)
+
+
+OBJZ1 = zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+ crc32$(OBJ) $(CRCA_O)
+OBJZ2 = globals$(OBJ) deflate$(OBJ) trees$(OBJ) crypt$(OBJ) \
+ ttyio$(OBJ)
+OBJZ = $(OBJZ1) $(OBJZ2) $(OBJZS) $(OBJA)
+
+OBJU1 = zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) globals$(OBJ)
+OBJU = $(OBJU1) $(OBJUS)
+
+OBJN = zipnote$(OBJ) $(OBJU)
+OBJS = zipsplit$(OBJ) $(OBJU)
+OBJC1 = zipcloak$(OBJ) crc32_$(OBJ) crypt_$(OBJ) ttyio$(OBJ)
+OBJC = $(OBJC1) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+ $(CC) -c -I. $(CCFLAGS) $(OUT)$@ $<
+
+# targets
+
+all: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ): zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ): zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ): zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio$(OBJ): fileio.c $(ZIP_H) crc32.h
+util$(OBJ): util.c $(ZIP_H)
+globals$(OBJ): globals.c $(ZIP_H)
+deflate$(OBJ): deflate.c $(ZIP_H)
+trees$(OBJ): trees.c $(ZIP_H)
+crc32$(OBJ): crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ): ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos$(OBJ): msdos/msdos.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) msdos$(DIRSEP)msdos.c
+
+win32zip$(OBJ): win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32zip.c
+
+win32$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32.c
+
+nt$(OBJ): win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)nt.c
+
+crc_gcc$(OBJ): crc_i386.S # 32bit, GNU AS
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+matchgcc$(OBJ): match.S
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zipcloak$(OBJ): zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote$(OBJ): zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ): zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ zipfile.c
+
+fileio_$(OBJ): fileio.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ fileio.c
+
+util_$(OBJ): util.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ util.c
+
+crc32_$(OBJ): crc32.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crc32.c
+
+crypt_$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crypt.c
+
+msdos_$(OBJ): msdos/msdos.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ msdos$(DIRSEP)msdos.c
+
+win32_$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ win32$(DIRSEP)win32.c
+
+# This next bit is nasty, but is needed to overcome the MS-DOS command
+# line limit as response files for emx's gcc seem to only work if each
+# file is on a different line. DJGPP doesn't do this (if you are at all
+# interested).
+
+zip.exe: $(OBJZ)
+# for DUMB make utilities, uncomment the following commands:
+ -@$(RM) zip.rsp
+ @for %%f in ($(OBJZ1)) do echo %%f >> zip.rsp
+ @for %%f in ($(OBJZ2)) do echo %%f >> zip.rsp
+ @for %%f in ($(OBJZS) $(OBJA)) do echo %%f >> zip.rsp
+ $(CC) $(LDFLAGS)$@ @zip.rsp $(LDFLAGS2)
+ @$(RM) zip.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+# $(CC) $(LDFLAGS)$@ $(OBJZ) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+# for DUMB make utilities, uncomment the following commands:
+ -@$(RM) zipcloak.rsp
+ @for %%f in ($(OBJC1)) do echo %%f >> zipcloak.rsp
+ @for %%f in ($(OBJU1)) do echo %%f >> zipcloak.rsp
+ @for %%f in ($(OBJUS)) do echo %%f >> zipcloak.rsp
+ $(CC) $(LDFLAGS)$@ @zipcloak.rsp $(LDFLAGS2)
+ @$(RM) zipcloak.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+# $(CC) $(LDFLAGS)$@ $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+ $(CC) $(LDFLAGS)$@ $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+ $(CC) $(LDFLAGS)$@ $(OBJS) $(LDFLAGS2)
diff --git a/msdos/makefile.msc b/msdos/makefile.msc
new file mode 100644
index 0000000..a7ec9c9
--- /dev/null
+++ b/msdos/makefile.msc
@@ -0,0 +1,209 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Microsoft C 5.1 and above.
+
+# To use, do "make makefile.msc"
+
+# Add -DSMALL_MEM or -DMEDIUM_MEM to the LOC macro if you wish to reduce
+# the memory requirements.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have masm.
+#
+# If you want link Zip against zlib to replace the built-in deflate routines,
+# the following changes are required:
+# - in the definition of "LOC", add "-DUSE_ZLIB" and remove "-DNO_SECURE_TESTS"
+# - comment out the "ASMOBJS" symbol definition
+# - modify the linking command blocks for zip and zipcloak according to
+# the following scheme:
+# add a command line "echo ,,,zlib_$(ZIPMODEL); >> zip[c].rsp" just
+# before the "$(LD)..." line; and remove the semicolon character from the
+# "echo ..." line immediately preceding the just inserted command
+
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = -DDOS -DDYN_ALLOC -DNO_SECURE_TESTS $(LOCAL_ZIP)
+
+# Zip requires compact or large memory model.
+# with 2.1, compact model exceeds 64k code segment; use large model
+ZIPMODEL=L # large model for Zip and ZipUtils
+
+# name of Flag to select memory model for assembler compiles, supported
+# values are __SMALL__ , __MEDIUM__ , __COMPACT__ , __LARGE__ :
+ASMODEL=__LARGE__ # keep in sync with ZIPMODEL definition !!
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+ASMOBJS = match.obj crc_i86.obj
+
+ASCPUFLAG = __$(CPU_TYP)86
+
+# ------------- Microsoft C 5.1, 6.0, 7.0 and VC++ Pro 1.0 -------------
+CC=cl
+MODEL=-A$(ZIPMODEL)
+FP=
+# With the feature additions of Zip 3, the default data segment gets occupied
+# with too much initialized data to fit into 64k. As a workaround, for some
+# source files with large amount of message strings, -Gt<num> is used to
+# force data items of size <num> or larger into their own data segments.
+COMMON_CFLAGS=-nologo -I. $(MODEL) $(FP) -DMSC $(LOC) -W3 -G$(CPU_TYP)
+CFLAGS=$(COMMON_CFLAGS) -Ox
+SPECFLAGS=$(COMMON_CFLAGS) -Oaict -Gs
+# For MSC/C++ 7.0 and VC++ no special flags are needed:
+# SPECFLAGS=$(CFLAGS)
+UTILFLAGS=-DUTIL $(CFLAGS) -Fo
+
+AS=masm
+ASFLAGS=-ml -t -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+# For MSC 6.0, use:
+#AS=ml
+#ASFLAGS=-c -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+# Supress -DDYN_ALLOC in ASFLAGS if you have suppressed it in CFLAGS
+
+LD=link
+LDFLAGS=/noi/farcall/packcode/e/st:0x1400/m
+# If you use an exe packer as recommended below, remove /e from LDFLAGS
+
+# ------------- Common declarations:
+STRIP=rem
+# If you don't have UPX, LZEXE, or PKLITE, get one of them. Then define:
+# (NOTE: upx needs a 386 or higher system to run the exe compressor)
+#STRIP=upx --8086 --best
+# or
+#STRIP=lzexe
+# or (if you've registered PKLITE)
+#STRIP=pklite
+# and remove /e from LDFLAGS.
+# This makes a big difference in .exe size (and possibly load time)
+
+# ------------- Used by install rule
+# set BIN to the directory you want to install the executables to
+BIN = c:\util
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) msdos.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj msdos_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) -Gt65 $*.c
+
+# MSC 5.1 generates bad code on zipfile with -Ox
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(SPECFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+msdos.obj: msdos/msdos.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) msdos/$*.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+# MSC 5.1 dies on zipsplit with -Ox
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(SPECFLAGS) $*.c
+
+# MSC 5.1 generates bad code on zipfile with -Ox
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(SPECFLAGS) -DUTIL -Fo$@ zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$@ fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$@ util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$@ crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS)$@ crypt.c
+
+msdos_.obj: msdos/msdos.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$@ msdos/msdos.c
+
+crc_i86.obj: msdos/crc_i86.asm
+ $(AS) $(ASFLAGS) msdos\crc_i86.asm ;
+
+match.obj: msdos/match.asm
+ $(AS) $(ASFLAGS) msdos\match.asm ;
+
+# we must cut the command line to fit in the MS/DOS 128 byte limit:
+zip.exe: $(OBJZ) $(OBJI)
+ echo $(OBJZ)+ > zip.rsp
+ echo $(OBJI); >> zip.rsp
+ $(LD) $(LDFLAGS) @zip.rsp
+ del zip.rsp
+ $(STRIP) zip.exe
+
+zipcloak.exe: $(OBJC)
+ echo $(OBJC); > zipc.rsp
+ $(LD) $(LDFLAGS) @zipc.rsp
+ del zipc.rsp
+ $(STRIP) zipcloak.exe
+
+zipnote.exe: $(OBJN)
+ echo $(OBJN); > zipn.rsp
+ $(LD) $(LDFLAGS) @zipn.rsp
+ del zipn.rsp
+ $(STRIP) zipnote.exe
+
+zipsplit.exe: $(OBJS)
+ echo $(OBJS); > zips.rsp
+ $(LD) $(LDFLAGS) @zips.rsp
+ del zips.rsp
+ $(STRIP) zipsplit.exe
+
+# No `install' and `clean' target possible as long as MSC's old MAKE utility
+# is supported (MSC 5.1 Make always tries to update ALL targets. The result
+# is that install and clean are always executed, unless an error occured.)
+#install: $(ZIPS)
+# copy /b *.exe $(BIN)
+#
+#clean:
+# del *.obj
+# del *.exe
diff --git a/msdos/makefile.tc b/msdos/makefile.tc
new file mode 100644
index 0000000..9ce3e32
--- /dev/null
+++ b/msdos/makefile.tc
@@ -0,0 +1,177 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Turbo C 2.0. (Thanks to Andrew Cadach <kadach@isi.itfs.nsk.su>)
+
+# To use, do "make -fmakefile.tc"
+
+# WARNING: the small model is not supported. You must use the large model.
+# Add -DSMALL_MEM or -DMEDIUM_MEM to the LOC macro if you wish to reduce
+# the memory requirements.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have tasm.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = -DDOS -DNO_SECURE_TESTS $(LOCAL_ZIP)
+
+# Zip requires compact or large memory model.
+# with 2.1, compact model exceeds 64k code segment; use large model
+ZIPMODEL=l # large model for Zip and ZipUtils
+
+# name of Flag to select memory model for assembler compiles, supported
+# values are __SMALL__ , __MEDIUM__ , __COMPACT__ , __LARGE__ :
+ASMODEL=__LARGE__ # keep in sync with ZIPMODEL definition !!
+
+# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc.
+CPU_TYP = 0
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+ASMOBJS = match.obj crc_i86.obj
+
+ASCPUFLAG = __$(CPU_TYP)86
+
+# ------------- Turbo C 2.0 -------------
+MODEL=-m$(ZIPMODEL)
+CFLAGS=-w -w-eff -w-def -w-sig -w-cln -a -d -G -O -Z $(MODEL) $(LOC)
+UTILFLAGS=-DUTIL $(CFLAGS) -o
+CC=tcc
+
+# Old versions of tasm (prior to 2.01) may not like the "-m2" option...
+AS=tasm
+ASFLAGS=-ml -t -m2 -DDYN_ALLOC -DSS_NEQ_DS -D$(ASCPUFLAG) -D$(ASMODEL) $(LOC)
+
+LD=tcc
+LDFLAGS=$(MODEL)
+
+# ------------- Common declarations:
+STRIP=rem
+# If you don't have UPX, LZEXE, or PKLITE, get one of them. Then define:
+# (NOTE: upx needs a 386 or higher system to run the exe compressor)
+#STRIP=upx --8086 --best
+# or
+#STRIP=lzexe
+# or (if you've registered PKLITE)
+#STRIP=pklite
+# This makes a big difference in .exe size (and possibly load time)
+
+# ------------- Used by install rule
+# set BIN to the directory you want to install the executables to
+BIN = c:\util
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) msdos.obj
+
+OBJU = _zipfile.obj _fileio.obj _util.obj globals.obj _msdos.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj _crc32.obj _crypt.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h msdos/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+msdos.obj: msdos/msdos.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) msdos/$*.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) -o$* $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) -o$* $*.c
+
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) -o$* $*.c
+
+_zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* zipfile.c
+
+_fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* fileio.c
+
+_util.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$* util.c
+
+_crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* crc32.c
+
+_crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS)$* crypt.c
+
+_msdos.obj: msdos/msdos.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$* msdos/msdos.c
+
+crc_i86.obj: msdos/crc_i86.asm
+ $(AS) $(ASFLAGS) msdos\crc_i86.asm ;
+
+match.obj: msdos/match.asm
+ $(AS) $(ASFLAGS) msdos\match.asm ;
+
+# make sure the command line fits in the MS/DOS 128 byte limit:
+zip.exe: $(OBJZ) $(OBJI)
+ rem ignore any warnings in the following renaming commands:
+ ren _*.obj _*.ob
+ ren zipcloak.obj *.ob
+ ren zipnote.obj *.ob
+ ren zipsplit.obj *.ob
+ $(LD) $(LDFLAGS) -ezip.exe *.obj
+ ren _*.ob _*.obj
+ ren zip???*.ob *.obj
+ $(STRIP) zip.exe
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) -ezipcloak.exe $(OBJC)
+ $(STRIP) zipcloak.exe
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) -ezipnote.exe $(OBJN)
+ $(STRIP) zipnote.exe
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) -ezipsplit.exe $(OBJS)
+ $(STRIP) zipsplit.exe
+
+install: $(ZIPS)
+ copy /b *.exe $(BIN)
+
+clean:
+ del *.obj
+ del *.exe
diff --git a/msdos/makefile.wat b/msdos/makefile.wat
new file mode 100644
index 0000000..dd4d8cd
--- /dev/null
+++ b/msdos/makefile.wat
@@ -0,0 +1,256 @@
+# WMAKE makefile for 16 bit MSDOS or 32 bit DOS extender (PMODE/W or DOS/4GW)
+# using Watcom C/C++ v11.0+, by Paul Kienitz, last revised 07 Aug 2005.
+# Makes Zip.exe, ZipNote.exe, ZipCloak.exe, and ZipSplit.exe.
+#
+# Invoke from Zip source dir with "WMAKE -F MSDOS\MAKEFILE.WAT [targets]"
+# To build with debug info use "WMAKE DEBUG=1 ..."
+# To build with no assembly modules use "WMAKE NOASM=1 ..."
+# To make the PMODE/W version use "WMAKE PM=1 ..."
+# To make the DOS/4GW version use "WMAKE GW=1 ..." (overrides PM=1)
+# Note: specifying PM or GW without NOASM requires that the win32 source
+# directory be present, so it can access the 32 bit assembly sources.
+# PMODE/W is recommended over DOS/4GW for best performance.
+# To create a low memory usage version of Zip, use "WMAKE WSIZE=8192 ..."
+# (or whatever power of two less than 32768 you wish) -- this also causes
+# SMALL_MEM to be defined. Compression performance will be reduced.
+# This currently is not supported with PM=1 or GW=1.
+#
+# Other options to be fed to the compiler and assembler can be specified in
+# an environment variable called LOCAL_ZIP.
+
+variation = $(%LOCAL_ZIP)
+
+# Stifle annoying "Delete this file?" questions when errors occur:
+.ERASE
+
+.EXTENSIONS:
+.EXTENSIONS: .exe .obj .c .h .asm
+
+# We maintain multiple sets of object files in different directories so that
+# we can compile msdos, dos/4gw or pmode/w, and win32 versions of Zip without
+# their object files interacting. The following var must be a directory name
+# ending with a backslash. All object file names must include this macro
+# at the beginning, for example "$(O)foo.obj".
+
+!ifdef GW
+PM = 1 # both protected mode formats use the same object files
+!endif
+
+!ifdef DEBUG
+! ifdef PM
+OBDIR = od32d
+! else
+! ifdef WSIZE
+OBDIR = od16l
+size = -DWSIZE=$(WSIZE) -DSMALL_MEM
+! else
+OBDIR = od16d
+size = -DMEDIUM_MEM
+! endif
+! endif
+!else
+! ifdef PM
+OBDIR = ob32d
+! else
+! ifdef WSIZE
+OBDIR = ob16l
+size = -DWSIZE=$(WSIZE) -DSMALL_MEM
+! else
+OBDIR = ob16d
+size = -DMEDIUM_MEM
+! endif
+! endif
+!endif
+O = $(OBDIR)\ # comment here so backslash won't continue the line
+
+# The assembly hot-spot code in crc_i[3]86.asm and match[32].asm is
+# optional. This section controls its usage.
+
+!ifdef NOASM
+ # C source
+asmob =
+cvars = $+$(cvars)$- -DDYN_ALLOC -DNO_ASM # or ASM_CRC might default on!
+# "$+$(foo)$-" means expand foo as it has been defined up to now; normally,
+# this make defers inner expansion until the outer macro is expanded.
+!else # !NOASM
+asmob = $(O)crc.obj $(O)match.obj
+! ifdef PM
+cvars = $+$(cvars)$- -DASM_CRC -DASMV # no DYN_ALLOC with match32.asm
+crc_s = win32\crc_i386.asm # requires that the win32 directory be present
+mat_s = win32\match32.asm # ditto
+! else
+cvars = $+$(cvars)$- -DDYN_ALLOC -DASM_CRC -DASMV
+avars = $+$(avars)$- -DDYN_ALLOC
+crc_s = msdos\crc_i86.asm
+mat_s = msdos\match.asm
+! endif
+!endif
+
+# Now we have to pick out the proper compiler and options for it. This gets
+# pretty complicated with the PM, GW, DEBUG, and NOASM options...
+
+link = wlink
+asm = wasm
+
+!ifdef PM
+cc = wcc386
+# Use Pentium Pro timings, register args, static strings in code:
+cflags = -bt=DOS -mf -6r -zt -zq
+aflags = -bt=DOS -mf -3 -zq
+cvars = $+$(cvars)$- -DDOS $(variation)
+avars = $+$(avars)$- -DWATCOM_DSEG $(variation)
+
+! ifdef GW
+lflags = sys DOS4G
+! else
+# THIS REQUIRES THAT PMODEW.EXE BE FINDABLE IN THE COMMAND PATH.
+# It does NOT require you to add a pmodew entry to wlink.lnk or wlsystem.lnk.
+defaultlibs = libpath %WATCOM%\lib386 libpath %WATCOM%\lib386\dos
+lflags = format os2 le op osname='PMODE/W' op stub=pmodew.exe $(defaultlibs)
+! endif
+
+!else # plain 16-bit DOS:
+
+cc = wcc
+# Use plain 8086 instructions, large memory model, static strings in code:
+cflags = -bt=DOS -ml -0 -zt -zq
+aflags = -bt=DOS -ml -0 -zq
+cvars = $+$(cvars)$- -DDOS $(size) $(variation)
+avars = $+$(avars)$- $(size) $(variation)
+lflags = sys DOS
+!endif # !PM
+
+# Specify optimizations, or a nonoptimized debugging version:
+
+!ifdef DEBUG
+cdebug = -od -d2
+ldebug = d w all op symf
+!else
+! ifdef PM
+cdebug = -s -obhikl+rt -oe=100 -zp8
+# -oa helps slightly but might be dangerous.
+! else
+cdebug = -s -oehiklrt
+! endif
+ldebug = op el
+!endif
+
+# How to compile most sources:
+.c.obj:
+ $(cc) $(cdebug) $(cflags) $(cvars) $[@ -fo=$@
+
+# Our object files. OBJZ is for Zip, OBJC is for ZipCloak, OBJN is for
+# ZipNote, and OBJS is for ZipSplit:
+
+OBJZ2 = $(O)zip.obj $(O)crypt.obj $(O)ttyio.obj $(O)zipfile.obj $(O)zipup.obj
+OBJZA = $(OBJZ2) $(O)util.obj $(O)fileio.obj $(O)deflate.obj
+OBJZB = $(O)trees.obj $(O)globals.obj $(O)crc32.obj $(asmob) $(O)msdos.obj
+
+OBJU2 = $(O)zipfile_.obj $(O)fileio_.obj $(O)util_.obj $(O)globals.obj
+OBJ_U = $(OBJU2) $(O)msdos_.obj
+
+OBJC = $(O)zipcloak.obj $(O)crc32_.obj $(O)crypt_.obj $(O)ttyio.obj $(OBJ_U)
+
+OBJN = $(O)zipnote.obj $(OBJ_U)
+
+OBJS = $(O)zipsplit.obj $(OBJ_U)
+
+# Common header files included by all C sources:
+
+ZIP_H = zip.h ziperr.h tailor.h msdos\osdep.h
+
+
+# HERE WE GO! By default, make all targets:
+all: Zip.exe ZipNote.exe ZipCloak.exe ZipSplit.exe
+
+# Convenient shorthand options for single targets:
+z: Zip.exe .SYMBOLIC
+n: ZipNote.exe .SYMBOLIC
+c: ZipCloak.exe .SYMBOLIC
+s: ZipSplit.exe .SYMBOLIC
+
+Zip.exe: $(OBDIR) $(OBJZA) $(OBJZB) $(OBJV)
+ set WLK_VA=file {$(OBJZA)}
+ set WLK_VB=file {$(OBJZB) $(OBJV)}
+ $(link) $(lflags) $(ldebug) name $@ @WLK_VA @WLK_VB
+ set WLK_VA=
+ set WLK_VB=
+# We use WLK_VA and WLK_VB to keep the size of each command under 256 chars.
+
+ZipNote.exe: $(OBDIR) $(OBJN)
+ set WLK_VAR=file {$(OBJN)}
+ $(link) $(lflags) $(ldebug) name $@ @WLK_VAR
+ set WLK_VAR=
+
+ZipCloak.exe: $(OBDIR) $(OBJC)
+ set WLK_VAR=file {$(OBJC)}
+ $(link) $(lflags) $(ldebug) name $@ @WLK_VAR
+ set WLK_VAR=
+
+ZipSplit.exe: $(OBDIR) $(OBJS)
+ set WLK_VAR=file {$(OBJS)}
+ $(link) $(lflags) $(ldebug) name $@ @WLK_VAR
+ set WLK_VAR=
+
+# Source dependencies:
+
+$(O)crc32.obj: crc32.c $(ZIP_H) crc32.h
+$(O)crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+$(O)deflate.obj: deflate.c $(ZIP_H)
+$(O)fileio.obj: fileio.c $(ZIP_H) crc32.h
+$(O)globals.obj: globals.c $(ZIP_H)
+$(O)trees.obj: trees.c $(ZIP_H)
+$(O)ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+$(O)util.obj: util.c $(ZIP_H)
+$(O)zip.obj: zip.c $(ZIP_H) crc32.h crypt.h revision.h ttyio.h
+$(O)zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+$(O)zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h msdos\zipup.h
+$(O)zipnote.obj: zipnote.c $(ZIP_H) revision.h
+$(O)zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+$(O)zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+# Special case object files:
+
+$(O)msdos.obj: msdos\msdos.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) msdos\msdos.c -fo=$@
+
+$(O)match.obj: $(mat_s)
+ $(asm) $(aflags) $(avars) $(mat_s) -fo=$@
+
+$(O)crc.obj: $(crc_s)
+ $(asm) $(aflags) $(avars) $(crc_s) -fo=$@
+
+# Variant object files for ZipNote, ZipCloak, and ZipSplit:
+
+$(O)zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL zipfile.c -fo=$@
+
+$(O)fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL fileio.c -fo=$@
+
+$(O)util_.obj: util.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL util.c -fo=$@
+
+$(O)crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crc32.c -fo=$@
+
+$(O)crypt_.obj: crypt.c $(ZIP_H) crc32.h crypt.h ttyio.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crypt.c -fo=$@
+
+$(O)msdos_.obj: msdos\msdos.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL msdos\msdos.c -fo=$@
+
+# Creation of subdirectory for intermediate files
+$(OBDIR):
+ -mkdir $@
+
+# Unwanted file removal:
+
+clean: .SYMBOLIC
+ del $(O)*.obj
+
+cleaner: clean .SYMBOLIC
+ del Zip.exe
+ del ZipNote.exe
+ del ZipCloak.exe
+ del ZipSplit.exe
diff --git a/msdos/match.asm b/msdos/match.asm
new file mode 100644
index 0000000..998881e
--- /dev/null
+++ b/msdos/match.asm
@@ -0,0 +1,477 @@
+;===========================================================================
+; Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2007-Mar-04 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+;
+; match.asm by Jean-loup Gailly.
+
+; match.asm, optimized version of longest_match() in deflate.c
+; Must be assembled with masm -ml. To be used only with C compact model
+; or large model. (For large model, assemble with -D__LARGE__).
+; This file is only optional. If you don't have masm or tasm, use the
+; C version (add -DNO_ASM to CFLAGS in makefile.msc and remove match.obj
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+;
+; The code has been prepared for two different C compiler calling conventions
+; and contains some support for dynamically allocated working space.
+; The different environments are selected by two conditional flags:
+; DYN_ALLOC : select support for malloc'ed working space
+; SS_NEQ_DS : relaxes assumption that stack and default data segments
+; are identical
+; When SS_NEQ_DS is defined, the code segment is used to store some
+; local variables. This (bad) coding practice is very likely to break any
+; `segment protection scheme', it will most probably only work for real
+; mode programs.
+;
+; Turbo C 2.0 does not support static allocation of more than 64K bytes per
+; file, and does not have SS == DS. So TC and BC++ users must use:
+; tasm -ml -DDYN_ALLOC -DSS_NEQ_DS match;
+;
+; To simplify the code, the option -DDYN_ALLOC is supported for OS/2
+; only if the arrays are guaranteed to have zero offset (allocated by
+; halloc). We also require SS==DS. This is satisfied for MSC but not Turbo C.
+;
+; Per default, test code is included to check if the above requirements are
+; fulfilled. This test code can be disabled by defining the compile time
+; option flag NO_SECURE_TESTS when compiling for a production executable.
+; This shortens the code size (but the performance gain is neglectable).
+; The security tests should remain enabled, when a new C compiler
+; and/or a new set of compilation options is tried.
+
+ name match
+
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+ifndef USE_ZLIB
+
+ifdef DEBUG
+ VERBOSE_INFO EQU 1
+else
+ ifdef _AS_MSG_
+ VERBOSE_INFO EQU 1
+ else
+ VERBOSE_INFO EQU 0
+ endif
+endif
+
+ifndef __SMALL__
+ ifndef __COMPACT__
+ ifndef __MEDIUM__
+ ifndef __LARGE__
+ ifndef __HUGE__
+; __SMALL__ EQU 1
+ endif
+ endif
+ endif
+ endif
+endif
+
+ifdef __HUGE__
+; .MODEL Huge
+ ifndef @CodeSize
+ @CodeSize EQU 1
+ endif
+ ifndef @DataSize
+ @DataSize EQU 1
+ endif
+ Save_DS EQU 1
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Huge memory model
+ endif
+ endif
+else
+ ifdef __LARGE__
+; .MODEL Large
+ ifndef @CodeSize
+ @CodeSize EQU 1
+ endif
+ ifndef @DataSize
+ @DataSize EQU 1
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Large memory model
+ endif
+ endif
+ else
+ ifdef __COMPACT__
+; .MODEL Compact
+ ifndef @CodeSize
+ @CodeSize EQU 0
+ endif
+ ifndef @DataSize
+ @DataSize EQU 1
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Compact memory model
+ endif
+ endif
+ else
+ ifdef __MEDIUM__
+; .MODEL Medium
+ ifndef @CodeSize
+ @CodeSize EQU 1
+ endif
+ ifndef @DataSize
+ @DataSize EQU 0
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Medium memory model
+ endif
+ endif
+ else
+; .MODEL Small
+ ifndef @CodeSize
+ @CodeSize EQU 0
+ endif
+ ifndef @DataSize
+ @DataSize EQU 0
+ endif
+ if VERBOSE_INFO
+ if1
+ %out Assembling for C, Small memory model
+ endif
+ endif
+ endif
+ endif
+ endif
+endif
+
+if @CodeSize
+ LCOD_OFS EQU 2
+else
+ LCOD_OFS EQU 0
+endif
+
+IF @DataSize
+ LDAT_OFS EQU 2
+else
+ LDAT_OFS EQU 0
+endif
+
+ifdef Save_DS
+; (di,si,ds)+(size, return address)
+ SAVE_REGS EQU 6+(4+LCOD_OFS)
+else
+; (di,si)+(size, return address)
+ SAVE_REGS EQU 4+(4+LCOD_OFS)
+endif
+
+;
+; Selection of the supported CPU instruction set and initialization
+; of CPU type related macros:
+;
+ifdef __586
+ Use_286_code EQU 1
+ Align_Size EQU 16 ; paragraph alignment on Pentium
+ Alig_PARA EQU 1 ; paragraph aligned code segment
+else
+ifdef __486
+ Use_286_code EQU 1
+ Align_Size EQU 4 ; dword alignment on 32 bit processors
+ Alig_PARA EQU 1 ; paragraph aligned code segment
+else
+ifdef __386
+ Use_286_code EQU 1
+ Align_Size EQU 4 ; dword alignment on 32 bit processors
+ Alig_PARA EQU 1 ; paragraph aligned code segment
+else
+ifdef __286
+ Use_286_code EQU 1
+ Align_Size EQU 2 ; word alignment on 16 bit processors
+ Alig_PARA EQU 0 ; word aligned code segment
+else
+ifdef __186
+ Use_186_code EQU 1
+ Align_Size EQU 2 ; word alignment on 16 bit processors
+ Alig_PARA EQU 0 ; word aligned code segment
+else
+ Align_Size EQU 2 ; word alignment on 16 bit processors
+ Alig_PARA EQU 0 ; word aligned code segment
+endif ;?__186
+endif ;?__286
+endif ;?__386
+endif ;?__486
+endif ;?__586
+
+ifdef Use_286_code
+ .286
+ Have_80x86 EQU 1
+else
+ifdef Use_186_code
+ .186
+ Have_80x86 EQU 1
+else
+ .8086
+ Have_80x86 EQU 0
+endif ;?Use_186_code
+endif ;?Use_286_code
+
+ifndef DYN_ALLOC
+ extrn _prev : word
+ extrn _window : byte
+ prev equ _prev ; offset part
+ window equ _window
+endif
+
+_DATA segment word public 'DATA'
+ extrn _nice_match : word
+ extrn _match_start : word
+ extrn _prev_length : word
+ extrn _good_match : word
+ extrn _strstart : word
+ extrn _max_chain_length : word
+ifdef DYN_ALLOC
+ extrn _prev : word
+ extrn _window : word
+ prev equ 0 ; offset forced to zero
+ window equ 0
+ window_seg equ _window[2]
+ window_off equ 0
+else
+ wseg dw seg _window
+ window_seg equ wseg
+ window_off equ offset _window
+endif
+_DATA ends
+
+DGROUP group _DATA
+
+if @CodeSize
+if Alig_PARA
+MATCH_TEXT SEGMENT PARA PUBLIC 'CODE'
+else
+MATCH_TEXT SEGMENT WORD PUBLIC 'CODE'
+endif
+ assume cs: MATCH_TEXT, ds: DGROUP
+else ;!@CodeSize
+if Alig_PARA
+_TEXT segment para public 'CODE'
+else
+_TEXT segment word public 'CODE'
+endif
+ assume cs: _TEXT, ds: DGROUP
+endif ;?@CodeSize
+
+ public _match_init
+ public _longest_match
+
+ifndef WSIZE
+ WSIZE equ 32768 ; keep in sync with zip.h !
+endif
+ MIN_MATCH equ 3
+ MAX_MATCH equ 258
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+ MAX_DIST equ (WSIZE-MIN_LOOKAHEAD)
+
+ifdef DYN_ALLOC
+ ifdef SS_NEQ_DS
+ prev_ptr dw seg _prev ; pointer to the prev array
+ endif
+else
+ prev_ptr dw seg _prev ; pointer to the prev array
+endif
+ifdef SS_NEQ_DS
+ match_start dw 0 ; copy of _match_start if SS != DS
+ nice_match dw 0 ; copy of _nice_match if SS != DS
+endif
+
+; initialize or check the variables used in match.asm.
+
+if @CodeSize
+_match_init proc far ; 'proc far' for large model
+else
+_match_init proc near ; 'proc near' for compact model
+endif
+ifdef SS_NEQ_DS
+ ma_start equ cs:match_start ; does not work on OS/2
+ nice equ cs:nice_match
+else
+ assume ss: DGROUP
+ ma_start equ ss:_match_start
+ nice equ ss:_nice_match
+ ifndef NO_SECURE_TESTS
+ mov ax,ds
+ mov bx,ss
+ cmp ax,bx ; SS == DS?
+ jne fatal_err
+ endif
+endif
+ifdef DYN_ALLOC
+ ifndef NO_SECURE_TESTS
+ cmp _prev[0],0 ; verify zero offset
+ jne fatal_err
+ cmp _window[0],0
+ jne fatal_err
+ endif
+ ifdef SS_NEQ_DS
+ mov ax,_prev[2] ; segment value
+ mov cs:prev_ptr,ax ; ugly write to code, crash on OS/2
+ prev_seg equ cs:prev_ptr
+ else
+ prev_seg equ ss:_prev[2] ; works on OS/2 if SS == DS
+ endif
+else
+ prev_seg equ cs:prev_ptr
+endif
+ ret
+ifndef NO_SECURE_TESTS
+if @CodeSize
+ extrn _exit : far ; 'far' for large model
+else
+ extrn _exit : near ; 'near' for compact model
+endif
+fatal_err: ; (quiet) emergency stop:
+ call _exit ; incompatible "global vars interface"
+endif
+
+_match_init endp
+
+; -----------------------------------------------------------------------
+; Set match_start to the longest match starting at the given string and
+; return its length. Matches shorter or equal to prev_length are discarded,
+; in which case the result is equal to prev_length and match_start is
+; garbage.
+; IN assertions: cur_match is the head of the hash chain for the current
+; string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+
+; int longest_match(cur_match)
+
+ align Align_Size
+
+if @CodeSize
+_longest_match proc far ; 'proc far' for large model
+else
+_longest_match proc near ; 'proc near' for compact model
+endif
+ push bp
+ mov bp,sp
+ push di
+ push si
+ push ds
+
+if @CodeSize
+ cur_match equ word ptr [bp+6] ; [bp+6] for large model
+else
+ cur_match equ word ptr [bp+4] ; [bp+4] for compact model
+endif
+
+; window equ es:window (es:0 for DYN_ALLOC)
+; prev equ ds:prev
+; match equ es:si
+; scan equ es:di
+; chain_length equ bp
+; best_len equ bx
+; limit equ dx
+
+ mov si,cur_match ; use bp before it is destroyed
+ifdef SS_NEQ_DS
+ mov ax,_nice_match
+ mov nice,ax ; ugly write to code, crash on OS/2
+endif
+ mov dx,_strstart
+ mov bp,_max_chain_length ; chain_length = max_chain_length
+ mov di,dx
+ sub dx,MAX_DIST ; limit = strstart-MAX_DIST
+ cld ; string ops increment si and di
+ jae limit_ok
+ sub dx,dx ; limit = NIL
+limit_ok:
+ add di,2+window_off ; di = offset(window + strstart + 2)
+ mov bx,_prev_length ; best_len = prev_length
+ mov es,window_seg
+ mov ax,es:[bx+di-3] ; ax = scan[best_len-1..best_len]
+ mov cx,es:[di-2] ; cx = scan[0..1]
+ cmp bx,_good_match ; do we have a good match already?
+ mov ds,prev_seg ; (does not destroy the flags)
+ assume ds: nothing
+ jb do_scan ; good match?
+if Have_80x86
+ shr bp,2 ; chain_length >>= 2
+else
+ shr bp,1 ; chain_length >>= 2
+ shr bp,1
+endif
+ jmp short do_scan
+
+ align Align_Size ; align destination of branch
+long_loop:
+; at this point, ds:di == scan+2, ds:si == cur_match
+ mov ax,[bx+di-3] ; ax = scan[best_len-1..best_len]
+ mov cx,[di-2] ; cx = scan[0..1]
+ mov ds,prev_seg ; reset ds to address the prev array
+short_loop:
+; at this point, di == scan+2, si = cur_match,
+; ax = scan[best_len-1..best_len] and cx = scan[0..1]
+if (WSIZE-32768)
+ and si,WSIZE-1 ; not needed if WSIZE=32768
+endif
+ shl si,1 ; cur_match as word index
+ dec bp ; --chain_length
+ mov si,prev[si] ; cur_match = prev[cur_match]
+ jz the_end
+ cmp si,dx ; cur_match <= limit ?
+ jbe the_end
+do_scan:
+ cmp ax,word ptr es:window[bx+si-1] ; check match at best_len-1
+ jne short_loop
+ cmp cx,word ptr es:window[si] ; check min_match_length match
+ jne short_loop
+
+ mov cx,es
+ add si,2+window_off ; si = match
+ mov ds,cx ; ds = es = window
+ mov cx,(MAX_MATCH-2)/2 ; scan for at most MAX_MATCH bytes
+ mov ax,di ; ax = scan+2
+ repe cmpsw ; loop until mismatch
+ je maxmatch ; match of length MAX_MATCH?
+mismatch:
+ mov cl,[di-2] ; mismatch on first or second byte?
+ xchg ax,di ; di = scan+2, ax = end of scan
+ sub cl,[si-2] ; cl = 0 if first bytes equal
+ sub ax,di ; ax = len
+ sub si,2+window_off ; si = cur_match + len
+ sub si,ax ; si = cur_match
+ sub cl,1 ; set carry if cl == 0 (can't use DEC)
+ adc ax,0 ; ax = carry ? len+1 : len
+ cmp ax,bx ; len > best_len ?
+ jle long_loop
+ mov ma_start,si ; match_start = cur_match
+ mov bx,ax ; bx = best_len = len
+ cmp ax,nice ; len >= nice_match ?
+ jl long_loop
+the_end:
+ pop ds
+ assume ds: DGROUP
+ifdef SS_NEQ_DS
+ mov ax,ma_start ; garbage if no match found
+ mov ds:_match_start,ax
+endif
+ pop si
+ pop di
+ pop bp
+ mov ax,bx ; result = ax = best_len
+ ret
+maxmatch: ; come here if maximum match
+ cmpsb ; increment si and di
+ jmp mismatch ; force match_length = MAX_LENGTH
+
+_longest_match endp
+
+if @CodeSize
+MATCH_TEXT ENDS
+else
+_TEXT ENDS
+endif
+;
+endif ;!USE_ZLIB
+;
+end
diff --git a/msdos/msdos.c b/msdos/msdos.c
new file mode 100644
index 0000000..4f71397
--- /dev/null
+++ b/msdos/msdos.c
@@ -0,0 +1,1126 @@
+/*
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL /* little or no material in this file is used by UTIL */
+
+#include <dos.h>
+#include <time.h>
+
+
+#if defined(__GO32__) || defined(__TURBOC__)
+# include <dir.h> /* prototypes of find*() */
+ typedef struct ffblk ff_dir;
+# define FATTR (hidden_files ? FA_HIDDEN+FA_SYSTEM+FA_DIREC : FA_DIREC)
+# define FFIRST(n,d,a) findfirst(n,(struct ffblk *)d,a)
+# define FNEXT(d) findnext((struct ffblk *)d)
+# if (defined(__TURBOC__) || (defined(__DJGPP__) && (__DJGPP__ >=2)))
+# if (defined(__DJGPP__) && (__DJGPP__ == 2) && (__DJGPP_MINOR__ == 0))
+# include <libc/dosio.h>
+# endif
+# define GetFileMode(name) _chmod(name, 0)
+# define SetFileMode(name, attr) _chmod(name, 1, attr)
+# else /* DJGPP v1.x */
+# define GetFileMode(name) bdosptr(0x43, (name), 0)
+# endif
+#endif /* __GO32__ || __TURBOC__ */
+
+#if defined(MSC) || defined(__WATCOMC__)
+ typedef struct find_t ff_dir;
+# define FATTR (hidden_files ? _A_HIDDEN+_A_SYSTEM+_A_SUBDIR : _A_SUBDIR)
+# ifndef FA_LABEL
+# define FA_LABEL _A_VOLID
+# endif
+# define FFIRST(n,d,a) _dos_findfirst(n,a,(struct find_t *)d)
+# define FNEXT(d) _dos_findnext((struct find_t *)d)
+# define ff_name name
+# define ff_fdate wr_date
+# define ff_ftime wr_time
+# define ff_attrib attrib
+#endif /* MSC || __WATCOMC__ */
+
+#ifdef __EMX__
+# ifdef EMX_OBSOLETE /* emx 0.9b or earlier */
+# define size_t xxx_size_t
+# define wchar_t xxx_wchar_t
+# define tm xxx_tm
+# include <sys/emx.h>
+# undef size_t
+# undef wchar_t
+# undef tm
+# else /* !EMX_OBSOLETE */ /* emx 0.9c or newer */
+# include <emx/syscalls.h>
+# endif /* ?EMX_OBSOLETE */
+ typedef struct _find ff_dir;
+# define FATTR (hidden_files ? _A_HIDDEN+_A_SYSTEM+_A_SUBDIR : _A_SUBDIR)
+# define FA_LABEL _A_VOLID
+# define FFIRST(n,d,a) __findfirst(n,a,d)
+# define FNEXT(d) __findnext(d)
+# define ff_name name
+# define ff_fdate date
+# define ff_ftime time
+# define ff_attrib attr
+# define GetFileMode(name) __chmod(name, 0, 0)
+# define SetFileMode(name, attr) __chmod(name, 1, attr)
+#endif /* __EMX__ */
+
+#ifndef SetFileMode
+# define SetFileMode(name, attr) _dos_setfileattr(name, attr)
+#endif
+
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+int rmdir OF((const char *));
+int utime OF((char *, ztimbuf *));
+
+/* Local functions */
+#ifndef GetFileMode
+int GetFileMode OF((char *name));
+#endif /* !GetFileMode */
+
+local int initDirSearch OF((char *name, ff_dir *ff_context_p));
+local char *getVolumeLabel OF((int, ulg *, ulg *, time_t *));
+local int wild_recurse OF((char *, char *));
+local int procname_dos OF((char *n, int caseflag, unsigned attribs));
+local int is_running_on_windows OF((void));
+
+#define MSDOS_INVALID_ATTR 0xFF
+#define getDirEntryAttr(d) ((d)->ff_attrib)
+
+/* Module level variables */
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Module level constants */
+local ZCONST char wild_match_all[] = "*.*";
+
+
+#ifndef GetFileMode
+int GetFileMode(char *name)
+{
+ unsigned int attr = 0;
+ return (_dos_getfileattr(name, &attr) ? -1 : attr);
+}
+#endif /* !GetFileMode */
+
+local int initDirSearch(name, ff_context_p)
+ char *name; /* name of directory to scan */
+ ff_dir *ff_context_p; /* pointer to FFIRST/FNEXT context structure */
+{
+ int r; /* FFIRST return value */
+ char *p, *q; /* temporary copy of name, and aux pointer */
+
+ if ((p = malloc(strlen(name) + (2 + sizeof(wild_match_all)))) == NULL)
+ return ZE_MEM;
+
+ strcpy(p, name);
+ q = p + strlen(p);
+ if (q[-1] == ':')
+ *q++ = '.';
+ if ((q - p) > 0 && *(q - 1) != '/')
+ *q++ = '/';
+ strcpy(q, wild_match_all);
+ r = FFIRST(p, ff_context_p, FATTR);
+ free((zvoid *)p);
+
+ return (r ? ZE_MISS : ZE_OK);
+}
+
+local char *getVolumeLabel(drive, vtime, vmode, vutim)
+ int drive; /* drive name: 'A' .. 'Z' or '\0' for current drive */
+ ulg *vtime; /* volume label creation time (DOS format) */
+ ulg *vmode; /* volume label file mode */
+ time_t *vutim;/* volume label creation time (UNIX format) */
+
+/* If a volume label exists for the given drive, return its name and
+ set its time and mode. The returned name must be static data. */
+{
+ static char vol[14];
+ ff_dir d;
+ char *p;
+
+ if (drive) {
+ vol[0] = (char)drive;
+ strcpy(vol+1, ":/");
+ } else {
+ strcpy(vol, "/");
+ }
+ strcat(vol, wild_match_all);
+ if (FFIRST(vol, &d, FA_LABEL) == 0) {
+ strncpy(vol, d.ff_name, sizeof(vol)-1);
+ vol[sizeof(vol)-1] = '\0'; /* just in case */
+ if ((p = strchr(vol, '.')) != NULL) /* remove dot, though PKZIP doesn't */
+ strcpy(p, p + 1);
+ *vtime = ((ulg)d.ff_fdate << 16) | ((ulg)d.ff_ftime & 0xffff);
+ *vmode = (ulg)d.ff_attrib;
+ *vutim = dos2unixtime(*vtime);
+ return vol;
+ }
+ return NULL;
+}
+
+
+#ifdef MSDOS16
+#define ONENAMELEN 12 /* no 16-bit compilers supports LFN */
+#else
+#define ONENAMELEN 255
+#endif
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the */
+/* middle of it. All wildcards to be expanded must come AFTER wildtail. */
+
+local int wild_recurse(whole, wildtail)
+char *whole;
+char *wildtail;
+{
+ ff_dir dir;
+ char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+ ush newlen, amatch = 0;
+ int e = ZE_MISS;
+
+ if (!isshexp(wildtail)) {
+ struct stat s; /* dummy buffer for stat() */
+
+ if (!LSSTAT(whole, &s)) /* file exists ? */
+ return procname(whole, 0);
+ else
+ return ZE_MISS; /* woops, no wildcards! */
+ }
+
+ /* back up thru path components till existing dir found */
+ do {
+ name = wildtail + strlen(wildtail) - 1;
+ for (;;)
+ if (name-- <= wildtail || *name == PATH_END) {
+ subwild = name + 1;
+ plug2 = *subwild;
+ *subwild = 0;
+ break;
+ }
+ if (glue)
+ *glue = plug;
+ glue = subwild;
+ plug = plug2;
+ e = initDirSearch(whole, &dir);
+ } while (e == ZE_MISS && subwild > wildtail);
+ wildtail = subwild; /* skip past non-wild components */
+ if (e != ZE_OK) {
+ if (glue)
+ *glue = plug;
+ goto ohforgetit;
+ }
+ subwild = strchr(wildtail + 1, PATH_END);
+ /* this "+ 1" dodges the ^^^ hole left by *glue == 0 */
+ if (subwild != NULL) {
+ *(subwild++) = 0; /* wildtail = one component pattern */
+ newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
+ } else
+ newlen = strlen(whole) + (ONENAMELEN + 1);
+ if ((newwhole = malloc(newlen)) == NULL) {
+ if (glue)
+ *glue = plug;
+ e = ZE_MEM;
+ goto ohforgetit;
+ }
+ strcpy(newwhole, whole);
+ newlen = strlen(newwhole);
+ if (glue)
+ *glue = plug; /* repair damage to whole */
+ if (!isshexp(wildtail)) {
+ e = ZE_MISS; /* non-wild name not found */
+ goto ohforgetit;
+ }
+
+ do {
+ if (strcmp(dir.ff_name, ".") && strcmp(dir.ff_name, "..")
+ && MATCH(wildtail, dir.ff_name, 0)) {
+ strcpy(newwhole + newlen, dir.ff_name);
+ if (subwild) {
+ name = newwhole + strlen(newwhole);
+ *(name++) = PATH_END;
+ strcpy(name, subwild);
+ e = wild_recurse(newwhole, name);
+ } else
+ e = procname_dos(newwhole, 0, getDirEntryAttr(&dir));
+ newwhole[newlen] = 0;
+ if (e == ZE_OK)
+ amatch = 1;
+ else if (e != ZE_MISS)
+ break;
+ }
+ } while (FNEXT(&dir) == 0);
+
+ ohforgetit:
+ if (subwild)
+ *--subwild = PATH_END;
+ if (newwhole)
+ free(newwhole);
+ if (e == ZE_MISS && amatch)
+ e = ZE_OK;
+ return e;
+}
+
+int wild(w)
+char *w; /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+ file system. Return an error code in the ZE_ class. */
+{
+ char *p; /* path */
+ char *q; /* diskless path */
+ int e; /* result */
+
+ if (volume_label == 1) {
+ volume_label = 2;
+ label = getVolumeLabel((w != NULL && w[1] == ':') ? to_up(w[0]) : '\0',
+ &label_time, &label_mode, &label_utim);
+ if (label != NULL)
+ (void)newname(label, 0, 0);
+ if (w == NULL || (w[1] == ':' && w[2] == '\0')) return ZE_OK;
+ /* "zip -$ foo a:" can be used to force drive name */
+ }
+ /* special handling of stdin request */
+ if (strcmp(w, "-") == 0) /* if compressing stdin */
+ return newname(w, 0, 0);
+
+ /* Allocate and copy pattern, leaving room to add "." if needed */
+ if ((p = malloc(strlen(w) + 2)) == NULL)
+ return ZE_MEM;
+ strcpy(p, w);
+
+ /* Normalize path delimiter as '/' */
+ for (q = p; *q; q++) /* use / consistently */
+ if (*q == '\\')
+ *q = '/';
+
+ /* Separate the disk part of the path */
+ q = strchr(p, ':');
+ if (q != NULL) {
+ if (strchr(++q, ':')) /* sanity check for safety of wild_recurse */
+ return ZE_MISS;
+ } else
+ q = p;
+
+ /* Normalize bare disk names */
+ if (q > p && !*q)
+ strcpy(q, ".");
+
+ /* Here we go */
+ e = wild_recurse(p, q);
+ free((zvoid *)p);
+ return e;
+}
+
+local int procname_dos(n, caseflag, attribs)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+unsigned attribs; /* file attributes, if available */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ ff_dir *d; /* control structure for FFIRST/FNEXT */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ int ff_status; /* return value of FFIRST/FNEXT */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (n == NULL) /* volume_label request in freshen|delete mode ?? */
+ return ZE_OK;
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (*n == '\0') return ZE_MISS;
+ else if (attribs != MSDOS_INVALID_ATTR)
+ {
+ /* Avoid calling stat() for performance reasons when it is already known
+ (from a previous directory scan) that the passed name corresponds to
+ a "real existing" file. The only information needed further down in
+ this function is the distinction between directory entries and other
+ (typically normal file) entries. This distinction can be derived from
+ the file's attributes that the directory lookup has already provided
+ "for free".
+ */
+ s.st_mode = ((attribs & MSDOS_DIR_ATTR) ? S_IFDIR : S_IFREG);
+ }
+ else if (LSSTAT(n, &s)
+#ifdef __TURBOC__
+ /* For this compiler, stat() succeeds on wild card names! */
+ || isshexp(n)
+#endif
+ )
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ if (caseflag) {
+ p = malloc(strlen(n) + 1);
+ if (p != NULL)
+ strcpy(p, n);
+ } else
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (z->mark) z->dosflag = 1; /* force DOS attribs for incl. names */
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ for (p = n; *p; p++) /* use / consistently */
+ if (*p == '\\')
+ *p = '/';
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse)
+ {
+ if ((d = malloc(sizeof(ff_dir))) == NULL ||
+ (m = initDirSearch(n, d)) == ZE_MEM)
+ {
+ if (d != NULL)
+ free((zvoid *)d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ for (e = d->ff_name, ff_status = m;
+ ff_status == 0;
+ ff_status = FNEXT(d))
+ {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ free((zvoid *)d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname_dos(a, caseflag, getDirEntryAttr(d)))
+ != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ free((zvoid *)d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+{
+ return procname_dos(n, caseflag, MSDOS_INVALID_ATTR);
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+ dosflag = 1;
+
+ /* Find starting point in name before doing malloc */
+ /* Strip drive specification */
+ t = *x && *(x + 1) == ':' ? x + 2 : x;
+ /* Strip "//host/share/" part of a UNC name */
+ if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
+ (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
+ n = x + 2;
+ while (*n != '\0' && *n != '/' && *n != '\\')
+ n++; /* strip host name */
+ if (*n != '\0') {
+ n++;
+ while (*n != '\0' && *n != '/' && *n != '\\')
+ n++; /* strip `share' name */
+ }
+ if (*n != '\0')
+ t = n + 1;
+ }
+ /* Strip leading "/" to convert an absolute path into a relative path */
+ while (*t == '/' || *t == '\\')
+ t++;
+ /* Skip leading "./" as well */
+ while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
+ t += 2;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ for (n = t; *n; n++)
+ if (*n == '\\')
+ *n = '/';
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (isdir == 42) return n; /* avoid warning on unused variable */
+
+ if (dosify)
+ msname(n);
+ else
+#if defined(__DJGPP__) && __DJGPP__ >= 2
+ if (_USE_LFN == 0)
+#endif
+ strlwr(n);
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+
+ return x;
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#if defined(__TURBOC__) || defined(__GO32__)
+ int h; /* file handle */
+
+ if ((h = open(f, 0)) != -1)
+ {
+ setftime(h, (struct ftime *)(void *)&d);
+ close(h);
+ }
+#else /* !__TURBOC__ && !__GO32__ */
+ ztimbuf u; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u.actime and u.modtime */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ /* Set updated and accessed times of f */
+ utime(f, &u);
+#endif /* ?(__TURBOC__ || __GO32__) */
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+ int isstdin = !strcmp(f, "-");
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (isstdin) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ time((time_t *)&s.st_mtime); /* some fstat()s return time zero */
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+#if (S_IFREG != 0x8000)
+ /* kludge to work around non-standard S_IFREG flag used in DJGPP V2.x */
+ if ((s.st_mode & S_IFMT) == S_IFREG) *a |= 0x80000000L;
+#endif
+ }
+ free(name);
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime((time_t *)&s.st_mtime);
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ */
+{
+ return rmdir(d);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid) return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME;
+ z->extra[5] = (char)(z_utim->mtime);
+ z->extra[6] = (char)(z_utim->mtime >> 8);
+ z->extra[7] = (char)(z_utim->mtime >> 16);
+ z->extra[8] = (char)(z_utim->mtime >> 24);
+
+ z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+ z->cextra = z->extra;
+
+ return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+ return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+
+#ifdef MY_ZCALLOC /* Special zcalloc function for MEMORY16 (MSDOS/OS2) */
+
+#if defined(__TURBOC__) && !defined(OS2)
+/* Small and medium model are for now limited to near allocation with
+ * reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ zvoid far *org_ptr;
+ zvoid far *new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+zvoid far *zcalloc (unsigned items, unsigned size)
+{
+ zvoid far *buf;
+ ulg bsize = (ulg)items*size;
+
+ if (bsize < (65536L-16L)) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-NULL) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+zvoid zcfree (zvoid far *ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = next_ptr - 1; n >= 0; n--) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ziperr(ZE_MEM, "zcfree: ptr not found");
+}
+#endif /* __TURBOC__ */
+
+#if defined(MSC) || defined(__WATCOMC__)
+#if (!defined(_MSC_VER) || (_MSC_VER < 700))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+zvoid far *zcalloc (unsigned items, unsigned size)
+{
+ return (zvoid far *)_halloc((long)items, size);
+}
+
+zvoid zcfree (zvoid far *ptr)
+{
+ _hfree((void huge *)ptr);
+}
+#endif /* MSC || __WATCOMC__ */
+
+#endif /* MY_ZCALLOC */
+
+#if (defined(__WATCOMC__) && defined(ASMV) && !defined(__386__))
+/* This is a hack to connect "call _exit" in match.asm to exit() */
+#pragma aux xit "_exit" parm caller []
+void xit(void)
+{
+ exit(20);
+}
+#endif
+
+local int is_running_on_windows(void)
+{
+ char * var = getenv("OS");
+
+ /* if the OS env.var says 'Windows_NT' then */
+ /* we're likely running on a variant of WinNT */
+
+ if ((NULL != var) && (0 == strcmp("Windows_NT", var)))
+ {
+ return 1;
+ }
+
+ /* if the windir env.var is non-null then */
+ /* we're likely running on a variant of Win9x */
+ /* DOS mode of Win9x doesn't define windir, only winbootdir */
+ /* NT's command.com can't see lowercase env. vars */
+
+ var = getenv("windir");
+ if ((NULL != var) && (0 != var[0]))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+void check_for_windows(char *app)
+{
+ /* Print a warning for users running under Windows */
+ /* to reduce bug reports due to running DOS version */
+ /* under Windows, when Windows version usually works correctly */
+
+ /* This is only called from the DOS version */
+
+ if (is_running_on_windows())
+ {
+ printf("\nzip warning: You are running MSDOS %s on Windows.\n"
+ "Try the Windows version before reporting any problems.\n",
+ app);
+ }
+}
+
+#endif /* !UTIL */
+
+
+#ifndef WINDLL
+/******************************/
+/* Function version_local() */
+/******************************/
+
+static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
+ /* At module level to keep Turbo C++ 1.0 happy !! */
+
+void version_local()
+{
+#if defined(__DJGPP__) || defined(__WATCOMC__) || \
+ (defined(_MSC_VER) && (_MSC_VER != 800))
+ char buf[80];
+#endif
+
+/* Define the compiler name and version strings */
+#if defined(__GNUC__)
+# if defined(__DJGPP__)
+ sprintf(buf, "djgpp v%d.%02d / gcc ", __DJGPP__, __DJGPP_MINOR__);
+# define COMPILER_NAME1 buf
+# elif defined(__GO32__) /* __GO32__ is defined as "1" only (sigh) */
+# define COMPILER_NAME1 "djgpp v1.x / gcc "
+# elif defined(__EMX__) /* ...so is __EMX__ (double sigh) */
+# define COMPILER_NAME1 "emx+gcc "
+# else
+# define COMPILER_NAME1 "gcc "
+# endif
+# define COMPILER_NAME2 __VERSION__
+#elif defined(__WATCOMC__)
+# if (__WATCOMC__ % 10 > 0)
+/* We do this silly test because __WATCOMC__ gives two digits for the */
+/* minor version, but Watcom packaging prefers to show only one digit. */
+ sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
+ __WATCOMC__ % 100);
+# else
+ sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
+ (__WATCOMC__ % 100) / 10);
+# endif
+# define COMPILER_NAME1 buf
+# define COMPILER_NAME2 ""
+#elif defined(__TURBOC__)
+# ifdef __BORLANDC__
+# define COMPILER_NAME1 "Borland C++"
+# if (__BORLANDC__ < 0x0200)
+# define COMPILER_NAME2 " 1.0"
+# elif (__BORLANDC__ == 0x0200) /* James: __TURBOC__ = 0x0297 */
+# define COMPILER_NAME2 " 2.0"
+# elif (__BORLANDC__ == 0x0400)
+# define COMPILER_NAME2 " 3.0"
+# elif (__BORLANDC__ == 0x0410) /* __BCPLUSPLUS__ = 0x0310 */
+# define COMPILER_NAME2 " 3.1"
+# elif (__BORLANDC__ == 0x0452) /* __BCPLUSPLUS__ = 0x0320 */
+# define COMPILER_NAME2 " 4.0 or 4.02"
+# elif (__BORLANDC__ == 0x0460) /* __BCPLUSPLUS__ = 0x0340 */
+# define COMPILER_NAME2 " 4.5"
+# elif (__BORLANDC__ == 0x0500) /* __TURBOC__ = 0x0500 */
+# define COMPILER_NAME2 " 5.0"
+# else
+# define COMPILER_NAME2 " later than 5.0"
+# endif
+# else
+# define COMPILER_NAME1 "Turbo C"
+# if (__TURBOC__ > 0x0401)
+# define COMPILER_NAME2 "++ later than 3.0"
+# elif (__TURBOC__ == 0x0401) /* Kevin: 3.0 -> 0x0401 */
+# define COMPILER_NAME2 "++ 3.0"
+# elif (__TURBOC__ == 0x0296) /* [662] checked by SPC */
+# define COMPILER_NAME2 "++ 1.01"
+# elif (__TURBOC__ == 0x0295) /* [661] vfy'd by Kevin */
+# define COMPILER_NAME2 "++ 1.0"
+# elif (__TURBOC__ == 0x0201) /* Brian: 2.01 -> 0x0201 */
+# define COMPILER_NAME2 " 2.01"
+# elif ((__TURBOC__ >= 0x018d) && (__TURBOC__ <= 0x0200)) /* James: 0x0200 */
+# define COMPILER_NAME2 " 2.0"
+# elif (__TURBOC__ > 0x0100)
+# define COMPILER_NAME2 " 1.5" /* James: 0x0105? */
+# else
+# define COMPILER_NAME2 " 1.0" /* James: 0x0100 */
+# endif
+# endif
+#elif defined(MSC)
+# if defined(_QC) && !defined(_MSC_VER)
+# define COMPILER_NAME1 "Microsoft Quick C"
+# define COMPILER_NAME2 "" /* _QC is defined as 1 */
+# else
+# define COMPILER_NAME1 "Microsoft C "
+# ifdef _MSC_VER
+# if (_MSC_VER == 800)
+# define COMPILER_NAME2 "8.0/8.0c (Visual C++ 1.0/1.5)"
+# else
+# define COMPILER_NAME2 \
+ (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf)
+# endif
+# else
+# define COMPILER_NAME2 "5.1 or earlier"
+# endif
+# endif
+#else
+# define COMPILER_NAME1 "unknown compiler"
+# define COMPILER_NAME2 ""
+#endif
+
+/* Define the OS name and memory environment strings */
+#if defined(__WATCOMC__) || defined(__TURBOC__) || defined(MSC) || \
+ defined(__GNUC__)
+# define OS_NAME1 "\nMS-DOS"
+#else
+# define OS_NAME1 "MS-DOS"
+#endif
+
+#if (defined(__GNUC__) || (defined(__WATCOMC__) && defined(__386__)))
+# define OS_NAME2 " (32-bit)"
+#elif defined(M_I86HM) || defined(__HUGE__)
+# define OS_NAME2 " (16-bit, huge)"
+#elif defined(M_I86LM) || defined(__LARGE__)
+# define OS_NAME2 " (16-bit, large)"
+#elif defined(M_I86MM) || defined(__MEDIUM__)
+# define OS_NAME2 " (16-bit, medium)"
+#elif defined(M_I86CM) || defined(__COMPACT__)
+# define OS_NAME2 " (16-bit, compact)"
+#elif defined(M_I86SM) || defined(__SMALL__)
+# define OS_NAME2 " (16-bit, small)"
+#elif defined(M_I86TM) || defined(__TINY__)
+# define OS_NAME2 " (16-bit, tiny)"
+#else
+# define OS_NAME2 " (16-bit)"
+#endif
+
+/* Define the compile date string */
+#ifdef __DATE__
+# define COMPILE_DATE " on " __DATE__
+#else
+# define COMPILE_DATE ""
+#endif
+
+ printf(CompiledWith, COMPILER_NAME1, COMPILER_NAME2,
+ OS_NAME1, OS_NAME2, COMPILE_DATE);
+
+} /* end function version_local() */
+#endif /* !WINDLL */
+
+
+#if 0 /* inserted here for future use (clearing of archive bits) */
+#if (defined(__GO32__) && (!defined(__DJGPP__) || (__DJGPP__ < 2)))
+
+#include <errno.h>
+int volatile _doserrno;
+
+unsigned _dos_setfileattr(char *name, unsigned attr)
+{
+#if 0 /* stripping of trailing '/' is not needed for zip-internal use */
+ unsigned namlen = strlen(name);
+ char *i_name = alloca(namlen + 1);
+
+ strcpy(i_name, name);
+ if (namlen > 1 && i_name[namlen-1] == '/' && i_name[namlen-2] != ':')
+ i_name[namlen-1] = '\0';
+ asm("movl %0, %%edx": : "g" (i_name));
+#else
+ asm("movl %0, %%edx": : "g" (name));
+#endif
+ asm("movl %0, %%ecx": : "g" (attr));
+ asm("movl $0x4301, %eax");
+ asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
+ _doserrno = 0;
+ asm("jnc 1f");
+ asm("movl %%eax, %0": "=m" (_doserrno));
+ switch (_doserrno) {
+ case 2:
+ case 3:
+ errno = ENOENT;
+ break;
+ case 5:
+ errno = EACCES;
+ break;
+ }
+ asm("1:");
+ return (unsigned)_doserrno;
+}
+
+#endif /* DJGPP v1.x */
+#endif /* never (not yet used) */
+
+
+#if (defined(__DJGPP__) && (__DJGPP__ >= 2))
+
+/* Disable determination of "x" bit in st_mode field for [f]stat() calls. */
+int _is_executable (const char *path, int fhandle, const char *ext)
+{
+ return 0;
+}
+
+/* Prevent globbing of filenames. This gives the same functionality as
+ * "stubedit <program> globbing=no" did with DJGPP v1.
+ */
+#ifndef USE_DJGPP_GLOB
+char **__crt0_glob_function(char *_arg)
+{
+ return NULL;
+}
+#endif
+
+/* Reduce the size of the executable and remove the functionality to read
+ * the program's environment from whatever $DJGPP points to.
+ */
+#if !defined(USE_DJGPP_ENV) || defined(UTIL)
+void __crt0_load_environment_file(char *_app_name)
+{
+}
+#endif
+
+#endif /* __DJGPP__ >= 2 */
+
+
+#if defined(_MSC_VER) && _MSC_VER == 700
+
+/*
+ * ARGH. MSC 7.0 libraries think times are based on 1899 Dec 31 00:00, not
+ * 1970 Jan 1 00:00. So we have to diddle time_t's appropriately: add
+ * 70 years' worth of seconds for localtime() wrapper function;
+ * (70*365 regular days + 17 leap days + 1 1899 day) * 86400 ==
+ * (25550 + 17 + 1) * 86400 == 2209075200 seconds.
+ * Let time() and stat() return seconds since 1970 by using our own
+ * _dtoxtime() which is the routine that is called by these two functions.
+ */
+
+
+#ifdef UTIL
+# include <time.h>
+#endif
+
+#ifndef UTIL
+#undef localtime
+struct tm *localtime(const time_t *);
+
+struct tm *msc7_localtime(const time_t *clock)
+{
+ time_t t = *clock;
+
+ t += 2209075200L;
+ return localtime(&t);
+}
+#endif /* !UTIL */
+
+
+void __tzset(void);
+int _isindst(struct tm *);
+
+extern int _days[];
+
+/* Nonzero if `y' is a leap year, else zero. */
+#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/* Number of leap years from 1970 to `y' (not including `y' itself). */
+#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+
+time_t _dtoxtime(year, month, mday, hour, min, sec)
+int year, month, mday, year, hour, min, sec;
+{
+ struct tm tm;
+ time_t t;
+ int days;
+
+ days = _days[month - 1] + mday;
+ year += 1980;
+ if (leap(year) && month > 2)
+ ++days;
+ tm.tm_yday = days;
+ tm.tm_mon = month - 1;
+ tm.tm_year = year - 1900;
+ tm.tm_hour = hour;
+ __tzset();
+ days += 365 * (year - 1970) + nleap (year);
+ t = 86400L * days + 3600L * hour + 60 * min + sec + _timezone;
+ if (_daylight && _isindst(&tm))
+ t -= 3600;
+ return t;
+}
+
+#endif /* _MSC_VER && _MSC_VER == 700 */
+
+
+#ifdef __WATCOMC__
+
+/* This papers over a bug in Watcom 10.6's standard library... sigh */
+/* Apparently it applies to both the DOS and Win32 stat()s. */
+
+int stat_bandaid(const char *path, struct stat *buf)
+{
+ char newname[4];
+ if (!stat(path, buf))
+ return 0;
+ else if (!strcmp(path, ".") || (path[0] && !strcmp(path + 1, ":."))) {
+ strcpy(newname, path);
+ newname[strlen(path) - 1] = '\\'; /* stat(".") fails for root! */
+ return stat(newname, buf);
+ } else
+ return -1;
+}
+
+#endif
diff --git a/msdos/osdep.h b/msdos/osdep.h
new file mode 100644
index 0000000..0e0f23f
--- /dev/null
+++ b/msdos/osdep.h
@@ -0,0 +1,218 @@
+/*
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* The symbol DOS is used throughout the Zip source to identify code portions
+ * specific to the MSDOS port.
+ * Just to make sure, we check that it is set.
+ * (Currently, this should should not be neccessary, since currently it has
+ * to be set on the compiler command line to get this file read in.)
+ */
+#ifndef DOS
+# define DOS
+#endif
+
+/* The symbol MSDOS is consistently used in the generic source files
+ * to identify code to support for MSDOS (and MSDOS related) stuff.
+ * e.g: FAT or (FAT like) file systems,
+ * '\\' as directory separator in paths,
+ * "\r\n" as record (line) terminator in text files, ...
+ *
+ * IMPORTANT Note:
+ * This symbol is not unique for the MSDOS port !!!!!!
+ * It is also defined by ports to some other OS which are (to some extend)
+ * considered DOS compatible.
+ * Examples are: OS/2 (OS2), Windows NT and Windows 95 (WIN32).
+ *
+ */
+#ifndef MSDOS
+# define MSDOS
+#endif
+
+/* Power C is similar to Turbo C */
+#ifdef __POWERC
+# define __TURBOC__
+#endif /* __POWERC */
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+# ifndef MSC
+# define MSC /* This should work for older MSC, too! */
+# endif
+#endif
+
+#if !defined(__GO32__) && !defined(__EMX__)
+# define NO_UNISTD_H
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+# define WATCOMC_386
+#endif
+
+#ifdef WINDLL
+# define MSWIN
+# define MEMORY16
+#endif
+
+
+#if !defined(__EMX__) && !defined(__GO32__) && !defined(WATCOMC_386)
+#if !defined(WINDLL)
+# define MSDOS16 /* 16 bit MSDOS only */
+# define MEMORY16
+#endif
+#endif
+
+#if !defined(NO_ASM) && !defined(ASMV)
+# define ASMV
+#endif
+
+/* enable creation of UTC time fields unless explicitely suppressed */
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+# define USE_EF_UT_TIME
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+# define IZ_CHECK_TZ
+#endif
+
+#ifdef MEMORY16
+# ifndef NO_ASM
+# define ASM_CRC 1
+# endif /* ?NO_ASM */
+# ifdef __TURBOC__
+# include <alloc.h>
+# if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
+# if defined(DYNAMIC_CRC_TABLE) && defined(DYNALLOC_CRCTAB)
+ error: No dynamic CRC table allocation with Borland C far data models.
+# endif /* DYNAMIC_CRC_TABLE */
+# endif /* Turbo/Borland C far data memory models */
+# define nearmalloc malloc
+# define nearfree free
+# define DYN_ALLOC
+# else /* !__TURBOC__ */
+# include <malloc.h>
+# define nearmalloc _nmalloc
+# define nearfree _nfree
+# define farmalloc _fmalloc
+# define farfree _ffree
+# endif /* ?__TURBOC__ */
+# define MY_ZCALLOC 1
+# ifdef SMALL_MEM
+# define CBSZ 2048
+# define ZBSZ 2048
+# endif
+# ifdef MEDIUM_MEM
+# define CBSZ 4096
+# define ZBSZ 4096
+# endif
+# ifndef CBSZ
+# define CBSZ 8192
+# define ZBSZ 8192
+# endif
+#endif /* MEMORY16 */
+
+
+/* Symbolic links are not supported, but some compilers may define S_IFLNK. */
+#ifndef NO_SYMLINKS
+# define NO_SYMLINKS
+#endif
+
+#ifdef MATCH
+# undef MATCH
+#endif
+#define MATCH dosmatch /* use DOS style wildcard matching */
+
+#define USE_CASE_MAP
+
+#define ROUNDED_TIME(time) (((time) + 1) & (~1))
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifdef ZCRYPT_INTERNAL
+# ifdef WINDLL
+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as seed pattern */
+# else
+# ifndef __GO32__
+# include <process.h> /* getpid() declaration for srand seed */
+# endif
+# endif
+#endif
+
+/*
+ * djgpp 1.x did not declare these
+ */
+#if defined(__GO32__) && !defined(__DJGPP__)
+char *strlwr(char *);
+int setmode(int, int);
+#endif
+
+#ifdef __WATCOMC__
+# define NO_MKTEMP
+# define HAS_OPENDIR
+# define SSTAT stat_bandaid
+ int stat_bandaid(const char *path, struct stat *buf);
+
+/* Get asm routines to link properly without using "__cdecl": */
+# ifdef __386__
+# ifdef ASMV
+# pragma aux match_init "_*" parm caller [] modify []
+# pragma aux longest_match "_*" parm caller [] value [eax] \
+ modify [eax ecx edx]
+# endif
+# ifndef USE_ZLIB
+# pragma aux crc32 "_*" parm caller [] value [eax] modify [eax]
+# pragma aux get_crc_table "_*" parm caller [] value [eax] \
+ modify [eax ecx edx]
+# endif /* !USE_ZLIB */
+# else /* !__386__ */
+# ifdef ASMV
+# pragma aux match_init "_*" parm caller [] loadds modify [ax bx]
+# pragma aux longest_match "_*" parm caller [] loadds value [ax] \
+ modify [ax bx cx dx es]
+# endif /* ASMV */
+# ifndef USE_ZLIB
+# pragma aux crc32 "_*" parm caller [] value [ax dx] \
+ modify [ax bx cx dx es]
+# pragma aux get_crc_table "_*" parm caller [] value [ax] \
+ modify [ax bx cx dx]
+# endif /* !USE_ZLIB */
+# endif /* ?__386__ */
+#endif /* __WATCOMC__ */
+
+/*
+ * Wrapper function to get around the MSC7 00:00:00 31 Dec 1899 time base,
+ * see msdos.c for more info
+ */
+
+#if defined(_MSC_VER) && _MSC_VER == 700
+# define localtime(t) msc7_localtime(t)
+#endif
+
+#ifdef __TURBOC__
+# ifdef __FILEIO_C
+# include <dir.h> /* supplies mktemp() prototype */
+# endif
+#endif
+
+#if (defined(__TURBOC__) && !defined(__BORLANDC__) && __TURBOC__ <= 0x0201)
+# ifndef NO_MKTIME
+# define NO_MKTIME /* TC 2.01 and earlier do not supply mktime() */
+# endif
+#endif
+
+void check_for_windows(char *app);
diff --git a/msdos/zipup.h b/msdos/zipup.h
new file mode 100644
index 0000000..78b428a
--- /dev/null
+++ b/msdos/zipup.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/novell/MAKEINIT b/novell/MAKEINIT
new file mode 100644
index 0000000..f9929e7
--- /dev/null
+++ b/novell/MAKEINIT
@@ -0,0 +1,71 @@
+#
+# makeinit file for makefiles created with QMK386
+#
+# Novell's NetWare SDK - Release 15
+#
+# Directories for both the WATCOM and NOVELL tools
+#
+wat386loc = e:\watcom\
+nlm386loc = c:\novell\ndk\nwsdk\
+nlm386hdr = $(nlm386loc)INCLUDE\NLM;$(nlm386loc)INCLUDE;.
+nlm386imp = $(nlm386loc)IMPORTS
+nlm386lib = $(wat386loc)LIB386;$(wat386loc)LIB386\NETWARE
+#
+# Define this macro with your copyright statement
+#
+#copyright = (C) Copyright 199x NONAME, INC. All Rights Reserved
+#
+# Macros that point to various tools we'll need to compile
+#
+wcc386r = WCC386 # location of 386 real mode compiler
+wcc386p = WCC386P # protected compiler (last avail on Watcom v9.5
+wcc386 = $(wcc386r) # version we want to use
+
+linkr = WLINK # location of real mode linker
+linkp = WLINKP # protected linker (last avail on Watcom v9.5
+linker = $(linkr) # version we want to use
+nlmlinkr = $(nlm386loc)TOOLS\NLMLINKR # location of real mode Novell linker
+nlmlinkp = $(nlm386loc)TOOLS\NLMLINKX # location of protected Novell linker
+nlmlinker = $(nlmlinkr) # version we want to use
+
+nlmpackr = $(nlm386loc)TOOLS\NLMPACK # location of real mode NLM compression utility
+nlmpackp = $(nlm386loc)TOOLS\NLMPACKP # location of protected NLM compression utility
+nlmpack = $(nlmpackr) # location of NLM compression utility
+
+inc_386 = $(nlm386hdr)
+lib_386 = $(nlm386lib)
+code_386 = $(wat386loc)BIN\386WCGL.EXE # code generator (last avail on Watcom v9.01
+librarian = $(wat386loc)BINB\WLIB # location of librarian
+#
+# NLM Import Files
+#
+startup = $(nlm386imp)\PRELUDE.OBJ # other option is nwpre.obj
+allimp = $(nlm386imp)\ALL.IMP # import to include all imports
+clibimp = $(nlm386imp)\CLIB.IMP # the clib import file
+tliimp = $(nlm386imp)\TLI.IMP # the tli import file
+aioimp = $(nlm386imp)\AIO.IMP # the aio import file
+socklibimp = $(nlm386imp)\SOCKLIB.IMP # the socket import file
+mathlibimp = $(nlm386imp)\MATHLIB.IMP # the math library import file
+dsapiimp = $(nlm386imp)\DSAPI.IMP # the NDS import file
+nutimp = $(nlm386imp)\NWSNUT.IMP # the NWSNUT import file
+appleimp = $(nlm386imp)\APPLTLK.IMP # the AppleTalk import file
+nitimp = $(nlm386imp)\NIT.IMP # the legacy NLM import file
+nlmlibimp = $(nlm386imp)\NLMLIB.IMP # the NLM-specific import file
+requesterimp = $(nlm386imp)\REQUESTR.IMP # the Requester import file
+fpsmimp = $(nlm386imp)\FPSM.IMP # floating point support import file
+threadsimp = $(nlm386imp)\THREADS.IMP # the threads import file
+dseventimp = $(nlm386imp)\DSEVENT.IMP # DS Events import file
+psrvimp = $(nlm386imp)\NWPSRV.IMP # print services import file
+psrv3ximp = $(nlm386imp)\NWPSRV3X.IMP # 3.x print services import file
+streamsimp = $(nlm386imp)\STREAMS.IMP # streams import file
+unicodeimp = $(nlm386imp)\UNICODE.IMP # unicode import file
+agentimp = $(nlm386imp)\agent.imp # SNMP Agent import file
+smileimp = $(nlm386imp)\smile.imp # SMILE (SNMP) import file
+#
+# Cross-platform Import Files
+#
+audnlm32imp = $(nlm386imp)\AUDNLM32.IMP # auditing import file
+calnlm32imp = $(nlm386imp)\CALNLM32.IMP # NWCALLS import file
+clxnlm32imp = $(nlm386imp)\CLXNLM32.IMP # NWCLIENT import file
+locnlm32imp = $(nlm386imp)\LOCNLM32.IMP # NWLOCALE import file
+netnlm32imp = $(nlm386imp)\NETNLM32.IMP # NWNET import file
diff --git a/novell/Makefile b/novell/Makefile
new file mode 100644
index 0000000..c88bf86
--- /dev/null
+++ b/novell/Makefile
@@ -0,0 +1,142 @@
+#
+# This makefile was generated by QMK386 v2.14
+#
+# Program: unzip.NLM
+# This makefile rebuilds the zip NetWare Loadable Module
+#
+# Created: Sun Jan 03 03:54:03 1999
+#
+# MAKEINIT defines many of the macros used herein
+# The following macros can be set via your environment:
+# CCF386 : Set compile options
+# QMKVER : Set to 'd' or 'p' to define VERSION
+# SILENT : If defined, .SILENT will be set
+#
+# The following macros are defined for your program:
+# vMAJ : Major version number
+# vMIN : Minor version number
+# vREV : Revision number
+
+!ifdef %SILENT
+.silent
+!endif
+
+program = zip
+
+pvmaj = 1 # major version number
+pvmin = 00 # minor version number
+pvrev = 3 # revision number e.g. 0,1,2, ...
+
+!ifndef %qmkver
+! define version p # use 'd' or 'p' here
+!else
+! define version $(%qmkver)
+!endif
+!ifeq version d
+! define lversion DEBUG
+! define debug /dDEBUG
+!else
+! define lversion PRODUCTION
+! define debug
+!endif
+
+nlm_TYPE = Form Novell NLM '$(program)'
+nlm_NAME = Name $^&
+nlm_SCREEN = Op ScreenName '$(program)'
+nlm_THREAD = Op ThreadName '$^&__P '
+nlm_STACK = Op Stack = 8k
+nlm_NLMVER = Op Version = $(pvmaj).$(pvmin).$(pvrev)
+nlm_COPYRIGHT = Op Copyright '$(copyright)'
+linkop = $+$(linkop)$- Caseexact
+linkop = $+$(linkop)$- Nod
+!ifeq version d
+! define linkop $+$(linkop)$- Map
+! define linkop $+$(linkop)$- Verbose
+! define ldebug debug all debug novell
+!endif
+
+objlst = BITS.OBJ
+objlst = $+$(objlst)$- CRC32.OBJ
+objlst = $+$(objlst)$- CRYPT.OBJ
+objlst = $+$(objlst)$- DEFLATE.OBJ
+objlst = $+$(objlst)$- FILEIO.OBJ
+objlst = $+$(objlst)$- GLOBALS.OBJ
+objlst = $+$(objlst)$- MKTIME.OBJ
+objlst = $+$(objlst)$- NETWARE.OBJ
+objlst = $+$(objlst)$- SIGNAL.OBJ
+objlst = $+$(objlst)$- TREES.OBJ
+objlst = $+$(objlst)$- TTYIO.OBJ
+objlst = $+$(objlst)$- UTIL.OBJ
+objlst = $+$(objlst)$- ZIP.OBJ
+objlst = $+$(objlst)$- ZIPFILE.OBJ
+objlst = $+$(objlst)$- ZIPUP.OBJ
+objlst = $+$(objlst)$- $(startup)
+
+import = $(allimp)
+
+module = CLib
+
+build_msg = Building a $(lversion) version of $(program)
+
+pgm_ver = /dvMAJ="$(pvmaj)" /dvMIN="$(pvmin)" /dvREV="$(pvrev)"
+
+!ifndef %ccf386
+! define d_wcc386opt /ms /w4 /e99 /zp1 /3s /ot /d2 /dN_PLAT_NLM /d_FIND_OLD_HEADERS -dNO_ASM -dNLM $(debug)
+! define p_wcc386opt /ms /w4 /s /zp1 /3s /oaxt /dN_PLAT_NLM /d_FIND_OLD_HEADERS -dNO_ASM -dNLM
+! define x_wcc386opt $($(version)_wcc386opt) $(pgm_ver)
+!else
+! define x_wcc386opt $(%ccf386)
+!endif
+
+compiler_cmd = $(wcc386) $(x_wcc386opt) $[*.c
+
+.BEFORE
+ echo $(build_msg)
+ set inc386=$(inc_386)
+ set lib386=$(lib_386)
+ set wcg386=$(code_386)
+
+.c.obj:
+ $(compiler_cmd)
+
+zip.nlm : $(objlst) zip.LNK
+ $(linker) @zip
+
+zip.LNK : MAKEFILE
+ if exist $^&.LNK del $^&.LNK
+ %append $^&.LNK $(nlm_TYPE)
+ %append $^&.LNK $(nlm_NAME)
+ %append $^&.LNK $(nlm_SCREEN)
+ %append $^&.LNK $(nlm_THREAD)
+ %append $^&.LNK $(nlm_STACK)
+ %append $^&.LNK $(nlm_NLMVER)
+!ifdef copyright
+ %append $^&.LNK $(nlm_COPYRIGHT)
+!endif
+!ifdef ldebug
+ %append $^&.LNK $(ldebug)
+!endif
+ for %i in ($(linkop)) do %append $^&.LNK Op %i
+ for %i in ($(objlst)) do %append $^&.LNK File %i
+ for %i in ($(import)) do %append $^&.LNK Import @%i
+ for %i in ($(export)) do %append $^&.LNK Export @%i
+ for %i in ($(module)) do %append $^&.LNK Module %i
+ for %i in ($(library)) do %append $^&.LNK Library %i
+
+clean : .symbolic
+ del *.MAP
+ del *.OBJ
+ del *.ERR
+ del *.LNK
+ del *.NLM
+
+zip : .symbolic
+ -pkzip -u zip MAKEFILE *.c *.h
+
+unzip : .symbolic
+ -pkunzip -n -d zip
+
+save : .symbolic
+ %make zip
+ %make clean
+
diff --git a/novell/Netware.c b/novell/Netware.c
new file mode 100644
index 0000000..20efa16
--- /dev/null
+++ b/novell/Netware.c
@@ -0,0 +1,970 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ntypes.h>
+#include <nwconio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <nit\nwdir.h>
+#include <dirent.h>
+#include <nwnamspc.h>
+#include <locale.h>
+#include <nwlocale.h>
+#include <time.h>
+
+extern void UseAccurateCaseForPaths(int);
+
+#include "zip.h"
+
+ /*------------------------------------------------------------------
+ ** Global Variables
+ */
+
+#define skipspace( x ) while( isspace( *x ) ) ++x
+#define nextspace( x ) while( *x && !isspace( *x ) ) ++x
+#define CWS 0
+#define CWV 1
+#define CWP 2
+#define ALL 99
+
+/* Globals */
+extern char *GetWorkArea(void);
+extern char *next_arg(char *);
+extern int NLM_exiting;
+char fid[100];
+static breakkey = FALSE;
+
+#define MATCH shmatch
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+#define PAD 0
+#define PATH_END '/'
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+void findzip(char *s)
+{
+ dowhereis(s);
+}
+
+void dowhereis(char *s)
+{
+ char dir[_MAX_PATH];
+ char fsv[_MAX_SERVER+_MAX_VOLUME+1];
+ char fdir[_MAX_PATH];
+ char fname[_MAX_FNAME],fext[_MAX_EXT], both[_MAX_FNAME+_MAX_EXT];
+ char *p = next_arg(s); /* point at argument */
+
+ if(!*p)
+ {
+ printf("No filename specified!");
+ return;
+ }
+
+ //setlocale (LC_ALL, "NORWAY");
+ NWLsetlocale (LC_ALL, "NORWAY");
+
+ strcpy(dir,GetWorkArea());
+
+ /* get the file name specification */
+ _splitpath(p,fsv,fdir,fname,fext);
+
+ //printf ("p %s, fsv %s, fdir %s, fname %s, fext %s\n", p,fsv,fdir,fname,fext);
+ //getch();
+
+ sprintf(both,"%s%s",strupr(fname),strupr(fext));
+
+ breakkey = FALSE;
+
+ /* startup the recursive file find operation */
+ chdir(fsv);
+ UseAccurateCaseForPaths(1);
+ SetCurrentNameSpace (NW_NS_LONG);
+ chdir(fdir);
+ findit(both);
+}
+
+char *GetWorkArea(void)
+{
+ static char cwd[_MAX_PATH];
+ static char serverName[_MAX_SERVER];
+ static char volumeName[_MAX_VOLUME + 1];
+ static char dirName[_MAX_DIR];
+
+ if(getcwd(cwd,_MAX_PATH) == NULL)
+ return NULL;
+
+ ParsePath(cwd,serverName,volumeName,dirName); /* shouldn't fail! */
+
+ return cwd;
+}
+
+char *next_arg(char *s)
+{
+ char *p;
+
+ skipspace(s); /* ignore white */
+ p = s;
+ nextspace(s); /* find next blank */
+ *s = NULL;
+ return(p);
+}
+
+static void findit(char *what)
+{
+ char dir[_MAX_PATH];
+ char zipdir[_MAX_PATH];
+ char szzipfile[_MAX_PATH];
+ char *psz;
+ DIR *dirStructPtr;
+ DIR *dirStructPtrSave;
+ int r;
+
+ getcwd(dir,_MAX_PATH);
+
+ psz = dir;
+
+ while (*psz)
+ {
+ if (*psz == ':')
+ {
+ strcpy (zipdir, psz + 1);
+ break;
+ }
+ psz++;
+ }
+
+ dirStructPtrSave = dirStructPtr = opendir(what);
+
+ /*
+ _A_NORMAL Normal file; read/write permitted
+ _A_RDONLY Read-only file
+ _A_HIDDEN Hidden file
+ _A_SYSTEM System file
+ _A_VOLID Volume ID entry
+ _A_SUBDIR Subdirectory
+ _A_ARCH Archive file
+ */
+
+ if (hidden_files)
+ SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
+ else
+ SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_ARCH);
+
+ //while(dirStructPtr && !breakkey)
+ while(dirStructPtr && !NLM_exiting)
+ {
+ //printf ("\n NLM_exiting test Line 167.... \n");
+
+ dirStructPtr = readdir(dirStructPtr);
+ if((dirStructPtr == NULL) || (dirStructPtr == -1))
+ break;
+
+ /* Filen er funnet */
+ if(dirStructPtr->d_attr & _A_SUBDIR)
+ continue;
+
+ strcpy (szzipfile, zipdir);
+ strcat (szzipfile, "/");
+ strcat (szzipfile, dirStructPtr->d_name);
+ procnamehho (szzipfile);
+
+ //ThreadSwitchWithDelay();
+
+ //if(kbhit() && getch() == 3)
+ // printf("^C\n",breakkey = TRUE);
+ }
+
+ if(dirStructPtrSave)
+ closedir(dirStructPtrSave);
+
+ if (!recurse)
+ return;
+
+ /* Now traverse the directories in this path */
+
+ dirStructPtrSave = dirStructPtr = opendir("*.*");
+ if(dirStructPtr == NULL)
+ return;
+
+ if (hidden_files)
+ SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH | _A_SUBDIR);
+ else
+ SetReaddirAttribute (dirStructPtr, _A_NORMAL | _A_ARCH | _A_SUBDIR);
+
+ //ThreadSwitchWithDelay();
+
+ while(!NLM_exiting)
+ {
+ //printf ("\n NLM_exiting test Line 204.... \n"); getch ();
+
+ dirStructPtr = readdir(dirStructPtr);
+ if((dirStructPtr == NULL) || (dirStructPtr == -1))
+ break;
+
+ if(dirStructPtr->d_attr & _A_SUBDIR)
+ {
+ strcpy (szzipfile, zipdir);
+ strcat (szzipfile, "/");
+ strcat (szzipfile, dirStructPtr->d_name);
+ procnamehho (szzipfile);
+
+ chdir(dirStructPtr->d_name);
+ findit(what);
+ chdir("..");
+ }
+
+ //if(kbhit() && getch() == 3)
+ // printf("^C\n",breakkey = TRUE);
+ }
+
+ if(dirStructPtrSave)
+ closedir(dirStructPtrSave);
+}
+
+
+int wild(w)
+char *w; /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+ file system. Return an error code in the ZE_ class. */
+{
+ DIR *d; /* stream for reading directory */
+ char *e; /* name found in directory */
+ int r; /* temporary variable */
+ char *n; /* constructed name from directory */
+ int f; /* true if there was a match */
+ char *a; /* alloc'ed space for name */
+ //char *p; /* path */
+ char *q; /* name */
+ char v[5]; /* space for device current directory */
+
+
+ char dir[_MAX_PATH];
+ char fsv[_MAX_SERVER+_MAX_VOLUME+1];
+ char fdir[_MAX_PATH];
+ char fname[_MAX_FNAME],fext[_MAX_EXT], both[_MAX_FNAME+_MAX_EXT];
+ char *p; /* point at argument */
+
+ p = w;
+
+
+ /* Test HHO */
+ findzip(p);
+
+ return ZE_OK;
+
+
+ strcpy(dir,GetWorkArea());
+
+ /* get the file name specification */
+
+ _splitpath(p,fsv,fdir,fname,fext);
+ sprintf(both,"%s%s",strupr(fname),strupr(fext));
+
+ /* startup the recursive file find operation */
+
+ chdir(fsv);
+
+ /* Search that level for matching names */
+ if ((d = opendir(both)) == NULL)
+ {
+ free((zvoid *)a);
+ return ZE_MISS;
+ }
+
+ f = 0;
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
+ {
+ f = 1;
+ if (strcmp(p, ".") == 0) { /* path is . */
+ r = procname(e); /* name is name */
+ if (r) {
+ f = 0;
+ break;
+ }
+ } else
+ {
+ if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
+ {
+ free((zvoid *)a);
+ closedir(d);
+ return ZE_MEM;
+ }
+ n = strcpy(n, p);
+ if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
+ strcat(n, "/");
+ r = procname(strcat(n, e)); /* name is path/name */
+ free((zvoid *)n);
+ if (r) {
+ f = 0;
+ break;
+ }
+ }
+ }
+ }
+ closedir(d);
+
+ /* Done */
+ free((zvoid *)a);
+ return f ? ZE_OK : ZE_MISS;
+}
+
+int procnamehho (char *n)
+{
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ char *a;
+
+ if (n == NULL) /* volume_label request in freshen|delete mode ?? */
+ return ZE_OK;
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0);
+ else if (stat(n, &s)
+#if defined(__TURBOC__) || defined(__WATCOMC__)
+ /* For these 2 compilers, stat() succeeds on wild card names! */
+ || isshexp(n)
+#endif
+ )
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname))
+ {
+ z->mark = pcount ? filter(z->zname) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ for (p = n; *p; p++) /* use / consistently */
+ if (*p == '\\')
+ *p = '/';
+
+ //printf ("\nHHO %s\n", n);
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ //printf ("\nHHO1 %s\n", n);
+ /* add or remove name of file */
+ //printf ("\nAdding name %s to list.\n", n);
+ if ((m = newname(n, 0)) != ZE_OK)
+ return m;
+ } else {
+
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ //if (dirnames && (m = newname(p, 1)) != ZE_OK) {
+ if ((m = newname(p, 1)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ free ((zvoid *)p);
+ }
+
+ return ZE_OK;
+ }
+ return ZE_OK;
+}
+
+int procname(n)
+char *n; /* name to process */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (n == NULL) /* volume_label request in freshen|delete mode ?? */
+ return ZE_OK;
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0);
+ else if (stat(n, &s)
+#if defined(__TURBOC__) || defined(__WATCOMC__)
+ /* For these 2 compilers, stat() succeeds on wild card names! */
+ || isshexp(n)
+#endif
+ )
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname))
+ {
+ z->mark = pcount ? filter(z->zname) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ for (p = n; *p; p++) /* use / consistently */
+ if (*p == '\\')
+ *p = '/';
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *szRelativParameter;
+char szRelativ[512];
+int iRelativOK = FALSE;
+int iRelativPakking = FALSE;
+
+int fixRelativpath ()
+{
+ char *szp;
+
+ szp = szRelativParameter;
+
+ if (szRelativParameter[0] == '/' || szRelativParameter[0] == '\\')
+ szp++;
+
+ while (*szp) {
+ if (*szp == '\\')
+ *szp = '/';
+ szp++;
+ }
+
+ szp = szRelativParameter;
+ if (szRelativParameter[0] == '/')
+ szp++;
+
+ strcpy (szRelativ, szp);
+
+ if (strlen(szp) == 0) {
+ szRelativ[0] = '\0';
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+ char *sztUpper;
+
+
+ /* Find starting point in name before doing malloc */
+ t = *x && *(x + 1) == ':' ? x + 2 : x;
+ while (*t == '/' || *t == '\\')
+ t++;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ for (n = t; *n; n++)
+ if (*n == '\\')
+ *n = '/';
+
+ if (iRelativPakking) {
+ //printf ("\n LINE 516 *ex2ex Internt navn %s external name %s.\n", t, x); getch ();
+ if (!iRelativOK) {
+ if (!fixRelativpath()) {
+ iRelativOK = FALSE;
+ iRelativPakking = FALSE;
+ }
+ else {
+ sztUpper = malloc (strlen(t) + 10);
+ strcpy (sztUpper, t);
+ NWLstrupr (sztUpper);
+ NWLstrupr (szRelativ);
+ if (strncmp (sztUpper, szRelativ, strlen(szRelativ)) == 0) {
+ t = t + strlen(szRelativ);
+ iRelativPakking = TRUE;
+ iRelativOK = TRUE;
+ }
+ else {
+ iRelativOK = FALSE;
+ iRelativPakking = FALSE;
+ }
+ free (sztUpper);
+ }
+ }
+ else
+ {
+ t = t + strlen(szRelativ);
+ }
+ }
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+
+ //if ( !IsFileNameValid(x) )
+ //ChangeNameForFAT(x);
+
+ //printf ("\n *in2ex Internt navn %s external name %s.\n", n, x); getch ();
+
+ return x;
+}
+
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ //SetFileTime(f, d);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0)
+ error("fstat(stdin)");
+ }
+ else if (stat(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = s.st_attr; // << 16) | !(s.st_mode & S_IWRITE);
+ //*a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ //if ((s.st_mode & S_IFMT) == S_IFDIR) {
+ //*a |= MSDOS_DIR_ATTR;
+ //}
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = t->mtime; /* best guess, (s.st_ctime: last status change!!) */
+ }
+ return unix2dostime(&s.st_mtime);
+}
+
+
+ulg filetimeHHO(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ char *name;
+ int len = strlen(f), isstdin = !strcmp(f, "-");
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetimeHHO");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (isstdin) {
+ /* it is common for some PC based compilers to
+ fail with fstat() on devices or pipes */
+ if (fstat(fileno(stdin), &s) != 0) {
+ s.st_mode = S_IFREG; s.st_size = -1L;
+ }
+ time(&s.st_ctime);
+ s.st_atime = s.st_mtime = s.st_ctime;
+ } else if (stat(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+
+ if (a != NULL) {
+ //*a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+ //*a = (ulg)s.st_mode;
+ *a = s.st_attr;
+ }
+
+ printf ("\nDette er en test LINE : 721 \n"); getch();
+
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+#ifdef __WATCOMC__
+ /* of course, Watcom always has to make an exception */
+ if (s.st_atime == 312764400)
+ s.st_atime = s.st_mtime;
+ if (s.st_ctime == 312764400)
+ s.st_ctime = s.st_mtime;
+#endif
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ printf ("\nDette er en test LINE : 735 \n"); getch();
+
+ //return GetFileTime(name);
+ free(name);
+ return t->atime;
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ */
+{
+ return rmdir(d);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+ if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME;
+ z->extra[5] = (char)(z_utim->mtime);
+ z->extra[6] = (char)(z_utim->mtime >> 8);
+ z->extra[7] = (char)(z_utim->mtime >> 16);
+ z->extra[8] = (char)(z_utim->mtime >> 24);
+
+ z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+ z->cextra = z->extra;
+
+ return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+ return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+ /* At module level to keep Turbo C++ 1.0 happy !! */
+
+void version_local()
+{
+#if defined(__DJGPP__) || defined(__WATCOMC__) || \
+ (defined(_MSC_VER) && (_MSC_VER != 800))
+ char buf[80];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+# if defined(__DJGPP__)
+ (sprintf(buf, "djgpp v%d / gcc ", __DJGPP__), buf),
+# elif defined(__GO32__)
+ "djgpp v1.x / gcc ",
+# elif defined(__EMX__) /* ...so is __EMX__ (double sigh) */
+ "emx+gcc ",
+# else
+ "gcc ",
+# endif
+ __VERSION__,
+#elif defined(__WATCOMC__)
+# if (__WATCOMC__ % 10 > 0)
+/* We do this silly test because __WATCOMC__ gives two digits for the */
+/* minor version, but Watcom packaging prefers to show only one digit. */
+ (sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
+ __WATCOMC__ % 100), buf), "",
+# else
+ (sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
+ (__WATCOMC__ % 100) / 10), buf), "",
+# endif
+#elif defined(__TURBOC__)
+# ifdef __BORLANDC__
+ "Borland C++",
+# if (__BORLANDC__ < 0x0200)
+ " 1.0",
+# elif (__BORLANDC__ == 0x0200) /* James: __TURBOC__ = 0x0297 */
+ " 2.0",
+# elif (__BORLANDC__ == 0x0400)
+ " 3.0",
+# elif (__BORLANDC__ == 0x0410) /* __BCPLUSPLUS__ = 0x0310 */
+ " 3.1",
+# elif (__BORLANDC__ == 0x0452) /* __BCPLUSPLUS__ = 0x0320 */
+ " 4.0 or 4.02",
+# elif (__BORLANDC__ == 0x0460) /* __BCPLUSPLUS__ = 0x0340 */
+ " 4.5",
+# elif (__BORLANDC__ == 0x0500) /* __TURBOC__ = 0x0500 */
+ " 5.0",
+# else
+ " later than 5.0",
+# endif
+# else
+ "Turbo C",
+# if (__TURBOC__ > 0x0401)
+ "++ later than 3.0"
+# elif (__TURBOC__ == 0x0401) /* Kevin: 3.0 -> 0x0401 */
+ "++ 3.0",
+# elif (__TURBOC__ == 0x0295) /* [661] vfy'd by Kevin */
+ "++ 1.0",
+# elif ((__TURBOC__ >= 0x018d) && (__TURBOC__ <= 0x0200)) /* James: 0x0200 */
+ " 2.0",
+# elif (__TURBOC__ > 0x0100)
+ " 1.5", /* James: 0x0105? */
+# else
+ " 1.0", /* James: 0x0100 */
+# endif
+# endif
+#elif defined(MSC)
+ "Microsoft C ",
+# ifdef _MSC_VER
+# if (_MSC_VER == 800)
+ "(Visual C++ v1.1)",
+# elif (_MSC_VER == 850)
+ "(Windows NT v3.5 SDK)",
+# elif (_MSC_VER == 900)
+ "(Visual C++ v2.0/v2.1)",
+# elif (_MSC_VER > 900)
+ (sprintf(buf2, "(Visual C++ v%d.%d)", _MSC_VER/100 - 6,
+ _MSC_VER%100/10), buf2),
+# else
+ (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
+# endif
+# else
+ "5.1 or earlier",
+# endif
+#else
+ "unknown compiler", "",
+#endif
+
+ "MS-DOS",
+
+#if (defined(__GNUC__) || (defined(__WATCOMC__) && defined(__386__)))
+ " (32-bit)",
+#elif defined(M_I86HM) || defined(__HUGE__)
+ " (16-bit, huge)",
+#elif defined(M_I86LM) || defined(__LARGE__)
+ " (16-bit, large)",
+#elif defined(M_I86MM) || defined(__MEDIUM__)
+ " (16-bit, medium)",
+#elif defined(M_I86CM) || defined(__COMPACT__)
+ " (16-bit, compact)",
+#elif defined(M_I86SM) || defined(__SMALL__)
+ " (16-bit, small)",
+#elif defined(M_I86TM) || defined(__TINY__)
+ " (16-bit, tiny)",
+#else
+ " (16-bit)",
+#endif
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
+
+
+#ifdef __WATCOMC__
+
+/* This papers over a bug in Watcom 10.6's standard library... sigh */
+/* Apparently it applies to both the DOS and Win32 stat()s. */
+
+int stat_bandaid(const char *path, struct stat *buf)
+{
+ char newname[4];
+ if (!stat(path, buf))
+ return 0;
+ else if (!strcmp(path, ".") || (path[0] && !strcmp(path + 1, ":."))) {
+ strcpy(newname, path);
+ newname[strlen(path) - 1] = '\\'; /* stat(".") fails for root! */
+ return stat(newname, buf);
+ } else
+ return -1;
+}
+
+#endif
+
+
diff --git a/novell/README b/novell/README
new file mode 100644
index 0000000..a620c1b
--- /dev/null
+++ b/novell/README
@@ -0,0 +1,9 @@
+Unfinished integration into zip 2.4 of novell port to zip 2.2.
+
+TODO:
+
+Too much novell specific stuff via ifdef into the main sourcecode,
+use atexit() and setjmp()/longjmp() constructions instead.
+
+If a function doesn't exist (e.g. isatty), just write a wrapper
+and put it in Netware.c
diff --git a/novell/m.cmd b/novell/m.cmd
new file mode 100644
index 0000000..04084b3
--- /dev/null
+++ b/novell/m.cmd
@@ -0,0 +1,9 @@
+wmake
+
+copy zip.nlm f:
+
+attrib -r -h -s g:\hho\*.* /s
+del g:\hho\Attrib\*.*
+del g:\hho\Attrib\*.*
+rmdir g:\hho\Attrib
+
diff --git a/novell/osdep.h b/novell/osdep.h
new file mode 100644
index 0000000..f7b463c
--- /dev/null
+++ b/novell/osdep.h
@@ -0,0 +1,205 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* The symbol DOS is used throughout the Zip source to identify code portions
+ * specific to the MSDOS port.
+ * Just to make sure, we check that it is set.
+ * (Currently, this should should not be neccessary, since currently it has
+ * to be set on the compiler command line to get this file read in.)
+ */
+#ifndef DOS
+# define DOS
+#endif
+
+/* The symbol MSDOS is consistently used in the generic source files
+ * to identify code to support for MSDOS (and MSDOS related) stuff.
+ * e.g: FAT or (FAT like) file systems,
+ * '\\' as directory separator in paths,
+ * "\r\n" as record (line) terminator in text files, ...
+ *
+ * IMPORTANT Note:
+ * This symbol is not unique for the MSDOS port !!!!!!
+ * It is also defined by ports to some other OS which are (to some extend)
+ * considered DOS compatible.
+ * Examples are: OS/2 (OS2), Windows NT and Windows 95 (WIN32).
+ *
+ */
+#ifndef MSDOS
+# define MSDOS
+#endif
+
+/* Power C is similar to Turbo C */
+#ifdef __POWERC
+# define __TURBOC__
+#endif /* __POWERC */
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+# ifndef MSC
+# define MSC /* This should work for older MSC, too! */
+# endif
+#endif
+
+#if !defined(__GO32__) && !defined(__EMX__)
+# define NO_UNISTD_H
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+# define WATCOMC_386
+#endif
+
+#ifdef WINDLL
+# define MSWIN
+# define MEMORY16
+#endif
+
+
+#if !defined(__EMX__) && !defined(__GO32__) && !defined(WATCOMC_386)
+#if !defined(WINDLL)
+# define MSDOS16 /* 16 bit MSDOS only */
+# define MEMORY16
+#endif
+#endif
+
+#if !defined(NO_ASM) && !defined(ASMV)
+# define ASMV
+#endif
+
+/* enable creation of UTC time fields unless explicitely suppressed */
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+# define USE_EF_UT_TIME
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+# define IZ_CHECK_TZ
+#endif
+
+#ifdef MEMORY16
+# ifndef NO_ASM
+# define ASM_CRC 1
+# endif /* ?NO_ASM */
+# ifdef __TURBOC__
+# include <alloc.h>
+# if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
+# if defined(DYNAMIC_CRC_TABLE) && defined(DYNALLOC_CRCTAB)
+ error: No dynamic CRC table allocation with Borland C far data models.
+# endif /* DYNAMIC_CRC_TABLE */
+# endif /* Turbo/Borland C far data memory models */
+# define nearmalloc malloc
+# define nearfree free
+# define DYN_ALLOC
+# else /* !__TURBOC__ */
+# include <malloc.h>
+# define nearmalloc _nmalloc
+# define nearfree _nfree
+# define farmalloc _fmalloc
+# define farfree _ffree
+# endif /* ?__TURBOC__ */
+# define MY_ZCALLOC 1
+# ifdef SMALL_MEM
+# define CBSZ 2048
+# define ZBSZ 2048
+# endif
+# ifdef MEDIUM_MEM
+# define CBSZ 4096
+# define ZBSZ 4096
+# endif
+# ifndef CBSZ
+# define CBSZ 8192
+# define ZBSZ 8192
+# endif
+#endif /* MEMORY16 */
+
+
+#ifdef MATCH
+# undef MATCH
+#endif
+#define MATCH dosmatch /* use DOS style wildcard matching */
+
+#define USE_CASE_MAP
+
+#define ROUNDED_TIME(time) (((time) + 1) & (~1))
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifdef ZCRYPT_INTERNAL
+# ifdef WINDLL
+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as seed pattern */
+# else
+# ifndef __GO32__
+# include <process.h> /* getpid() declaration for srand seed */
+# endif
+# endif
+#endif
+
+/*
+ * djgpp 1.x did not declare these
+ */
+#if defined(__GO32__) && !defined(__DJGPP__)
+char *strlwr(char *);
+int setmode(int, int);
+#endif
+
+#ifdef __WATCOMC__
+# define NO_MKTEMP
+# define HAS_OPENDIR
+# define SSTAT stat_bandaid
+ int stat_bandaid(const char *path, struct stat *buf);
+
+/* Get asm routines to link properly without using "__cdecl": */
+# ifdef __386__
+# ifdef ASMV
+# pragma aux match_init "_*" parm caller [] modify []
+# pragma aux longest_match "_*" parm caller [] value [eax] \
+ modify [eax ecx edx]
+# endif
+# ifndef USE_ZLIB
+# pragma aux crc32 "_*" parm caller [] value [eax] modify [eax]
+# pragma aux get_crc_table "_*" parm caller [] value [eax] \
+ modify [eax ecx edx]
+# endif /* !USE_ZLIB */
+# else /* !__386__ */
+# ifdef ASMV
+# pragma aux match_init "_*" parm caller [] loadds modify [ax bx]
+# pragma aux longest_match "_*" parm caller [] loadds value [ax] \
+ modify [ax bx cx dx es]
+# endif /* ASMV */
+# ifndef USE_ZLIB
+# pragma aux crc32 "_*" parm caller [] value [ax dx] \
+ modify [ax bx cx dx es]
+# pragma aux get_crc_table "_*" parm caller [] value [ax] \
+ modify [ax bx cx dx]
+# endif /* !USE_ZLIB */
+# endif /* ?__386__ */
+#endif /* __WATCOMC__ */
+
+/*
+ * Wrapper function to get around the MSC7 00:00:00 31 Dec 1899 time base,
+ * see msdos.c for more info
+ */
+
+#if defined(_MSC_VER) && _MSC_VER == 700
+# define localtime(t) msc7_localtime(t)
+#endif
+
+#if (defined(__TURBOC__) && !defined(__BORLANDC__) && __TURBOC__ <= 0x0201)
+# ifndef NO_MKTIME
+# define NO_MKTIME /* TC 2.01 and earlier do not supply mktime() */
+# endif
+#endif
diff --git a/novell/signal.c b/novell/signal.c
new file mode 100644
index 0000000..a092bd3
--- /dev/null
+++ b/novell/signal.c
@@ -0,0 +1,49 @@
+#include <nwthread.h>
+#include <nwerrno.h>
+
+/*******************************/
+/* Interupt handler */
+/*******************************/
+
+int NLM_mainThreadGroupID;
+int NLM_threadCnt = 0;
+int NLM_exiting = FALSE;
+
+#pragma off(unreferenced);
+void NLM_SignalHandler(int sig)
+#pragma on(unreferenced);
+{
+ int handlerThreadGroupID;
+
+ switch(sig)
+ {
+ case SIGTERM:
+ NLM_exiting = TRUE;
+ handlerThreadGroupID = GetThreadGroupID();
+ SetThreadGroupID(NLM_mainThreadGroupID);
+
+ /* NLM SDK functions may be called here */
+
+ while (NLM_threadCnt != 0)
+ ThreadSwitchWithDelay();
+ SetThreadGroupID(handlerThreadGroupID);
+ break;
+ case SIGINT:
+ signal(SIGINT, NLM_SignalHandler);
+ break;
+ }
+ return;
+}
+
+void NLMsignals(void)
+{
+ ++NLM_threadCnt;
+ NLM_mainThreadGroupID = GetThreadGroupID();
+ signal(SIGTERM, NLM_SignalHandler);
+ signal(SIGINT, NLM_SignalHandler);
+}
+
+void NLMexit(void)
+{
+ --NLM_threadCnt;
+}
diff --git a/novell/zip.lnk b/novell/zip.lnk
new file mode 100644
index 0000000..19626c7
--- /dev/null
+++ b/novell/zip.lnk
@@ -0,0 +1,25 @@
+Form Novell NLM 'zip'
+Name zip
+Op ScreenName 'zip'
+Op ThreadName 'zip__P '
+Op Stack = 8k
+Op Version = 1.00.3
+Op Caseexact
+Op Nod
+File BITS.OBJ
+File CRC_i386.OBJ
+File CRYPT.OBJ
+File DEFLATE.OBJ
+File FILEIO.OBJ
+File GLOBALS.OBJ
+File MKTIME.OBJ
+File NETWARE.OBJ
+File TREES.OBJ
+File TTYIO.OBJ
+File UTIL.OBJ
+File ZIP.OBJ
+File ZIPFILE.OBJ
+File ZIPUP.OBJ
+File c:\novell\ndk\nwsdk\IMPORTS\PRELUDE.OBJ
+Import @c:\novell\ndk\nwsdk\IMPORTS\ALL.IMP
+Module CLib
diff --git a/novell/zipup.h b/novell/zipup.h
new file mode 100644
index 0000000..78b428a
--- /dev/null
+++ b/novell/zipup.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/os2/makefile.os2 b/os2/makefile.os2
new file mode 100644
index 0000000..a008ea5
--- /dev/null
+++ b/os2/makefile.os2
@@ -0,0 +1,563 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+
+# Supported Make utilities:
+# - Microsoft/IBM nmake
+# - dmake 3.8 or higher
+# - GNU make, at least version 3.68
+# - NOT watcom make
+# For Microsoft and Watcom C, better use NMAKE,
+# otherwise it doesn't matter.
+
+# Supported 16-bit C Compilers (created programs run under OS/2 1.x and 2.x):
+# - Microsoft C 6.00A
+# - Watcom C/C++ 16-bit
+
+# Supported 32-bit C Compilers (created programs run under OS/2 2.x only):
+# - GNU gcc (emx kit 0.9c or newer)
+# - IBM C Set/2 or C Set++ - does not yet work with ASM code
+# - Watcom C/C++ 32-bit - does not yet work with ASM code
+# - Borland C++ - no ASM code yet
+# - MetaWare High C/C++ - no ASM code yet
+
+# Supported Cross-Compilers for MS-DOS:
+# - Microsoft C 6.00A (16-bit)
+# - Watcom C/C++ (16- and 32-bit)
+# - GNU gcc (emx kit 0.9c or newer, 32-bit)
+
+# Supported Cross-Compilers for Win32 (WinNT/Win95):
+# - GNU gcc (emx kit 0.9c or newer, with RSXNT 1.4 or newer)
+
+# Supported Assemblers:
+# - Microsoft MASM 6.00 with Microsoft C, IBM C
+# - Watcom WASM with Watcom C/C++
+# - GNU as with GNU gcc
+
+# To use MASM 5.x instead of MASM 6.00:
+# - set AS="masm -T -Ml"
+# - set ASEOL=";"
+
+
+# To use, enter "make/nmake/dmake -f os2/makefile.os2"
+# (this makefile depends on its name being "os2/makefile.os2").
+
+# Add -DNO_ASM to CFLAGS and define OBJA to `nothing' if you do not have
+# masm or ml.
+# Add -DDYN_ALLOC to ASFLAGS if you have defined it in tailor.h or CFLAGS
+
+# Note: assembly language modules are really only supported for
+# Microsoft 16-bit and GNU gcc 32-bit compilation.
+
+# Notes on 16-bit (Microsoft C 6.00) compilation:
+
+# The resulting programs can be used under OS/2 protected mode only.
+# A larger stack has to be used for OS/2 because system calls
+# use more stack than under DOS, 8k is recommended by Microsoft.
+# Note that __STDC__ has to be defined explicitly with C 6.00 when -Ze
+# is given, because Microsoft disables __STDC__ when their extensions
+# are enabled. This is different from the C 5.10 behaviour.
+
+# Notes on 32-bit OS/2 compilation:
+
+# The resulting programs can be used under OS/2 protected
+# mode of OS/2 2.x only, not under 1.x and not under DOS.
+# It makes no difference if __STDC__ is defined or not.
+# Borland C++ works with DYN_ALLOC only.
+
+# Special Notes on IBM C/C++ compilation:
+
+# The older C compiler (C Set/2) breaks, while optimizing, on deflate.c
+# and trees.c (generates incorrect code). The newer C++ compiler (C Set++)
+# doesn't but instead breaks on crypt.c in the initial version and up to
+# CSD level 003. Starting with CSD level 004, it doesn't break any longer.
+
+# Notes on Watcom C/C++ compilation for DOS with the PMODE/W extender:
+#
+# You need to add the following section to your \watcom\binb\wlsystem.lnk
+# file and also need to copy pmodew.exe to the same directory:
+#
+# system begin pmodew
+# option osname='PMODE/W'
+# libpath %WATCOM%\lib386
+# libpath %WATCOM%\lib386\dos
+# op stub=pmodew.exe
+# format os2 le
+# end
+#
+# PMODE/W 1.16 or higher is required.
+
+
+default:
+ @echo "Enter $(MAKE) -f os2/makefile.os2 target"
+ @echo "where target is one of:"
+ @echo " msc mscdos ibm ibmdyn ibmdebug ibmprof metaware borland"
+ @echo " gcc gccdyn gcczlib gccdebug gccdos gccwin32 gccw32dyn"
+ @echo " watcom watcom16 watcomdos watcom16dos pmodew"
+
+# MS C 6.00 for OS/2, 16-bit
+msc:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="cl -nologo -AL -Ocegit -Gs $(FP)" \
+ CFLAGS="-W1 -Zep -J -G2 -D__STDC__ -DOS2 -DASM_CRC" \
+ AS="ml -nologo -c -Zm -Cp" \
+ ASFLAGS="-D__LARGE__ -D__286" \
+ LDFLAGS="-F 2000 -Lp -Fe" \
+ LDFLAGS2="-link /noe /pm:vio" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ CRCA_O="crc_i86.obj" \
+ OBJA="match.obj" \
+ DEF="os2\zip.def"
+
+# MS C 6.00 for OS/2, 16-bit, debug
+mscdebug:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="cl -nologo -AL -Zi -Od $(FP)" \
+ CFLAGS="-W1 -Zep -J -G2 -D__STDC__ -DOS2 -DASM_CRC" \
+ AS="ml -nologo -c -Zim -Cp" \
+ ASFLAGS="-D__LARGE__ -D__286" \
+ LDFLAGS="-F 2000 -Lp -Fe" \
+ LDFLAGS2="-link /noe /pm:vio" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ CRCA_O="crc_i86.obj" \
+ OBJA="match.obj" \
+ DEF="os2\zip.def"
+
+# crosscompilation for MS-DOS with MS C 6.00
+mscdos:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="cl -nologo -AL -Ocegit -Gs $(FP)" \
+ CFLAGS="-W1 -Zep -J -D__STDC__ -DDOS -DASM_CRC -DDYN_ALLOC" \
+ AS="ml -nologo -c -Zm -Cp" \
+ ASFLAGS="-D__LARGE__ -DDYN_ALLOC" \
+ LDFLAGS="-F 2000 -Lr -Fe" \
+ LDFLAGS2="-link /noe /exe" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ CRCA_O="crc_i86.obj" \
+ OBJA="match.obj" \
+ OBJ2="msdos.obj" OBJU2="msdos_.obj" \
+ OSDEP_H="msdos/osdep.h" ZIPUP_H="msdos/zipup.h"
+
+
+# IBM C Set/2, statically linked runtime
+ibm:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="icc -Q -O -Gs" \
+ CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM" \
+ AS="ml -nologo -c -Zm -Cp" \
+ ASFLAGS="" \
+ LDFLAGS="-B/ST:0x50000 -Fe" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ OBJA="" \
+ DEF="os2/zip.def"
+
+# IBM C Set/2, dynamically linked runtime
+ibmdyn:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="icc -Q -O -Gd -Gs" \
+ CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM" \
+ AS="ml -nologo -c -Zm -Cp" \
+ ASFLAGS="" \
+ LDFLAGS="-B/ST:0x50000 -Fe" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ OBJA="" \
+ DEF="os2/zip.def"
+
+# IBM C Set/2, debug version
+ibmdebug:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="icc -Q -Ti" \
+ CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM -Tm" \
+ AS="ml -nologo -c -Zim -Cp" \
+ ASFLAGS="" \
+ LDFLAGS="-B/ST:0x50000 -Fe" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ OBJA="" \
+ DEF="os2/zip.def"
+
+# IBM C Set/2, profiling version for PROFIT
+ibmprof:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="icc -Q -O -Gs -Gh -Ti" \
+ CFLAGS="-Sm -Sp1 -DOS2 -DNO_ASM" \
+ AS="ml -nologo -c -Zm -Cp" \
+ ASFLAGS="" \
+ LDFLAGS="-B/ST:0x50000 -Fe" \
+ LDFLAGS2="profit.obj" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ OBJA="" \
+ DEF="os2/zip.def"
+
+# Watcom C/386 9.0 or higher
+watcom:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="wcl386 -bt=os2v2 -zq -Ox -s" \
+ CFLAGS="-Zp1 -DOS2 -DNO_ASM" \
+ AS="wasm -zq -bt=os2v2 -3p" \
+ ASFLAGS="" \
+ LDFLAGS="-k0x50000 -x -l=os2v2 -Fe=" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ OBJA="" \
+ DIRSEP="\\" \
+ AS_DIRSEP="\\"
+
+# Watcom C/286 9.0 or higher
+watcom16:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="wcl -bt=os2 -zq -ml -Ox -s" \
+ CFLAGS="-Zp1 -DOS2 -DNO_ASM" \
+ AS="wasm -zq -bt=os2 -2p -ml" \
+ ASFLAGS="" \
+ LDFLAGS="/\"option newfiles\" -k0x3000 -x -l=os2 -Fe=" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ OBJA="" \
+ DIRSEP="\\" \
+ AS_DIRSEP="\\"
+
+# Watcom C/386 9.0 or higher, crosscompilation for DOS, DOS4GW extender
+watcomdos:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="wcl386 -bt=dos4g -zq -Ox -s" \
+ CFLAGS="-Zp1 -DDOS -DMSDOS -DASM_CRC" \
+ AS="wasm -zq -bt=dos4g -3p" \
+ ASFLAGS="-DWATCOM_DSEG" \
+ LDFLAGS="-k0x50000 -x -l=dos4g -Fe=" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ CRCA_O="crc_i386.obj" \
+ OBJA="match32.obj" \
+ OBJ2="msdos.obj" \
+ OBJU2="msdos_.obj" \
+ OSDEP_H="msdos/osdep.h" \
+ ZIPUP_H="msdos/zipup.h" \
+ DIRSEP="\\" \
+ AS_DIRSEP="\\"
+
+# Watcom C/386 9.0 or higher, crosscompilation for DOS, PMODE/W extender
+pmodew:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="wcl386 -bt=dos4g -zq -Ox -s" \
+ CFLAGS="-Zp1 -DDOS -DMSDOS -DASM_CRC" \
+ AS="wasm -zq -bt=dos4g -3p" \
+ ASFLAGS="-DWATCOM_DSEG" \
+ LDFLAGS="-k0x50000 -x -l=pmodew -Fe=" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ CRCA_O="crc_i386.obj" \
+ OBJA="match32.obj" \
+ OBJ2="msdos.obj" \
+ OBJU2="msdos_.obj" \
+ OSDEP_H="msdos/osdep.h" \
+ ZIPUP_H="msdos/zipup.h" \
+ DIRSEP="\\" \
+ AS_DIRSEP="\\"
+
+# Watcom C/286 9.0 or higher, crosscompilation for DOS
+watcom16dos:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="wcl -bt=dos -zq -ml -Ox -s" \
+ CFLAGS="-Zp1 -DDOS -DMSDOS -DDYN_ALLOC -DNO_ASM" \
+ AS="wasm -zq -bt=dos -2 -ml" \
+ ASFLAGS="-DDYN_ALLOC" \
+ LDFLAGS="-k0x2000 -x -l=dos -Fe=" \
+ LDFLAGS2="" \
+ OUT="-Fo" \
+ OBJ=".obj" \
+ OBJA="" \
+ OBJ2="msdos.obj" \
+ OBJU2="msdos_.obj" \
+ OSDEP_H="msdos/osdep.h" \
+ ZIPUP_H="msdos/zipup.h" \
+ DIRSEP="\\" \
+ AS_DIRSEP="\\"
+
+# MetaWare High C/C++ 3.2
+metaware:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="hc -O2" \
+ CFLAGS="-D__32BIT__ -DOS2 -DNO_ASM" \
+ AS="ml -nologo -c -Zm -Cp" \
+ ASFLAGS="" \
+ LDFLAGS="-o " \
+ LDFLAGS2="" \
+ OUT="-o ./" \
+ OBJ=".obj" \
+ DEF="-Hdef=os2/zip.def"
+
+# Borland C++
+borland:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="bcc -O" \
+ CFLAGS="-w- -DOS2 -DDYN_ALLOC -DNO_ASM" \
+ AS="ml -nologo -c -Zm -Cp" \
+ ASFLAGS="" \
+ LDFLAGS="-e" \
+ LDFLAGS2="" \
+ OUT="-o" \
+ OBJ=".obj" \
+ OBJA="" \
+ DEF="-sDos2/zip.def"
+
+# emx 0.9c, gcc, OMF format, statically linked C runtime and emx
+gcc:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="gcc -Zomf -O -Wimplicit" \
+ CFLAGS="-DOS2 -DASM_CRC" \
+ AS="gcc -Zomf" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-Zsys -Zstack 320 -s -Zsmall-conv" \
+ OUT="-o" \
+ OBJ=".obj" \
+ CRCA_O="crc_gcc.obj" \
+ OBJA="matchgcc.obj" \
+ DEF="os2/zip.def"
+
+# emx 0.9c, gcc, OMF format, dynamically linked C runtime and emx
+gccdyn:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="gcc -Zomf -O -Wimplicit" \
+ CFLAGS="-DOS2 -DASM_CRC" \
+ AS="gcc -Zomf" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-Zcrtdll -Zstack 320 -s" \
+ OUT="-o" \
+ OBJ=".obj" \
+ CRCA_O="crc_gcc.obj" \
+ OBJA="matchgcc.obj" \
+ DEF="os2/zip.def"
+
+# emx 0.9c, gcc, OMF format, statically linked zlib, C runtime, and emx
+gcczlib:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="gcc -Zomf -O -Wimplicit" \
+ CFLAGS="-DOS2 -DUSE_ZLIB" \
+ AS="gcc -Zomf" \
+ ASFLAGS="-Di386 -DUSE_ZLIB" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-L. -lzlib -Zsys -Zstack 320 -s -Zsmall-conv" \
+ OUT="-o" \
+ OBJ=".obj" \
+ CRCA_O="" \
+ OBJA="" \
+ DEF="os2/zip.def"
+
+# emx 0.9c, gcc, a.out format, with debug info for gdb
+gccdebug:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="gcc -g -Wimplicit" \
+ CFLAGS="-DOS2 -DASM_CRC" \
+ AS="gcc" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ OBJA="matchgcc.o" \
+ DEF="os2/zip.def"
+
+# emx 0.9c, gcc, a.out format, for MS-DOS
+gccdos:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="gcc -O -Wimplicit" \
+ CFLAGS="-DDOS -DMSDOS -DASM_CRC" \
+ AS="gcc" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-s -Zsmall-conv" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ OBJA="matchgcc.o" \
+ OBJ2="msdos.o" \
+ OBJU2="msdos_.o" \
+ OSDEP_H="msdos/osdep.h" \
+ ZIPUP_H="msdos/zipup.h"
+
+# emx 0.9c, gcc, RSXNT 1.4, cross-compilation for Win32
+gccwin32:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="gcc -Zwin32 -O -m486 -Wall" \
+ CFLAGS="-DWIN32 -DASM_CRC" \
+ AS="gcc -Zwin32" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-ladvapi32 -Zsys -Zsmall-conv -s" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ OBJA="matchgcc.o" \
+ OBJ2="win32zip.o win32.o nt.o" \
+ OBJU2="win32_.o" \
+ OSDEP_H="win32/osdep.h" \
+ ZIPUP_H="win32/zipup.h" \
+ DEF="win32/zip.def"
+
+# emx 0.9c, gcc, RSXNT 1.4, cross-compilation for Win32, use emx C rtl DLL
+gccw32dyn:
+ $(MAKE) -f os2/makefile.os2 zips \
+ CC="gcc -Zwin32 -Zcrtdll=crtrsxnt -O -m486 -Wall" \
+ CFLAGS="-DWIN32 -DASM_CRC" \
+ AS="gcc -Zwin32" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-ladvapi32 -s" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ OBJA="matchgcc.o" \
+ OBJ2="win32zip.o win32.o nt.o" \
+ OBJU2="win32_.o" \
+ OSDEP_H="win32/osdep.h" \
+ ZIPUP_H="win32/zipup.h" \
+ DEF="win32/zip.def"
+
+# VPATH = .;os2
+
+# variables
+
+#default settings for target dependent macros:
+DIRSEP = /
+AS_DIRSEP = /
+# LOCAL_OPTS =
+CCFLAGS = $(CFLAGS) $(LOCAL_OPTS)
+
+OSDEP_H = os2/osdep.h
+ZIPUP_H = os2/os2zip.h os2/zipup.h
+CRCA_O =
+
+
+OBJZ = zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+ crc32$(OBJ) $(CRCA_O) globals$(OBJ) \
+ deflate$(OBJ) trees$(OBJ) crypt$(OBJ) ttyio$(OBJ)
+OBJ2 = os2zip$(OBJ) os2$(OBJ) os2acl$(OBJ)
+
+OBJU = zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) globals$(OBJ)
+OBJU2 = os2zip_$(OBJ)
+
+OBJN = zipnote$(OBJ) $(OBJU) $(OBJU2)
+OBJS = zipsplit$(OBJ) $(OBJU) $(OBJU2)
+OBJC = zipcloak$(OBJ) crc32_$(OBJ) crypt_$(OBJ) ttyio$(OBJ) $(OBJU) $(OBJU2)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+ $(CC) -c -I. $(CCFLAGS) $<
+
+.asm$(OBJ):
+ $(AS) $(ASFLAGS) $< $(ASEOL)
+
+# targets
+
+zips: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ): zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ): zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ): zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio$(OBJ): fileio.c $(ZIP_H) crc32.h
+util$(OBJ): util.c $(ZIP_H)
+globals$(OBJ): globals.c $(ZIP_H)
+deflate$(OBJ): deflate.c $(ZIP_H)
+trees$(OBJ): trees.c $(ZIP_H)
+crc32$(OBJ): crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ): ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+os2zip$(OBJ): os2/os2zip.c $(ZIP_H) os2/os2zip.h os2/os2acl.h
+ $(CC) -c -I. $(CCFLAGS) os2$(DIRSEP)os2zip.c
+
+os2$(OBJ): os2/os2.c $(ZIP_H) os2/os2zip.h
+ $(CC) -c -I. $(CCFLAGS) os2$(DIRSEP)os2.c
+
+os2acl$(OBJ): os2/os2acl.c os2/os2acl.h
+ $(CC) -c -I. $(CCFLAGS) os2$(DIRSEP)os2acl.c
+
+msdos$(OBJ): msdos/msdos.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) msdos$(DIRSEP)msdos.c
+
+win32zip$(OBJ): win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32zip.c
+
+win32$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32.c
+
+nt$(OBJ): win32/nt.c win32/nt.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)nt.c
+
+crc_i86$(OBJ): msdos/crc_i86.asm # 16bit only
+ $(AS) $(ASFLAGS) msdos$(AS_DIRSEP)crc_i86.asm $(ASEOL)
+
+crc_i386$(OBJ): win32/crc_i386.asm # 32bit, MASM
+ $(AS) $(ASFLAGS) win32$(AS_DIRSEP)crc_i386.asm $(ASEOL)
+
+crc_gcc$(OBJ): crc_i386.S # 32bit, GNU AS
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+match$(OBJ): msdos/match.asm
+ $(AS) $(ASFLAGS) msdos$(AS_DIRSEP)match.asm $(ASEOL)
+
+match32$(OBJ): win32/match32.asm
+ $(AS) $(ASFLAGS) win32$(AS_DIRSEP)match32.asm
+
+matchgcc$(OBJ): match.S
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zipcloak$(OBJ): zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote$(OBJ): zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ): zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ zipfile.c
+
+fileio_$(OBJ): fileio.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ fileio.c
+
+util_$(OBJ): util.c $(ZIP_H) os2/os2zip.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ util.c
+
+crc32_$(OBJ): crc32.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crc32.c
+
+crypt_$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crypt.c
+
+os2zip_$(OBJ): os2/os2zip.c $(ZIP_H) os2/os2zip.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ os2$(DIRSEP)os2zip.c
+
+msdos_$(OBJ): msdos/msdos.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ msdos$(DIRSEP)msdos.c
+
+win32_$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ win32$(DIRSEP)win32.c
+
+zip.exe: $(OBJZ) $(OBJ2) $(OBJA)
+ $(CC) $(LDFLAGS)$@ $(DEF) $(OBJZ) $(OBJ2) $(OBJA) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+ $(CC) $(LDFLAGS)$@ $(DEF) $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+ $(CC) $(LDFLAGS)$@ $(DEF) $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+ $(CC) $(LDFLAGS)$@ $(DEF) $(OBJS) $(LDFLAGS2)
diff --git a/os2/match32.asm b/os2/match32.asm
new file mode 100644
index 0000000..4797a73
--- /dev/null
+++ b/os2/match32.asm
@@ -0,0 +1,175 @@
+;===========================================================================
+; Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2005-Feb-10 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+;
+; match32.asm by Jean-loup Gailly.
+
+; match32.asm, optimized version of longest_match() in deflate.c
+; To be used only with 32 bit flat model. To simplify the code, the option
+; -DDYN_ALLOC is not supported.
+; This file is only optional. If you don't have an assembler, use the
+; C version (add -DNO_ASM to CFLAGS in makefile and remove match.o
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+
+; Caution: this module works for IBM's C/C++ compiler versions 2 and 3
+; and for Watcom's 32-bit C/C++ compiler. Both pass the first (and only)
+; argument for longest_match in the EAX register, not on the stack, with
+; the default calling conventions (_System would use the stack).
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+ IFNDEF USE_ZLIB
+;
+ .386
+
+ name match
+
+BSS32 segment dword USE32 public 'BSS'
+ extrn window : byte
+ extrn prev : word
+ extrn prev_length : dword
+ extrn strstart : dword
+ extrn match_start : dword
+ extrn max_chain_length : dword
+ extrn good_match : dword
+ extrn nice_match : dword
+BSS32 ends
+
+CODE32 segment dword USE32 public 'CODE'
+ assume cs:CODE32, ds:FLAT, ss:FLAT
+
+ public match_init
+ public longest_match
+
+ ifndef WSIZE
+ WSIZE equ 32768 ; keep in sync with zip.h !
+ endif
+ MIN_MATCH equ 3
+ MAX_MATCH equ 258
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+ MAX_DIST equ (WSIZE-MIN_LOOKAHEAD)
+
+; initialize or check the variables used in match.asm.
+
+match_init proc near
+ ret
+match_init endp
+
+; -----------------------------------------------------------------------
+; Set match_start to the longest match starting at the given string and
+; return its length. Matches shorter or equal to prev_length are discarded,
+; in which case the result is equal to prev_length and match_start is
+; garbage.
+; IN assertions: cur_match is the head of the hash chain for the current
+; string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+
+; int longest_match(cur_match)
+
+longest_match proc near
+
+ ; return address ; esp+16
+ push ebp ; esp+12
+ push edi ; esp+8
+ push esi ; esp+4
+
+ lea ebx,window
+ add ebx,2
+ window_off equ dword ptr [esp]
+ push ebx ; esp
+
+; match equ esi
+; scan equ edi
+; chain_length equ ebp
+; best_len equ ebx
+; limit equ edx
+
+ mov esi,eax ; cur_match
+ mov edx,strstart
+ mov ebp,max_chain_length ; chain_length = max_chain_length
+ mov edi,edx
+ sub edx,MAX_DIST ; limit = strstart-MAX_DIST
+ cld ; string ops increment esi and edi
+ jae short limit_ok
+ sub edx,edx ; limit = NIL
+limit_ok:
+ add edi,window_off ; edi = offset(window + strstart + 2)
+ mov ebx,prev_length ; best_len = prev_length
+ mov cx,[edi-2] ; cx = scan[0..1]
+ mov ax,[ebx+edi-3] ; ax = scan[best_len-1..best_len]
+ cmp ebx,good_match ; do we have a good match already?
+ jb do_scan
+ shr ebp,2 ; chain_length >>= 2
+ jmp short do_scan
+
+ align 4 ; align destination of branch
+long_loop:
+; at this point, edi == scan+2, esi == cur_match
+ mov ax,[ebx+edi-3] ; ax = scan[best_len-1..best_len]
+ mov cx,[edi-2] ; cx = scan[0..1]
+short_loop:
+; at this point, edi == scan+2, esi == cur_match,
+; ax = scan[best_len-1..best_len] and cx = scan[0..1]
+ and esi,WSIZE-1 ; not needed if WSIZE=32768
+ dec ebp ; --chain_length
+ shl esi,1 ; cur_match as word index
+ mov si,prev[esi] ; cur_match = prev[cur_match]
+ ; top word of esi is still 0
+ jz the_end
+ cmp esi,edx ; cur_match <= limit ?
+ jbe short the_end
+do_scan:
+ cmp ax,word ptr window[ebx+esi-1] ; check match at best_len-1
+ jne short_loop
+ cmp cx,word ptr window[esi] ; check min_match_length match
+ jne short_loop
+
+ add esi,window_off ; esi = match
+ mov ecx,(MAX_MATCH-2)/2 ; scan for at most MAX_MATCH bytes
+ mov eax,edi ; eax = scan+2
+ repe cmpsw ; loop until mismatch
+ je maxmatch ; match of length MAX_MATCH?
+mismatch:
+ mov cl,[edi-2] ; mismatch on first or second byte?
+ xchg eax,edi ; edi = scan+2, eax = end of scan
+ sub cl,[esi-2] ; cl = 0 if first bytes equal
+ sub eax,edi ; eax = len
+ sub esi,window_off ; esi = match - (2 + offset(window))
+ sub esi,eax ; esi = cur_match (= match - len)
+ sub cl,1 ; set carry if cl == 0 (can't use DEC)
+ adc eax,0 ; eax = carry ? len+1 : len
+ cmp eax,ebx ; len > best_len ?
+ jle long_loop
+ mov match_start,esi ; match_start = cur_match
+ mov ebx,eax ; ebx = best_len = len
+ ifdef FULL_SEARCH
+ cmp eax,MAX_MATCH ; len >= MAX_MATCH ?
+ else
+ cmp eax,nice_match ; len >= nice_match ?
+ endif
+ jl long_loop
+the_end:
+ mov eax,ebx ; result = eax = best_len
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+maxmatch: ; come here if maximum match
+ cmpsb ; increment esi and edi
+ jmp mismatch ; force match_length = MAX_LENGTH
+
+longest_match endp
+
+CODE32 ends
+;
+ ENDIF ; !USE_ZLIB
+;
+ end
diff --git a/os2/os2.c b/os2/os2.c
new file mode 100644
index 0000000..b44fe2e
--- /dev/null
+++ b/os2/os2.c
@@ -0,0 +1,481 @@
+/*
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#if defined(__IBMC__) || defined(MSC)
+#include <direct.h>
+#endif
+
+/* Extra malloc() space in names for cutpath() */
+#define PAD 0
+#define PATH_END '/'
+
+
+#include "os2zip.h"
+
+/* Library functions not in (most) header files */
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int wild(w)
+char *w; /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+ file system. Return an error code in the ZE_ class. */
+{
+ DIR *d; /* stream for reading directory */
+ char *e; /* name found in directory */
+ int r; /* temporary variable */
+ char *n; /* constructed name from directory */
+ int f; /* true if there was a match */
+ char *a; /* alloc'ed space for name */
+ char *p; /* path */
+ char *q; /* name */
+ char v[5]; /* space for device current directory */
+
+ if (volume_label == 1) {
+ volume_label = 2;
+ label = getVolumeLabel((w != NULL && w[1] == ':') ? to_up(w[0]) : '\0',
+ &label_time, &label_mode, &label_utim);
+ if (label != NULL) {
+ newname(label, 0, 0);
+ }
+ if (w == NULL || (w[1] == ':' && w[2] == '\0')) return ZE_OK;
+ /* "zip -$ foo a:" can be used to force drive name */
+ }
+
+ if (w == NULL)
+ return ZE_OK;
+
+ /* special handling of stdin request */
+ if (strcmp(w, "-") == 0) /* if compressing stdin */
+ return newname(w, 0, 0);
+
+ /* Allocate and copy pattern */
+ if ((p = a = malloc(strlen(w) + 1)) == NULL)
+ return ZE_MEM;
+ strcpy(p, w);
+
+ /* catch special case: treat "*.*" as "*" for DOS-impaired people */
+ r = strlen(p);
+ if (strcmp(p + r - 3, "*.*") == 0)
+ p[r - 2] = '\0';
+
+ /* Normalize path delimiter as '/'. */
+ for (q = p; *q; q++) /* use / consistently */
+ if (*q == '\\')
+ *q = '/';
+
+ /* Only name can have special matching characters */
+ if ((q = isshexp(p)) != NULL &&
+ (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
+ {
+ free((zvoid *)a);
+ return ZE_PARMS;
+ }
+
+ /* Separate path and name into p and q */
+ if ((q = strrchr(p, '/')) != NULL && (q == p || q[-1] != ':'))
+ {
+ *q++ = '\0'; /* path/name -> path, name */
+ if (*p == '\0') /* path is just / */
+ p = strcpy(v, "/.");
+ }
+ else if ((q = strrchr(p, ':')) != NULL)
+ { /* has device and no or root path */
+ *q++ = '\0';
+ p = strcat(strcpy(v, p), ":"); /* copy device as path */
+ if (*q == '/') /* -> device:/., name */
+ {
+ strcat(p, "/");
+ q++;
+ }
+ strcat(p, ".");
+ }
+ else if (recurse && (strcmp(p, ".") == 0 || strcmp(p, "..") == 0))
+ { /* current or parent directory */
+ /* I can't understand Mark's code so I am adding a hack here to get
+ * "zip -r foo ." to work. Allow the dubious "zip -r foo .." but
+ * reject "zip -rm foo ..".
+ */
+ if (dispose && strcmp(p, "..") == 0)
+ ziperr(ZE_PARMS, "cannot remove parent directory");
+ q = "*";
+ }
+ else /* no path or device */
+ {
+ q = p;
+ p = strcpy(v, ".");
+ }
+ if (recurse && *q == '\0') {
+ q = "*";
+ }
+ /* Search that level for matching names */
+ if ((d = opendir(p)) == NULL)
+ {
+ free((zvoid *)a);
+ return ZE_MISS;
+ }
+ if ((r = strlen(p)) > 1 &&
+ (strcmp(p + r - 2, ":.") == 0 || strcmp(p + r - 2, "/.") == 0))
+ *(p + r - 1) = '\0';
+ f = 0;
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e, 0))
+ {
+ f = 1;
+ if (strcmp(p, ".") == 0) { /* path is . */
+ r = procname(e, 0); /* name is name */
+ if (r) {
+ f = 0;
+ break;
+ }
+ } else
+ {
+ if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
+ {
+ free((zvoid *)a);
+ closedir(d);
+ return ZE_MEM;
+ }
+ n = strcpy(n, p);
+ if (n[r = strlen(n) - 1] != '/' && n[r] != ':')
+ strcat(n, "/");
+ r = procname(strcat(n, e), 0); /* name is path/name */
+ free((zvoid *)n);
+ if (r) {
+ f = 0;
+ break;
+ }
+ }
+ }
+ }
+ closedir(d);
+
+ /* Done */
+ free((zvoid *)a);
+ return f ? ZE_OK : ZE_MISS;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (n == NULL) /* volume_label request in freshen|delete mode ?? */
+ return ZE_OK;
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s)
+#if defined(__TURBOC__) || defined(__WATCOMC__)
+ /* For these 2 compilers, stat() succeeds on wild card names! */
+ || isshexp(n)
+#endif
+ )
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ for (p = n; *p; p++) /* use / consistently */
+ if (*p == '\\')
+ *p = '/';
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+ dosflag = dosify || IsFileSystemFAT(x) || (x == label);
+ if (!dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL)
+ {
+ x = t;
+ dosflag = 0;
+ }
+
+ /* Find starting point in name before doing malloc */
+ /* Strip drive specification */
+ t = *x && *(x + 1) == ':' ? x + 2 : x;
+ /* Strip "//host/share/" part of a UNC name */
+ if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
+ (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
+ n = x + 2;
+ while (*n != '\0' && *n != '/' && *n != '\\')
+ n++; /* strip host name */
+ if (*n != '\0') {
+ n++;
+ while (*n != '\0' && *n != '/' && *n != '\\')
+ n++; /* strip `share' name */
+ }
+ if (*n != '\0')
+ t = n + 1;
+ }
+ /* Strip leading "/" to convert an absolute path into a relative path */
+ while (*t == '/' || *t == '\\')
+ t++;
+ /* Strip leading "./" as well as drive letter */
+ while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
+ t += 2;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ for (n = t; *n; n++)
+ if (*n == '\\')
+ *n = '/';
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+
+ return x;
+}
+
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ SetFileTime(f, d);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ char *name;
+ ulg r;
+ unsigned int len = strlen(f);
+ int isstdin = !strcmp(f, "-");
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (isstdin) {
+ /* it is common for some PC based compilers to
+ fail with fstat() on devices or pipes */
+ if (fstat(fileno(stdin), &s) != 0) {
+ s.st_mode = S_IFREG; s.st_size = -1L;
+ }
+ time(&s.st_ctime);
+ s.st_atime = s.st_mtime = s.st_ctime;
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+#ifdef __WATCOMC__
+ /* of course, Watcom always has to make an exception */
+ if (s.st_atime == 312764400)
+ s.st_atime = s.st_mtime;
+ if (s.st_ctime == 312764400)
+ s.st_ctime = s.st_mtime;
+#endif
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ r = GetFileTime(name);
+ free(name);
+
+ return r;
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ */
+{
+ return rmdir(d);
+}
+
+
+#if defined MY_ZCALLOC /* Special zcalloc function for MEMORY16 (MSDOS/OS2) */
+
+#ifdef MSC /* Microsoft C */
+
+zvoid far *zcalloc (unsigned items, unsigned size)
+{
+ return (zvoid far *)halloc((long)items, size);
+}
+
+zvoid zcfree (zvoid far *ptr)
+{
+ hfree((void huge *)ptr);
+}
+
+#endif /* MSC */
+
+#endif /* MY_ZCALLOC */
+
+#endif /* !UTIL */
diff --git a/os2/os2acl.c b/os2/os2acl.c
new file mode 100644
index 0000000..4f88643
--- /dev/null
+++ b/os2/os2acl.c
@@ -0,0 +1,385 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* os2acl.c - access to OS/2 (LAN Server) ACLs
+ *
+ * Author: Kai Uwe Rommel <rommel@ars.de>
+ * Created: Mon Aug 08 1994
+ *
+ */
+
+/*
+ * supported 32-bit compilers:
+ * - emx+gcc
+ * - IBM C Set++ 2.1 or newer
+ * - Watcom C/C++ 10.0 or newer
+ *
+ * supported 16-bit compilers:
+ * - MS C 6.00A
+ * - Watcom C/C++ 10.0 or newer
+ *
+ * supported OS/2 LAN environments:
+ * - IBM LAN Server/Requester 3.0, 4.0 and 5.0 (Warp Server)
+ * - IBM Peer 1.0 (Warp Connect)
+ */
+
+#ifdef KUR
+ static char *rcsid =
+ "$Id: os2acl.c,v 1.3 1996/04/03 19:18:27 rommel Exp rommel $";
+ static char *rcsrev = "$Revision: 1.3 $";
+#endif
+
+/*
+ * $Log: os2acl.c,v $
+ * Revision 1.3 1996/04/03 19:18:27 rommel
+ * minor fixes
+ *
+ * Revision 1.2 1996/03/30 22:03:52 rommel
+ * avoid frequent dynamic allocation for every call
+ * streamlined code
+ *
+ * Revision 1.1 1996/03/30 09:35:00 rommel
+ * Initial revision
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+
+#define INCL_NOPM
+#define INCL_DOS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include "os2/os2acl.h"
+
+#define UNLEN 20
+
+#if defined(__WATCOMC__) && defined(__386__) && !defined(__32BIT__)
+#define __32BIT__
+#endif
+
+#ifdef __32BIT__
+typedef ULONG U_INT;
+#ifdef __EMX__
+#define PSTR16 _far16ptr
+#define PTR16(x) _emx_32to16(x)
+#else /* other 32-bit */
+#define PSTR16 PCHAR16
+#define PTR16(x) ((PCHAR16)(x))
+#endif
+#else /* 16-bit */
+typedef USHORT U_INT;
+#define PSTR16 PSZ
+#define PTR16(x) (x)
+#endif
+
+typedef struct access_list
+{
+ char acl_ugname[UNLEN+1];
+ char acl_pad;
+ USHORT acl_access;
+}
+ACCLIST;
+
+typedef struct access_info
+{
+ PSTR16 acc_resource_name;
+ USHORT acc_attr;
+ USHORT acc_count;
+}
+ACCINFO;
+
+static ACCINFO *ai;
+static char *path, *data;
+
+#ifdef __32BIT__
+
+#ifdef __EMX__
+
+static USHORT (APIENTRY *_NetAccessGetInfo)(PSZ pszServer, PSZ pszResource,
+ USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail);
+static USHORT (APIENTRY *_NetAccessSetInfo)(PSZ pszServer, PSZ pszResource,
+ USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, USHORT sParmNum);
+static USHORT (APIENTRY *_NetAccessAdd)(PSZ pszServer,
+ USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer);
+
+USHORT NetAccessGetInfo(PSZ pszServer, PSZ pszResource, USHORT sLevel,
+ PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail)
+{
+ return (USHORT)
+ (_THUNK_PROLOG (4+4+2+4+2+4);
+ _THUNK_FLAT (pszServer);
+ _THUNK_FLAT (pszResource);
+ _THUNK_SHORT (sLevel);
+ _THUNK_FLAT (pbBuffer);
+ _THUNK_SHORT (cbBuffer);
+ _THUNK_FLAT (pcbTotalAvail);
+ _THUNK_CALLI (_emx_32to16(_NetAccessGetInfo)));
+}
+
+USHORT NetAccessSetInfo(PSZ pszServer, PSZ pszResource, USHORT sLevel,
+ PVOID pbBuffer, USHORT cbBuffer, USHORT sParmNum)
+{
+ return (USHORT)
+ (_THUNK_PROLOG (4+4+2+4+2+2);
+ _THUNK_FLAT (pszServer);
+ _THUNK_FLAT (pszResource);
+ _THUNK_SHORT (sLevel);
+ _THUNK_FLAT (pbBuffer);
+ _THUNK_SHORT (cbBuffer);
+ _THUNK_SHORT (sParmNum);
+ _THUNK_CALLI (_emx_32to16(_NetAccessSetInfo)));
+}
+
+USHORT NetAccessAdd(PSZ pszServer, USHORT sLevel,
+ PVOID pbBuffer, USHORT cbBuffer)
+{
+ return (USHORT)
+ (_THUNK_PROLOG (4+2+4+2);
+ _THUNK_FLAT (pszServer);
+ _THUNK_SHORT (sLevel);
+ _THUNK_FLAT (pbBuffer);
+ _THUNK_SHORT (cbBuffer);
+ _THUNK_CALLI (_emx_32to16(_NetAccessAdd)));
+}
+
+#else /* other 32-bit */
+
+APIRET16 (* APIENTRY16 NetAccessGetInfo)(PCHAR16 pszServer, PCHAR16 pszResource,
+ USHORT sLevel, PVOID16 pbBuffer, USHORT cbBuffer, PVOID16 pcbTotalAvail);
+APIRET16 (* APIENTRY16 NetAccessSetInfo)(PCHAR16 pszServer, PCHAR16 pszResource,
+ USHORT sLevel, PVOID16 pbBuffer, USHORT cbBuffer, USHORT sParmNum);
+APIRET16 (* APIENTRY16 NetAccessAdd)(PCHAR16 pszServer,
+ USHORT sLevel, PVOID16 pbBuffer, USHORT cbBuffer);
+
+#define _NetAccessGetInfo NetAccessGetInfo
+#define _NetAccessSetInfo NetAccessSetInfo
+#define _NetAccessAdd NetAccessAdd
+
+#if !defined(__IBMC__) || !defined(__TILED__)
+#define _tmalloc malloc
+#define _tfree free
+#endif
+
+#endif
+#else /* 16-bit */
+
+USHORT (APIENTRY *NetAccessGetInfo)(PSZ pszServer, PSZ pszResource,
+ USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, PUSHORT pcbTotalAvail);
+USHORT (APIENTRY *NetAccessSetInfo)(PSZ pszServer, PSZ pszResource,
+ USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer, USHORT sParmNum);
+USHORT (APIENTRY *NetAccessAdd)(PSZ pszServer,
+ USHORT sLevel, PVOID pbBuffer, USHORT cbBuffer);
+
+#define _NetAccessGetInfo NetAccessGetInfo
+#define _NetAccessSetInfo NetAccessSetInfo
+#define _NetAccessAdd NetAccessAdd
+
+#define _tmalloc malloc
+#define _tfree free
+
+#define DosQueryProcAddr(handle, ord, name, funcptr) \
+ DosGetProcAddr(handle, name, funcptr)
+#define DosQueryCurrentDir DosQCurDir
+#define DosQueryCurrentDisk DosQCurDisk
+
+#endif
+
+
+static BOOL acl_init(void)
+{
+ static BOOL initialized, netapi_avail;
+ HMODULE netapi;
+ char buf[256];
+
+ if (initialized)
+ return netapi_avail;
+
+ initialized = TRUE;
+
+ if (DosLoadModule(buf, sizeof(buf), "NETAPI", &netapi))
+ return FALSE;
+
+ if (DosQueryProcAddr(netapi, 0, "NETACCESSGETINFO", (PFN *) &_NetAccessGetInfo) ||
+ DosQueryProcAddr(netapi, 0, "NETACCESSSETINFO", (PFN *) &_NetAccessSetInfo) ||
+ DosQueryProcAddr(netapi, 0, "NETACCESSADD", (PFN *) &_NetAccessAdd))
+ return FALSE;
+
+#if defined(__WATCOMC__) && defined(__386__)
+ NetAccessGetInfo = (PVOID) (ULONG) (PVOID16) NetAccessGetInfo;
+ NetAccessSetInfo = (PVOID) (ULONG) (PVOID16) NetAccessSetInfo;
+ NetAccessAdd = (PVOID) (ULONG) (PVOID16) NetAccessAdd;
+#endif
+
+ if ((path = _tmalloc(CCHMAXPATH)) == NULL)
+ return FALSE;
+ if ((data = _tmalloc(ACL_BUFFERSIZE)) == NULL)
+ return FALSE;
+ if ((ai = _tmalloc(sizeof(ACCINFO))) == NULL)
+ return -1;
+
+ netapi_avail = TRUE;
+
+ return netapi_avail;
+}
+
+static void acl_mkpath(char *buffer, const char *source)
+{
+ char *ptr;
+ static char cwd[CCHMAXPATH];
+ static U_INT cwdlen;
+ U_INT cdrive;
+ ULONG drivemap;
+
+ if (isalpha((int)source[0]) && source[1] == ':')
+ buffer[0] = 0; /* fully qualified names */
+ else
+ {
+ if (cwd[0] == 0)
+ {
+ DosQueryCurrentDisk(&cdrive, &drivemap);
+ cwd[0] = (char)(cdrive + '@');
+ cwd[1] = ':';
+ cwd[2] = '\\';
+ cwdlen = sizeof(cwd) - 3;
+ DosQueryCurrentDir(0, cwd + 3, &cwdlen);
+ cwdlen = strlen(cwd);
+ }
+
+ if (source[0] == '/' || source[0] == '\\')
+ {
+ if (source[1] == '/' || source[1] == '\\')
+ buffer[0] = 0; /* UNC names */
+ else
+ {
+ strncpy(buffer, cwd, 2);
+ buffer[2] = 0;
+ }
+ }
+ else
+ {
+ strcpy(buffer, cwd);
+ if (cwd[cwdlen - 1] != '\\' && cwd[cwdlen - 1] != '/')
+ strcat(buffer, "/");
+ }
+ }
+
+ strcat(buffer, source);
+
+ for (ptr = buffer; *ptr; ptr++)
+ if (*ptr == '/')
+ *ptr = '\\';
+
+ if (ptr[-1] == '\\')
+ ptr[-1] = 0;
+
+ strupr(buffer);
+}
+
+static int acl_bin2text(char *data, char *text)
+{
+ ACCINFO *ai;
+ ACCLIST *al;
+ U_INT cnt, offs;
+
+ ai = (ACCINFO *) data;
+ al = (ACCLIST *) (data + sizeof(ACCINFO));
+
+ offs = sprintf(text, "ACL1:%X,%d\n",
+ ai -> acc_attr, ai -> acc_count);
+
+ for (cnt = 0; cnt < ai -> acc_count; cnt++)
+ offs += sprintf(text + offs, "%s,%X\n",
+ al[cnt].acl_ugname, al[cnt].acl_access);
+
+ return strlen(text);
+}
+
+int acl_get(char *server, const char *resource, char *buffer)
+{
+ USHORT datalen;
+ PSZ srv = NULL;
+ int rc;
+
+ if (!acl_init())
+ return -1;
+
+ if (server)
+ srv = server;
+
+ acl_mkpath(path, resource);
+ datalen = 0;
+
+ rc = NetAccessGetInfo(srv, path, 1, data, ACL_BUFFERSIZE, &datalen);
+
+ if (rc == 0)
+ acl_bin2text(data, buffer);
+
+ return rc;
+}
+
+static int acl_text2bin(char *data, char *text, char *path)
+{
+ ACCINFO *ai;
+ ACCLIST *al;
+ char *ptr, *ptr2;
+ U_INT cnt;
+
+ ai = (ACCINFO *) data;
+ ai -> acc_resource_name = PTR16(path);
+
+ if (sscanf(text, "ACL1:%hX,%hd",
+ &ai -> acc_attr, &ai -> acc_count) != 2)
+ return ERROR_INVALID_PARAMETER;
+
+ al = (ACCLIST *) (data + sizeof(ACCINFO));
+ ptr = strchr(text, '\n') + 1;
+
+ for (cnt = 0; cnt < ai -> acc_count; cnt++)
+ {
+ ptr2 = strchr(ptr, ',');
+ strncpy(al[cnt].acl_ugname, ptr, ptr2 - ptr);
+ al[cnt].acl_ugname[ptr2 - ptr] = 0;
+ sscanf(ptr2 + 1, "%hx", &al[cnt].acl_access);
+ ptr = strchr(ptr, '\n') + 1;
+ }
+
+ return sizeof(ACCINFO) + ai -> acc_count * sizeof(ACCLIST);
+}
+
+int acl_set(char *server, const char *resource, char *buffer)
+{
+ USHORT datalen;
+ PSZ srv = NULL;
+
+ if (!acl_init())
+ return -1;
+
+ if (server)
+ srv = server;
+
+ acl_mkpath(path, resource);
+
+ ai -> acc_resource_name = PTR16(path);
+ ai -> acc_attr = 0;
+ ai -> acc_count = 0;
+
+ NetAccessAdd(srv, 1, ai, sizeof(ACCINFO));
+ /* Ignore any errors, most probably because ACL already exists. */
+ /* In any such case, try updating the existing ACL. */
+
+ datalen = acl_text2bin(data, buffer, path);
+
+ return NetAccessSetInfo(srv, path, 1, data, datalen, 0);
+}
+
+/* end of os2acl.c */
diff --git a/os2/os2acl.h b/os2/os2acl.h
new file mode 100644
index 0000000..03bb8a2
--- /dev/null
+++ b/os2/os2acl.h
@@ -0,0 +1,34 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* os2acl.h
+ *
+ * Author: Kai Uwe Rommel <rommel@ars.de>
+ * Created: Fri Mar 29 1996
+ */
+
+/* $Id: os2acl.h,v 1.1 1996/03/30 09:35:00 rommel Exp rommel $ */
+
+/*
+ * $Log: os2acl.h,v $
+ * Revision 1.1 1996/03/30 09:35:00 rommel
+ * Initial revision
+ *
+ */
+
+#ifndef _OS2ACL_H
+#define _OS2ACL_H
+
+#define ACL_BUFFERSIZE 4096
+
+int acl_get(char *server, const char *resource, char *buffer);
+int acl_set(char *server, const char *resource, char *buffer);
+
+#endif /* _OS2ACL_H */
+
+/* end of os2acl.h */
diff --git a/os2/os2zip.c b/os2/os2zip.c
new file mode 100644
index 0000000..83bc3bc
--- /dev/null
+++ b/os2/os2zip.c
@@ -0,0 +1,1213 @@
+/*
+ * @(#)dir.c 1.4 87/11/06 Public Domain.
+ *
+ * A public domain implementation of BSD directory routines for
+ * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
+ * August 1987
+ *
+ * Ported to OS/2 by Kai Uwe Rommel
+ * Addition of other OS/2 file system specific code
+ * Placed into the public domain
+ */
+
+/* does also contain EA access code for use in ZIP */
+
+
+#ifdef OS2
+
+
+#if defined(__EMX__) && !defined(__32BIT__)
+# define __32BIT__
+#endif
+
+#include "zip.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#ifndef __BORLANDC__
+#include <malloc.h>
+#endif
+
+#define INCL_NOPM
+#define INCL_DOSNLS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include "os2zip.h"
+#include "os2acl.h"
+
+
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+
+#ifdef __32BIT__
+#define DosFindFirst(p1, p2, p3, p4, p5, p6) \
+ DosFindFirst(p1, p2, p3, p4, p5, p6, 1)
+#else
+#define DosQueryCurrentDisk DosQCurDisk
+#define DosQueryFSAttach(p1, p2, p3, p4, p5) \
+ DosQFSAttach(p1, p2, p3, p4, p5, 0)
+#define DosQueryFSInfo(d, l, b, s) \
+ DosQFSInfo(d, l, b, s)
+#define DosQueryPathInfo(p1, p2, p3, p4) \
+ DosQPathInfo(p1, p2, p3, p4, 0)
+#define DosSetPathInfo(p1, p2, p3, p4, p5) \
+ DosSetPathInfo(p1, p2, p3, p4, p5, 0)
+#define DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7) \
+ DosEnumAttribute(p1, p2, p3, p4, p5, p6, p7, 0)
+#define DosFindFirst(p1, p2, p3, p4, p5, p6) \
+ DosFindFirst(p1, p2, p3, p4, p5, p6, 0)
+#define DosMapCase DosCaseMap
+#endif
+
+
+#ifndef UTIL
+
+extern int noisy;
+
+#ifndef S_IFMT
+#define S_IFMT 0xF000
+#endif
+
+static int attributes = _A_DIR | _A_HIDDEN | _A_SYSTEM;
+
+static char *getdirent(char *);
+static void free_dircontents(struct _dircontents *);
+
+#ifdef __32BIT__
+static HDIR hdir;
+static ULONG count;
+static FILEFINDBUF3 find;
+#else
+static HDIR hdir;
+static USHORT count;
+static FILEFINDBUF find;
+#endif
+
+DIR *opendir(const char *name)
+{
+ struct stat statb;
+ DIR *dirp;
+ char c;
+ char *s;
+ struct _dircontents *dp;
+ char nbuf[MAXPATHLEN + 1];
+ int len;
+
+ attributes = hidden_files ? (_A_DIR | _A_HIDDEN | _A_SYSTEM) : _A_DIR;
+
+ strcpy(nbuf, name);
+ if ((len = strlen(nbuf)) == 0)
+ return NULL;
+
+ if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len > 1))
+ {
+ nbuf[len - 1] = 0;
+ --len;
+
+ if (nbuf[len - 1] == ':')
+ {
+ strcpy(nbuf+len, "\\.");
+ len += 2;
+ }
+ }
+ else
+ if (nbuf[len - 1] == ':')
+ {
+ strcpy(nbuf+len, ".");
+ ++len;
+ }
+
+#ifndef __BORLANDC__
+ /* when will we ever see a Borland compiler that can properly stat !!! */
+ if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
+ return NULL;
+#endif
+
+ if ((dirp = malloc(sizeof(DIR))) == NULL)
+ return NULL;
+
+ if (nbuf[len - 1] == '.' && (len == 1 || nbuf[len - 2] != '.'))
+ strcpy(nbuf+len-1, "*.*");
+ else
+ if (((c = nbuf[len - 1]) == '\\' || c == '/') && (len == 1))
+ strcpy(nbuf+len, "*");
+ else
+ strcpy(nbuf+len, "\\*");
+
+ /* len is no longer correct (but no longer needed) */
+
+ dirp -> dd_loc = 0;
+ dirp -> dd_contents = dirp -> dd_cp = NULL;
+
+ if ((s = getdirent(nbuf)) == NULL)
+ return dirp;
+
+ do
+ {
+ if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
+ ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL) )
+ {
+ if (dp)
+ free(dp);
+ free_dircontents(dirp -> dd_contents);
+
+ return NULL;
+ }
+
+ if (dirp -> dd_contents)
+ {
+ dirp -> dd_cp -> _d_next = dp;
+ dirp -> dd_cp = dirp -> dd_cp -> _d_next;
+ }
+ else
+ dirp -> dd_contents = dirp -> dd_cp = dp;
+
+ strcpy(dp -> _d_entry, s);
+ dp -> _d_next = NULL;
+
+ dp -> _d_size = find.cbFile;
+ dp -> _d_mode = find.attrFile;
+ dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
+ dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
+ }
+ while ((s = getdirent(NULL)) != NULL);
+
+ dirp -> dd_cp = dirp -> dd_contents;
+
+ return dirp;
+}
+
+void closedir(DIR * dirp)
+{
+ free_dircontents(dirp -> dd_contents);
+ free(dirp);
+}
+
+struct dirent *readdir(DIR * dirp)
+{
+ static struct dirent dp;
+
+ if (dirp -> dd_cp == NULL)
+ return NULL;
+
+ dp.d_namlen = dp.d_reclen =
+ strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
+
+ dp.d_ino = 0;
+
+ dp.d_size = dirp -> dd_cp -> _d_size;
+ dp.d_mode = dirp -> dd_cp -> _d_mode;
+ dp.d_time = dirp -> dd_cp -> _d_time;
+ dp.d_date = dirp -> dd_cp -> _d_date;
+
+ dirp -> dd_cp = dirp -> dd_cp -> _d_next;
+ dirp -> dd_loc++;
+
+ return &dp;
+}
+
+void seekdir(DIR * dirp, long off)
+{
+ long i = off;
+ struct _dircontents *dp;
+
+ if (off >= 0)
+ {
+ for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
+
+ dirp -> dd_loc = off - (i + 1);
+ dirp -> dd_cp = dp;
+ }
+}
+
+long telldir(DIR * dirp)
+{
+ return dirp -> dd_loc;
+}
+
+static void free_dircontents(struct _dircontents * dp)
+{
+ struct _dircontents *odp;
+
+ while (dp)
+ {
+ if (dp -> _d_entry)
+ free(dp -> _d_entry);
+
+ dp = (odp = dp) -> _d_next;
+ free(odp);
+ }
+}
+
+static char *getdirent(char *dir)
+{
+ int done;
+ static int lower;
+
+ if (dir != NULL)
+ { /* get first entry */
+ hdir = HDIR_SYSTEM;
+ count = 1;
+ done = DosFindFirst(dir, &hdir, attributes, &find, sizeof(find), &count);
+ lower = IsFileSystemFAT(dir);
+ }
+ else /* get next entry */
+ done = DosFindNext(hdir, &find, sizeof(find), &count);
+
+ if (done == 0)
+ {
+ if (lower)
+ StringLower(find.achName);
+ return find.achName;
+ }
+ else
+ {
+ DosFindClose(hdir);
+ return NULL;
+ }
+}
+
+/* FAT / HPFS detection */
+
+int IsFileSystemFAT(char *dir)
+{
+ static USHORT nLastDrive = -1, nResult;
+ ULONG lMap;
+ BYTE bData[64];
+ char bName[3];
+#ifdef __32BIT__
+ ULONG nDrive, cbData;
+ PFSQBUFFER2 pData = (PFSQBUFFER2) bData;
+#else
+ USHORT nDrive, cbData;
+ PFSQBUFFER pData = (PFSQBUFFER) bData;
+#endif
+
+ /* We separate FAT and HPFS+other file systems here.
+ at the moment I consider other systems to be similar to HPFS,
+ i.e. support long file names and being case sensitive */
+
+ if (isalpha(dir[0]) && (dir[1] == ':'))
+ nDrive = to_up(dir[0]) - '@';
+ else
+ DosQueryCurrentDisk(&nDrive, &lMap);
+
+ if (nDrive == nLastDrive)
+ return nResult;
+
+ bName[0] = (char) (nDrive + '@');
+ bName[1] = ':';
+ bName[2] = 0;
+
+ nLastDrive = nDrive;
+ cbData = sizeof(bData);
+
+ if (!DosQueryFSAttach(bName, 0, FSAIL_QUERYNAME, (PVOID) pData, &cbData))
+ nResult = !strcmp((char *) pData -> szFSDName + pData -> cbName, "FAT");
+ else
+ nResult = FALSE;
+
+ /* End of this ugly code */
+ return nResult;
+}
+
+/* access mode bits and time stamp */
+
+int GetFileMode(char *name)
+{
+#ifdef __32BIT__
+ FILESTATUS3 fs;
+ return DosQueryPathInfo(name, 1, &fs, sizeof(fs)) ? -1 : fs.attrFile;
+#else
+ USHORT mode;
+ return DosQFileMode(name, &mode, 0L) ? -1 : mode;
+#endif
+}
+
+ulg GetFileTime(char *name)
+{
+#ifdef __32BIT__
+ FILESTATUS3 fs;
+#else
+ FILESTATUS fs;
+#endif
+ USHORT nDate, nTime;
+ DATETIME dtCurrent;
+
+ if (strcmp(name, "-") == 0)
+ {
+ DosGetDateTime(&dtCurrent);
+ fs.fdateLastWrite.day = dtCurrent.day;
+ fs.fdateLastWrite.month = dtCurrent.month;
+ fs.fdateLastWrite.year = dtCurrent.year - 1980;
+ fs.ftimeLastWrite.hours = dtCurrent.hours;
+ fs.ftimeLastWrite.minutes = dtCurrent.minutes;
+ fs.ftimeLastWrite.twosecs = dtCurrent.seconds / 2;
+ }
+ else
+ if (DosQueryPathInfo(name, 1, (PBYTE) &fs, sizeof(fs)))
+ return -1;
+
+ nDate = * (USHORT *) &fs.fdateLastWrite;
+ nTime = * (USHORT *) &fs.ftimeLastWrite;
+
+ return ((ULONG) nDate) << 16 | nTime;
+}
+
+void SetFileTime(char *path, ulg stamp)
+{
+ FILESTATUS fs;
+ USHORT fd, ft;
+
+ if (DosQueryPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs)))
+ return;
+
+ fd = (USHORT) (stamp >> 16);
+ ft = (USHORT) stamp;
+ fs.fdateLastWrite = fs.fdateCreation = * (FDATE *) &fd;
+ fs.ftimeLastWrite = fs.ftimeCreation = * (FTIME *) &ft;
+
+ DosSetPathInfo(path, FIL_STANDARD, (PBYTE) &fs, sizeof(fs), 0);
+}
+
+/* read volume label */
+
+char *getVolumeLabel(int drive, unsigned long *vtime, unsigned long *vmode,
+ time_t *utim)
+{
+ static FSINFO fi;
+
+ if (DosQueryFSInfo(drive ? drive - 'A' + 1 : 0,
+ FSIL_VOLSER, (PBYTE) &fi, sizeof(fi)))
+ return NULL;
+
+ time(utim);
+ *vtime = unix2dostime(utim);
+ *vmode = _A_VOLID | _A_ARCHIVE;
+
+ return (fi.vol.cch > 0) ? fi.vol.szVolLabel : NULL;
+}
+
+/* FAT / HPFS name conversion stuff */
+
+int IsFileNameValid(char *name)
+{
+ HFILE hf;
+#ifdef __32BIT__
+ ULONG uAction;
+#else
+ USHORT uAction;
+#endif
+
+ switch(DosOpen(name, &hf, &uAction, 0, 0, FILE_OPEN,
+ OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0))
+ {
+ case ERROR_INVALID_NAME:
+ case ERROR_FILENAME_EXCED_RANGE:
+ return FALSE;
+ case NO_ERROR:
+ DosClose(hf);
+ default:
+ return TRUE;
+ }
+}
+
+void ChangeNameForFAT(char *name)
+{
+ char *src, *dst, *next, *ptr, *dot, *start;
+ static char invalid[] = ":;,=+\"[]<>| \t";
+
+ if (isalpha(name[0]) && (name[1] == ':'))
+ start = name + 2;
+ else
+ start = name;
+
+ src = dst = start;
+ if ((*src == '/') || (*src == '\\'))
+ src++, dst++;
+
+ while (*src)
+ {
+ for (next = src; *next && (*next != '/') && (*next != '\\'); next++);
+
+ for (ptr = src, dot = NULL; ptr < next; ptr++)
+ if (*ptr == '.')
+ {
+ dot = ptr; /* remember last dot */
+ *ptr = '_';
+ }
+
+ if (dot == NULL)
+ for (ptr = src; ptr < next; ptr++)
+ if (*ptr == '_')
+ dot = ptr; /* remember last _ as if it were a dot */
+
+ if (dot && (dot > src) &&
+ ((next - dot <= 4) ||
+ ((next - src > 8) && (dot - src > 3))))
+ {
+ if (dot)
+ *dot = '.';
+
+ for (ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++)
+ *dst++ = *ptr;
+
+ for (ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++)
+ *dst++ = *ptr;
+ }
+ else
+ {
+ if (dot && (next - src == 1))
+ *dot = '.'; /* special case: "." as a path component */
+
+ for (ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++)
+ *dst++ = *ptr;
+ }
+
+ *dst++ = *next; /* either '/' or 0 */
+
+ if (*next)
+ {
+ src = next + 1;
+
+ if (*src == 0) /* handle trailing '/' on dirs ! */
+ *dst = 0;
+ }
+ else
+ break;
+ }
+
+ for (src = start; *src != 0; ++src)
+ if ((strchr(invalid, *src) != NULL) || (*src == ' '))
+ *src = '_';
+}
+
+/* .LONGNAME EA code */
+
+typedef struct
+{
+ ULONG cbList; /* length of value + 22 */
+#ifdef __32BIT__
+ ULONG oNext;
+#endif
+ BYTE fEA; /* 0 */
+ BYTE cbName; /* length of ".LONGNAME" = 9 */
+ USHORT cbValue; /* length of value + 4 */
+ BYTE szName[10]; /* ".LONGNAME" */
+ USHORT eaType; /* 0xFFFD for length-preceded ASCII */
+ USHORT eaSize; /* length of value */
+ BYTE szValue[CCHMAXPATH];
+}
+FEALST;
+
+typedef struct
+{
+ ULONG cbList;
+#ifdef __32BIT__
+ ULONG oNext;
+#endif
+ BYTE cbName;
+ BYTE szName[10]; /* ".LONGNAME" */
+}
+GEALST;
+
+char *GetLongNameEA(const char *name)
+{
+ EAOP eaop;
+ GEALST gealst;
+ static FEALST fealst;
+ char *ptr;
+
+ eaop.fpGEAList = (PGEALIST) &gealst;
+ eaop.fpFEAList = (PFEALIST) &fealst;
+ eaop.oError = 0;
+
+ strcpy((char *) gealst.szName, ".LONGNAME");
+ gealst.cbName = (BYTE) strlen((char *) gealst.szName);
+#ifdef __32BIT__
+ gealst.oNext = 0;
+#endif
+
+ gealst.cbList = sizeof(gealst);
+ fealst.cbList = sizeof(fealst);
+
+ if (DosQueryPathInfo(name, FIL_QUERYEASFROMLIST,
+ (PBYTE) &eaop, sizeof(eaop)))
+ return NULL;
+
+ if (fealst.cbValue > 4 && fealst.eaType == 0xFFFD)
+ {
+ fealst.szValue[fealst.eaSize] = 0;
+
+ for (ptr = fealst.szValue; *ptr; ptr++)
+ if (*ptr == '/' || *ptr == '\\')
+ *ptr = '!';
+
+ return (char *) fealst.szValue;
+ }
+
+ return NULL;
+}
+
+char *GetLongPathEA(const char *name)
+{
+ static char nbuf[CCHMAXPATH + 1];
+ char tempbuf[CCHMAXPATH + 1];
+ char *comp, *next, *ea, sep;
+ BOOL bFound = FALSE;
+
+ nbuf[0] = 0;
+ strncpy(tempbuf, name, CCHMAXPATH);
+ tempbuf[CCHMAXPATH] = '\0';
+ next = tempbuf;
+
+ while (*next)
+ {
+ comp = next;
+
+ while (*next != '\\' && *next != '/' && *next != 0)
+ next++;
+
+ sep = *next;
+ *next = 0;
+
+ ea = GetLongNameEA(tempbuf);
+ strcat(nbuf, ea ? ea : comp);
+ bFound = bFound || (ea != NULL);
+
+ if (sep)
+ {
+ strcat(nbuf, "\\");
+ *next++ = sep;
+ }
+ }
+
+ return (nbuf[0] != 0) && bFound ? nbuf : NULL;
+}
+
+/* general EA code */
+
+typedef struct
+{
+ USHORT nID;
+ USHORT nSize;
+ ULONG lSize;
+}
+EFHEADER, *PEFHEADER;
+
+#ifdef __32BIT__
+
+/* Perhaps due to bugs in the current OS/2 2.0 kernel, the success or
+ failure of the DosEnumAttribute() and DosQueryPathInfo() system calls
+ depends on the area where the return buffers are allocated. This
+ differs for the various compilers, for some alloca() works, for some
+ malloc() works, for some, both work. We'll have to live with that. */
+
+/* The use of malloc() is not very convenient, because it requires
+ backtracking (i.e. free()) at error returns. We do that for system
+ calls that may fail, but not for malloc() calls, because they are VERY
+ unlikely to fail. If ever, we just leave some memory allocated
+ over the usually short lifetime of a zip process ... */
+
+#ifdef __GNUC__
+#define alloc(x) alloca(x)
+#define unalloc(x)
+#else
+#define alloc(x) malloc(x)
+#define unalloc(x) free(x)
+#endif
+
+void GetEAs(char *path, char **bufptr, size_t *size,
+ char **cbufptr, size_t *csize)
+{
+ FILESTATUS4 fs;
+ PDENA2 pDENA, pFound;
+ EAOP2 eaop;
+ PGEA2 pGEA;
+ PGEA2LIST pGEAlist;
+ PFEA2LIST pFEAlist;
+ PEFHEADER pEAblock;
+ ULONG ulAttributes, ulMemoryBlock;
+ ULONG nLength;
+ ULONG nBlock;
+ char szName[CCHMAXPATH];
+
+ *size = *csize = 0;
+
+ strcpy(szName, path);
+ nLength = strlen(szName);
+ if (szName[nLength - 1] == '/')
+ szName[nLength - 1] = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs)))
+ return;
+ nBlock = max(fs.cbList, 65535);
+ if ((pDENA = alloc((size_t) nBlock)) == NULL)
+ return;
+
+ ulAttributes = -1;
+
+ if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, nBlock,
+ &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
+ || ulAttributes == 0
+ || (pGEAlist = alloc((size_t) nBlock)) == NULL)
+ {
+ unalloc(pDENA);
+ return;
+ }
+
+ pGEA = pGEAlist -> list;
+ memset(pGEAlist, 0, nBlock);
+ pFound = pDENA;
+
+ while (ulAttributes--)
+ {
+ if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
+ {
+ pGEA -> cbName = pFound -> cbName;
+ strcpy(pGEA -> szName, pFound -> szName);
+
+ nLength = sizeof(GEA2) + strlen(pGEA -> szName);
+ nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
+
+ pGEA -> oNextEntryOffset = ulAttributes ? nLength : 0;
+ pGEA = (PGEA2) ((PCH) pGEA + nLength);
+ }
+
+ pFound = (PDENA2) ((PCH) pFound + pFound -> oNextEntryOffset);
+ }
+
+ if (pGEA == pGEAlist -> list) /* no attributes to save */
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
+
+ pFEAlist = (PVOID) pDENA; /* reuse buffer */
+ pFEAlist -> cbList = nBlock;
+
+ eaop.fpGEA2List = pGEAlist;
+ eaop.fpFEA2List = pFEAlist;
+ eaop.oError = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
+ (PBYTE) &eaop, sizeof(eaop)))
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ /* The maximum compressed size is (in case of STORE type) the
+ uncompressed size plus the size of the compression type field
+ plus the size of the CRC field + 2*5 deflate overhead bytes
+ for uncompressable data.
+ (5 bytes per 32Kb block, max compressed size = 2 blocks) */
+
+ ulAttributes = pFEAlist -> cbList;
+ ulMemoryBlock = ulAttributes +
+ sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
+ pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER) + ulMemoryBlock);
+
+ if (pEAblock == NULL)
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ *bufptr = (char *) pEAblock;
+ *size = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes; /* uncompressed size */
+
+ nLength = memcompress((char *) (pEAblock + 1), ulMemoryBlock,
+ (char *) pFEAlist, ulAttributes);
+ *size += nLength;
+ pEAblock -> nSize += nLength;
+
+ if ((pEAblock = (PEFHEADER) malloc(sizeof(EFHEADER))) == NULL)
+ {
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+ return;
+ }
+
+ *cbufptr = (char *) pEAblock;
+ *csize = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes;
+
+ if (noisy)
+ printf(" (%ld bytes EA's)", ulAttributes);
+
+ unalloc(pDENA);
+ unalloc(pGEAlist);
+}
+
+#else /* !__32BIT__ */
+
+typedef struct
+{
+ ULONG oNextEntryOffset;
+ BYTE fEA;
+ BYTE cbName;
+ USHORT cbValue;
+ CHAR szName[1];
+}
+FEA2, *PFEA2;
+
+typedef struct
+{
+ ULONG cbList;
+ FEA2 list[1];
+}
+FEA2LIST, *PFEA2LIST;
+
+void GetEAs(char *path, char **bufptr, size_t *size,
+ char **cbufptr, size_t *csize)
+{
+ FILESTATUS2 fs;
+ PDENA1 pDENA, pFound;
+ EAOP eaop;
+ PGEALIST pGEAlist;
+ PGEA pGEA;
+ PFEALIST pFEAlist;
+ PFEA pFEA;
+ PFEA2LIST pFEA2list;
+ PFEA2 pFEA2;
+ EFHEADER *pEAblock;
+ ULONG ulAttributes;
+ USHORT nLength, nMaxSize;
+ char szName[CCHMAXPATH];
+
+ *size = *csize = 0;
+
+ strcpy(szName, path);
+ nLength = strlen(szName);
+ if (szName[nLength - 1] == '/')
+ szName[nLength - 1] = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASIZE, (PBYTE) &fs, sizeof(fs))
+ || fs.cbList <= 2 * sizeof(ULONG))
+ return;
+
+ ulAttributes = -1;
+ nMaxSize = (USHORT) min(fs.cbList * 2, 65520L);
+
+ if ((pDENA = malloc((size_t) nMaxSize)) == NULL)
+ return;
+
+ if (DosEnumAttribute(ENUMEA_REFTYPE_PATH, szName, 1, pDENA, fs.cbList,
+ &ulAttributes, ENUMEA_LEVEL_NO_VALUE)
+ || ulAttributes == 0
+ || (pGEAlist = malloc(nMaxSize)) == NULL)
+ {
+ free(pDENA);
+ return;
+ }
+
+ pGEA = pGEAlist -> list;
+ pFound = pDENA;
+
+ while (ulAttributes--)
+ {
+ nLength = strlen(pFound -> szName);
+
+ if (!(strcmp(pFound -> szName, ".LONGNAME") == 0 && use_longname_ea))
+ {
+ pGEA -> cbName = pFound -> cbName;
+ strcpy(pGEA -> szName, pFound -> szName);
+
+ pGEA++;
+ pGEA = (PGEA) (((PCH) pGEA) + nLength);
+ }
+
+ pFound++;
+ pFound = (PDENA1) (((PCH) pFound) + nLength);
+ }
+
+ if (pGEA == pGEAlist -> list)
+ {
+ free(pDENA);
+ free(pGEAlist);
+ return;
+ }
+
+ pGEAlist -> cbList = (PCH) pGEA - (PCH) pGEAlist;
+
+ pFEAlist = (PFEALIST) pDENA; /* reuse buffer */
+ pFEAlist -> cbList = fs.cbList;
+ pFEA = pFEAlist -> list;
+
+ eaop.fpGEAList = pGEAlist;
+ eaop.fpFEAList = pFEAlist;
+ eaop.oError = 0;
+
+ if (DosQueryPathInfo(szName, FIL_QUERYEASFROMLIST,
+ (PBYTE) &eaop, sizeof(eaop)))
+ {
+ free(pDENA);
+ free(pGEAlist);
+ return;
+ }
+
+ /* now convert into new OS/2 2.0 32-bit format */
+
+ pFEA2list = (PFEA2LIST) pGEAlist; /* reuse buffer */
+ pFEA2 = pFEA2list -> list;
+
+ while ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList)
+ {
+ nLength = sizeof(FEA) + pFEA -> cbName + 1 + pFEA -> cbValue;
+ memcpy((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset), pFEA, nLength);
+ memset((PCH) pFEA2 + sizeof(pFEA2 -> oNextEntryOffset) + nLength, 0, 3);
+ pFEA = (PFEA) ((PCH) pFEA + nLength);
+
+ nLength = sizeof(FEA2) + pFEA2 -> cbName + 1 + pFEA2 -> cbValue;
+ nLength = ((nLength - 1) / sizeof(ULONG) + 1) * sizeof(ULONG);
+ /* rounded up to 4-byte boundary */
+ pFEA2 -> oNextEntryOffset =
+ ((PCH) pFEA - (PCH) pFEAlist < pFEAlist -> cbList) ? nLength : 0;
+ pFEA2 = (PFEA2) ((PCH) pFEA2 + nLength);
+ }
+
+ pFEA2list -> cbList = (PCH) pFEA2 - (PCH) pFEA2list;
+ ulAttributes = pFEA2list -> cbList;
+
+ pEAblock = (PEFHEADER) pDENA; /* reuse buffer */
+
+ *bufptr = (char *) pEAblock;
+ *size = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes; /* uncompressed size */
+
+ nLength = (USHORT) memcompress((char *) (pEAblock + 1),
+ nMaxSize - sizeof(EFHEADER), (char *) pFEA2list, ulAttributes);
+
+ *size += nLength;
+ pEAblock -> nSize += nLength;
+
+ pEAblock = (PEFHEADER) pGEAlist;
+
+ *cbufptr = (char *) pEAblock;
+ *csize = sizeof(EFHEADER);
+
+ pEAblock -> nID = EF_OS2EA;
+ pEAblock -> nSize = sizeof(pEAblock -> lSize);
+ pEAblock -> lSize = ulAttributes;
+
+ if (noisy)
+ printf(" (%ld bytes EA's)", ulAttributes);
+}
+
+#endif /* __32BIT__ */
+
+void GetACL(char *path, char **bufptr, size_t *size,
+ char **cbufptr, size_t *csize)
+{
+ static char *buffer;
+ char *cbuffer;
+ long bytes, cbytes;
+ PEFHEADER pACLblock;
+
+ if (buffer == NULL) /* avoid frequent allocation (for every file) */
+ if ((buffer = malloc(ACL_BUFFERSIZE)) == NULL)
+ return;
+
+ if (acl_get(NULL, path, buffer))
+ return; /* this will be the most likely case */
+
+ bytes = strlen(buffer);
+
+ /* The maximum compressed size is (in case of STORE type) the
+ uncompressed size plus the size of the compression type field
+ plus the size of the CRC field + 2*5 deflate overhead bytes
+ for uncompressable data.
+ (5 bytes per 32Kb block, max compressed size = 2 blocks) */
+
+ cbytes = bytes + sizeof(USHORT) + sizeof(ULONG) + EB_DEFLAT_EXTRA;
+ if ((*bufptr = realloc(*bufptr, *size + sizeof(EFHEADER) + cbytes)) == NULL)
+ return;
+
+ pACLblock = (PEFHEADER) (*bufptr + *size);
+
+ cbuffer = (char *) (pACLblock + 1);
+ cbytes = memcompress(cbuffer, cbytes, buffer, bytes);
+
+ *size += sizeof(EFHEADER) + cbytes;
+
+ pACLblock -> nID = EF_ACL;
+ pACLblock -> nSize = sizeof(pACLblock -> lSize) + cbytes;
+ pACLblock -> lSize = bytes; /* uncompressed size */
+
+ if ((*cbufptr = realloc(*cbufptr, *csize + sizeof(EFHEADER))) == NULL)
+ return;
+
+ pACLblock = (PEFHEADER) (*cbufptr + *csize);
+ *csize += sizeof(EFHEADER);
+
+ pACLblock -> nID = EF_ACL;
+ pACLblock -> nSize = sizeof(pACLblock -> lSize);
+ pACLblock -> lSize = bytes;
+
+ if (noisy)
+ printf(" (%ld bytes ACL)", bytes);
+}
+
+#ifdef USE_EF_UT_TIME
+
+int GetExtraTime(struct zlist far *z, iztimes *z_utim)
+{
+ int eb_c_size = EB_HEADSIZE + EB_UT_LEN(1);
+ int eb_l_size = eb_c_size;
+ char *eb_c_ptr;
+ char *eb_l_ptr;
+ unsigned long ultime;
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid) return ZE_OK; /* skip silently no correct tz info */
+#endif
+
+ eb_c_ptr = realloc(z->cextra, (z->cext + eb_c_size));
+ if (eb_c_ptr == NULL)
+ return ZE_MEM;
+ z->cextra = eb_c_ptr;
+ eb_c_ptr += z->cext;
+ z->cext += eb_c_size;
+
+ eb_c_ptr[0] = 'U';
+ eb_c_ptr[1] = 'T';
+ eb_c_ptr[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ eb_c_ptr[3] = 0;
+ eb_c_ptr[4] = EB_UT_FL_MTIME;
+ ultime = (unsigned long) z_utim->mtime;
+ eb_c_ptr[5] = (char)(ultime);
+ eb_c_ptr[6] = (char)(ultime >> 8);
+ eb_c_ptr[7] = (char)(ultime >> 16);
+ eb_c_ptr[8] = (char)(ultime >> 24);
+
+ if (z_utim->mtime != z_utim->atime || z_utim->mtime != z_utim->ctime)
+ {
+ eb_c_ptr[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+ eb_l_size = EB_HEADSIZE + EB_UT_LEN(3); /* only on HPFS they can differ */
+ /* so only then it makes sense to store all three time stamps */
+ }
+
+ eb_l_ptr = realloc(z->extra, (z->ext + eb_l_size));
+ if (eb_l_ptr == NULL)
+ return ZE_MEM;
+ z->extra = eb_l_ptr;
+ eb_l_ptr += z->ext;
+ z->ext += eb_l_size;
+
+ memcpy(eb_l_ptr, eb_c_ptr, eb_c_size);
+
+ if (eb_l_size > eb_c_size)
+ {
+ eb_l_ptr[2] = EB_UT_LEN(3);
+ ultime = (unsigned long) z_utim->atime;
+ eb_l_ptr[9] = (char)(ultime);
+ eb_l_ptr[10] = (char)(ultime >> 8);
+ eb_l_ptr[11] = (char)(ultime >> 16);
+ eb_l_ptr[12] = (char)(ultime >> 24);
+ ultime = (unsigned long) z_utim->ctime;
+ eb_l_ptr[13] = (char)(ultime);
+ eb_l_ptr[14] = (char)(ultime >> 8);
+ eb_l_ptr[15] = (char)(ultime >> 16);
+ eb_l_ptr[16] = (char)(ultime >> 24);
+ }
+
+ return ZE_OK;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+int set_extra_field(struct zlist far *z, iztimes *z_utim)
+{
+ /* store EA data in local header, and size only in central headers */
+ GetEAs(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+
+ /* store ACL data in local header, and size only in central headers */
+ GetACL(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+
+#ifdef USE_EF_UT_TIME
+ /* store extended time stamps in both headers */
+ return GetExtraTime(z, z_utim);
+#else /* !USE_EF_UT_TIME */
+ return ZE_OK;
+#endif /* ?USE_EF_UT_TIME */
+}
+
+#endif /* !UTIL */
+
+/* Initialize the table of uppercase characters including handling of
+ country dependent characters. */
+
+void init_upper()
+{
+ COUNTRYCODE cc;
+ unsigned nCnt, nU;
+
+ for (nCnt = 0; nCnt < sizeof(upper); nCnt++)
+ upper[nCnt] = lower[nCnt] = (unsigned char) nCnt;
+
+ cc.country = cc.codepage = 0;
+ DosMapCase(sizeof(upper), &cc, (PCHAR) upper);
+
+ for (nCnt = 0; nCnt < 256; nCnt++)
+ {
+ nU = upper[nCnt];
+ if (nU != nCnt && lower[nU] == (unsigned char) nU)
+ lower[nU] = (unsigned char) nCnt;
+ }
+
+ for (nCnt = 'A'; nCnt <= 'Z'; nCnt++)
+ lower[nCnt] = (unsigned char) (nCnt - 'A' + 'a');
+}
+
+char *StringLower(char *szArg)
+{
+ unsigned char *szPtr;
+ for (szPtr = (unsigned char *) szArg; *szPtr; szPtr++)
+ *szPtr = lower[*szPtr];
+ return szArg;
+}
+
+#if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
+void DebugMalloc(void)
+{
+ _dump_allocated(0); /* print out debug malloc memory statistics */
+}
+#endif
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if defined(__IBMC__) || defined(__WATCOMC__) || defined(_MSC_VER)
+ char buf[80];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+# ifdef __EMX__ /* __EMX__ is defined as "1" only (sigh) */
+ "emx+gcc ", __VERSION__,
+# else
+ "gcc/2 ", __VERSION__,
+# endif
+#elif defined(__IBMC__)
+ "IBM ",
+# if (__IBMC__ < 200)
+ (sprintf(buf, "C Set/2 %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+# elif (__IBMC__ < 300)
+ (sprintf(buf, "C Set++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+# else
+ (sprintf(buf, "Visual Age C++ %d.%02d", __IBMC__/100,__IBMC__%100), buf),
+# endif
+#elif defined(__WATCOMC__)
+ "Watcom C", (sprintf(buf, " (__WATCOMC__ = %d)", __WATCOMC__), buf),
+#elif defined(__TURBOC__)
+# ifdef __BORLANDC__
+ "Borland C++",
+# if (__BORLANDC__ < 0x0460)
+ " 1.0",
+# elif (__BORLANDC__ == 0x0460)
+ " 1.5",
+# else
+ " 2.0",
+# endif
+# else
+ "Turbo C",
+# if (__TURBOC__ >= 661)
+ "++ 1.0 or later",
+# elif (__TURBOC__ == 661)
+ " 3.0?",
+# elif (__TURBOC__ == 397)
+ " 2.0",
+# else
+ " 1.0 or 1.5?",
+# endif
+# endif
+#elif defined(MSC)
+ "Microsoft C ",
+# ifdef _MSC_VER
+ (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
+# else
+ "5.1 or earlier",
+# endif
+#else
+ "unknown compiler", "",
+#endif /* __GNUC__ */
+
+ "OS/2",
+
+/* GRR: does IBM C/2 identify itself as IBM rather than Microsoft? */
+#if (defined(MSC) || (defined(__WATCOMC__) && !defined(__386__)))
+# if defined(M_I86HM) || defined(__HUGE__)
+ " (16-bit, huge)",
+# elif defined(M_I86LM) || defined(__LARGE__)
+ " (16-bit, large)",
+# elif defined(M_I86MM) || defined(__MEDIUM__)
+ " (16-bit, medium)",
+# elif defined(M_I86CM) || defined(__COMPACT__)
+ " (16-bit, compact)",
+# elif defined(M_I86SM) || defined(__SMALL__)
+ " (16-bit, small)",
+# elif defined(M_I86TM) || defined(__TINY__)
+ " (16-bit, tiny)",
+# else
+ " (16-bit)",
+# endif
+#else
+ " 2.x/3.x (32-bit)",
+#endif
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+ /* temporary debugging code for Borland compilers only */
+#ifdef __TURBOC__
+ printf("\t(__TURBOC__ = 0x%04x = %d)\n", __TURBOC__, __TURBOC__);
+#ifdef __BORLANDC__
+ printf("\t(__BORLANDC__ = 0x%04x)\n",__BORLANDC__);
+#else
+ printf("\tdebug(__BORLANDC__ not defined)\n");
+#endif
+#ifdef __TCPLUSPLUS__
+ printf("\t(__TCPLUSPLUS__ = 0x%04x)\n", __TCPLUSPLUS__);
+#else
+ printf("\tdebug(__TCPLUSPLUS__ not defined)\n");
+#endif
+#ifdef __BCPLUSPLUS__
+ printf("\t(__BCPLUSPLUS__ = 0x%04x)\n\n", __BCPLUSPLUS__);
+#else
+ printf("\tdebug(__BCPLUSPLUS__ not defined)\n\n");
+#endif
+#endif /* __TURBOC__ */
+
+} /* end function version_local() */
+
+#endif /* OS2 */
diff --git a/os2/os2zip.h b/os2/os2zip.h
new file mode 100644
index 0000000..06d0a02
--- /dev/null
+++ b/os2/os2zip.h
@@ -0,0 +1,84 @@
+/*
+ * @(#) dir.h 1.4 87/11/06 Public Domain.
+ *
+ * A public domain implementation of BSD directory routines for
+ * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
+ * August 1987
+ *
+ * Ported to OS/2 by Kai Uwe Rommel
+ * Addition of other OS/2 file system specific code
+ * Placed into the public domain
+ */
+
+
+#define MAXNAMLEN 256
+#define MAXPATHLEN 256
+
+#define _A_RONLY 0x01
+#define _A_HIDDEN 0x02
+#define _A_SYSTEM 0x04
+#define _A_VOLID 0x08
+#define _A_DIR 0x10
+#define _A_ARCHIVE 0x20
+
+
+struct dirent
+{
+ ino_t d_ino; /* a bit of a farce */
+ int d_reclen; /* more farce */
+ int d_namlen; /* length of d_name */
+ char d_name[MAXNAMLEN + 1]; /* null terminated */
+ /* nonstandard fields */
+ long d_size; /* size in bytes */
+ unsigned d_mode; /* DOS or OS/2 file attributes */
+ unsigned d_time;
+ unsigned d_date;
+};
+
+/* The fields d_size and d_mode are extensions by me (Kai Uwe Rommel).
+ * The find_first and find_next calls deliver this data without any extra cost.
+ * If this data is needed, these fields save a lot of extra calls to stat()
+ * (each stat() again performs a find_first call !).
+ */
+
+struct _dircontents
+{
+ char *_d_entry;
+ long _d_size;
+ unsigned _d_mode, _d_time, _d_date;
+ struct _dircontents *_d_next;
+};
+
+typedef struct _dirdesc
+{
+ int dd_id; /* uniquely identify each open directory */
+ long dd_loc; /* where we are in directory entry is this */
+ struct _dircontents *dd_contents; /* pointer to contents of dir */
+ struct _dircontents *dd_cp; /* pointer to current position */
+}
+DIR;
+
+
+extern DIR *opendir(const char *);
+extern struct dirent *readdir(DIR *);
+extern void seekdir(DIR *, long);
+extern long telldir(DIR *);
+extern void closedir(DIR *);
+#define rewinddir(dirp) seekdir(dirp, 0L)
+
+int GetFileMode(char *name);
+ulg GetFileTime(char *name);
+void SetFileTime(char *path, ulg stamp);
+char *getVolumeLabel(int drive, unsigned long *time, unsigned long *mode,
+ time_t *utim);
+
+int IsFileNameValid(char *name);
+int IsFileSystemFAT(char *dir);
+void ChangeNameForFAT(char *name);
+
+char *GetLongNameEA(const char *name);
+char *GetLongPathEA(const char *name);
+void GetEAs(char *name, char **bufptr, size_t *size,
+ char **cbufptr, size_t *csize);
+
+char *StringLower(char *);
diff --git a/os2/osdep.h b/os2/osdep.h
new file mode 100644
index 0000000..ea2c3f9
--- /dev/null
+++ b/os2/osdep.h
@@ -0,0 +1,173 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#if defined(__OS2__) && !defined(OS2)
+# define OS2
+#endif
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+# ifndef MSC
+# define MSC /* This should work for older MSC, too! */
+# endif
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+# define WATCOMC_386
+#endif
+
+#if defined(__EMX__) || defined(WATCOMC_386) || defined(__BORLANDC__)
+# if (defined(OS2) && !defined(__32BIT__))
+# define __32BIT__
+# endif
+#endif
+
+#if defined(OS2) && !defined(__32BIT__)
+# define MEMORY16
+#endif
+
+#ifndef NO_ASM
+# define ASMV
+/* # define ASM_CRC */
+#endif
+
+/* enable creation of UTC time fields unless explicitely suppressed */
+#if (!defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME))
+# define USE_EF_UT_TIME
+#endif
+
+/* check that TZ environment variable is defined before using UTC times */
+#if (!defined(NO_IZ_CHECK_TZ) && !defined(IZ_CHECK_TZ))
+# define IZ_CHECK_TZ
+#endif
+
+#ifndef ZP_NEED_MEMCOMPR
+# define ZP_NEED_MEMCOMPR
+#endif
+
+#ifdef MEMORY16
+# ifdef __TURBOC__
+# include <alloc.h>
+# if defined(__COMPACT__) || defined(__LARGE__) || defined(__HUGE__)
+# if defined(DYNAMIC_CRC_TABLE) && defined(DYNALLOC_CRCTAB)
+ error: No dynamic CRC table allocation with Borland C far data models.
+# endif /* DYNAMIC_CRC_TABLE */
+# endif /* Turbo/Borland C far data memory models */
+# define nearmalloc malloc
+# define nearfree free
+# define DYN_ALLOC
+# else /* !__TURBOC__ */
+# include <malloc.h>
+# define nearmalloc _nmalloc
+# define nearfree _nfree
+# define farmalloc _fmalloc
+# define farfree _ffree
+# endif /* ?__TURBOC__ */
+# define MY_ZCALLOC 1
+#endif /* MEMORY16 */
+
+
+/* The symbol MSDOS is consistently used in the generic source files
+ * to identify code to support for MSDOS (and MSDOS related) stuff.
+ * e.g: FAT or (FAT like) file systems,
+ * '\\' as directory separator in paths,
+ * "\r\n" as record (line) terminator in text files, ...
+ *
+ * MSDOS is defined anyway with MS C 16-bit. So the block above works.
+ * For the 32-bit compilers, MSDOS must not be defined in the block above.
+ */
+#if (defined(OS2) && !defined(MSDOS))
+# define MSDOS
+/* inherit MS-DOS file system etc. stuff */
+#endif
+
+#define USE_CASE_MAP
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+/* time stamp resolution of file system is 2 seconds */
+#define ROUNDED_TIME(time) ((time_t)(((unsigned long)(time) + 1) & (~1)))
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+#ifdef __32BIT__
+# define CBSZ 0x40000
+# define ZBSZ 0x40000
+#else
+# define CBSZ 0xE000
+# define ZBSZ 0x7F00 /* Some libraries do not allow a buffer size > 32K */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifdef ZCRYPT_INTERNAL
+# ifndef __GO32__
+# include <process.h> /* getpid() declaration for srand seed */
+# endif
+#endif
+
+/* for some (all ?) versions of IBM C Set/2 and IBM C Set++ */
+#ifndef S_IFMT
+# define S_IFMT 0xF000
+#endif /* !S_IFMT */
+
+#ifdef MSC
+# define NO_UNISTD_H
+#endif
+
+#ifdef __WATCOMC__
+# define NO_MKTEMP
+/* Get asm routines to link properly without using "__cdecl": */
+# ifdef __386__
+# ifdef ASMV
+# pragma aux window "*";
+# pragma aux prev "*";
+# pragma aux prev_length "*";
+# pragma aux strstart "*";
+# pragma aux match_start "*";
+# pragma aux max_chain_length "*";
+# pragma aux good_match "*";
+# pragma aux nice_match "*";
+# pragma aux match_init "*";
+# pragma aux longest_match "*";
+# endif
+# ifndef USE_ZLIB
+# pragma aux crc32 "_*" parm caller [] value [eax] modify [eax]
+# pragma aux get_crc_table "_*" parm caller [] value [eax] \
+ modify [eax ecx edx]
+# endif /* !USE_ZLIB */
+# else /* !__386__ */
+# if defined(ASMV) || defined(ASM_CRC)
+/*# error 16 bit assembly modules currently DO NOT WORK with Watcom C. */
+# endif
+# ifdef ASMV
+# pragma aux match_init "_*" parm caller [] loadds modify [ax bx]
+# pragma aux longest_match "_*" parm caller [] loadds value [ax] \
+ modify [ax bx cx dx es]
+# endif
+# ifndef USE_ZLIB
+# pragma aux crc32 "_*" parm caller [] value [ax dx] \
+ modify [ax bx cx dx es]
+# pragma aux get_crc_table "_*" parm caller [] value [ax] \
+ modify [ax bx cx dx]
+# endif /* !USE_ZLIB */
+# endif /* ?__386__ */
+#endif
+
+#ifdef __IBMC__
+# define NO_UNISTD_H
+# define NO_MKTEMP
+# define timezone _timezone /* (underscore names work with */
+# define tzset _tzset /* all versions of C Set) */
+#endif
diff --git a/os2/zip.def b/os2/zip.def
new file mode 100644
index 0000000..7404eee
--- /dev/null
+++ b/os2/zip.def
@@ -0,0 +1,3 @@
+NAME WINDOWCOMPAT NEWFILES
+DESCRIPTION 'The world-famous zip utilities from Info-ZIP'
+; STACKSIZE 0x50000
diff --git a/os2/zipup.h b/os2/zipup.h
new file mode 100644
index 0000000..592cff8
--- /dev/null
+++ b/os2/zipup.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/proginfo/3rdparty.bug b/proginfo/3rdparty.bug
new file mode 100644
index 0000000..32e7823
--- /dev/null
+++ b/proginfo/3rdparty.bug
@@ -0,0 +1,114 @@
+Known, current PKZIP bugs/limitations:
+-------------------------------------
+
+ - PKUNZIP 2.04g is reported to corrupt some files when compressing them with
+ the -ex option; when tested, the files fail the CRC check, and comparison
+ with the original file shows bogus data (6K in one case) embedded in the
+ middle. PKWARE apparently characterized this as a "known problem."
+
+ - PKUNZIP 2.04g considers volume labels valid only if originated on a FAT
+ file system, but other OSes and file systems (e.g., Amiga and OS/2 HPFS)
+ support volume labels, too.
+
+ - PKUNZIP 2.04g can restore volume labels created by Zip 2.x but not by
+ PKZIP 2.04g (OS/2 DOS box only??).
+
+ - PKUNZIP 2.04g gives an error message for stored directory entries created
+ under other OSes (although it creates the directory anyway), and PKZIP -vt
+ does not report the directory attribute bit as being set, even if it is.
+
+ - PKZIP 2.04g mangles unknown extra fields (especially OS/2 extended attri-
+ butes) when adding new files to an existing zipfile [example: Walnut Creek
+ Hobbes March 1995 CD-ROM, FILE_ID.DIZ additions].
+
+ - PKUNZIP 2.04g is unable to detect or deal with prepended junk in a zipfile,
+ reporting CRC errors in valid compressed data.
+
+ - PKUNZIP 2.04g (registered version) incorrectly updates/freshens the AV extra
+ field in authenticated archives. The resultant extra block length and total
+ extra field length are inconsistent.
+
+ - [Windows version 2.01] Win95 long filenames (VFAT) are stored OK, but the
+ file system is always listed as ordinary DOS FAT.
+
+ - [Windows version 2.50] NT long filenames (NTFS) are stored OK, but the
+ file system is always listed as ordinary DOS FAT.
+
+ - PKZIP 2.04 for DOS encrypts using the OEM code page for 8-bit passwords,
+ while PKZIP 2.50 for Windows uses Latin-1 (ISO 8859-1). This means an
+ archive encrypted with an 8-bit password with one of the two PKZIP versions
+ cannot be decrypted with the other version.
+
+ - PKZIP for Windows GUI (v 2.60), PKZIP for Windows command line (v 2.50) and
+ PKZIP for Unix (v 2.51) save the host's native file timestamps, but
+ only in a local extra field. Thus, timestamp-related selections (update
+ or freshen, both in extraction or archiving operations) use the DOS-format
+ localtime records in the Zip archives for comparisons. This may result
+ in wrong decisions of the program when updating archives that were
+ previously created in a different local time zone.
+
+ - PKZIP releases newer than PKZIP for DOS 2.04g (PKZIP for Windows, both
+ GUI v 2.60 and console v 2.50; PKZIP for Unix v 2.51; probably others too)
+ use different code pages for storing filenames in central (OEM Codepage)
+ and local (ANSI / ISO 8859-1 Codepage) headers. When a stored filename
+ contains extended-ASCII characters, the local and central filename fields
+ do not match. As a consequence, Info-ZIP's Zip program considers such
+ archives as being corrupt and does not allow to modify them. Beginning
+ with release 5.41, Info-ZIP's UnZip contains a workaround to list AND
+ extract such archives with the correct filenames.
+ Maybe PKWARE has implemented this "feature" to allow extraction of their
+ "made-by-PKZIP for Unix/Windows" archives using old (v5.2 and earlier)
+ versions of Info-ZIP's UnZip for Unix/WinNT ??? (UnZip versions before
+ v 5.3 assumed that all archive entries were encoded in the codepage of
+ the UnZip program's host system.)
+
+ - PKUNZIP 2.04g is reported to have problems with archives created on and/or
+ copied from Iomega ZIP drives (irony, eh?).
+
+Known, current WinZip bugs/limitations:
+--------------------------------------
+
+ - [16-bit version 6.1a] NT short filenames (FAT) are stored OK, but the
+ file system is always listed as NTFS.
+
+ - WinZip doesn't allow 8-bit passwords, which means it cannot decrypt an
+ archive created with an 8-bit password (by PKZIP or Info-ZIP's Zip).
+
+ - WinZip (at least Versions 6.3 PL1, 7.0 SR1) fails to remove old extra
+ fields when freshening existing archive entries. When updating archives
+ created by Info-ZIP's Zip that contain UT time stamp extra field blocks,
+ UnZip cannot display or restore the updated (DOS) time stamps of the
+ freshened archive members.
+
+Known, current other third-party Zip utils bugs/limitations:
+------------------------------------------------------------
+
+ - Asi's PKZip clones for Macintosh (versions 2.3 and 2.10d) are thoroughly
+ broken. They create invalid Zip archives!
+ a) For the first entry, both compressed size and uncompressed length
+ are recorded as 0, despite the fact that compressed data of non-zero
+ length has been added.
+ b) Their program creates extra fields with an (undocumented) internal
+ structure that violates the requirements of PKWARE's Zip format
+ specification document "appnote.txt": Their extra field seems to
+ contain pure data; the 4-byte block header consisting of block ID
+ and data length is missing.
+
+Possibly current PKZIP bugs:
+---------------------------
+
+ - PKZIP (2.04g?) can silently ignore read errors on network drives, storing
+ the correct CRC and compressed length but an incorrect and inconsistent
+ uncompressed length.
+
+ - PKZIP (2.04g?), when deleting files from within a zipfile on a Novell
+ drive, sometimes only zeros out the data while failing to shrink the
+ zipfile.
+
+Other limitations:
+-----------------
+
+ - PKZIP 1.x and 2.x encryption has been cracked (known-plaintext approach;
+ see http://www.cryptography.com/ for details).
+
+[many other bugs in PKZIP 1.0, 1.1, 1.93a, 2.04c and 2.04e]
diff --git a/proginfo/ZipPorts b/proginfo/ZipPorts
new file mode 100644
index 0000000..2d946d3
--- /dev/null
+++ b/proginfo/ZipPorts
@@ -0,0 +1,285 @@
+__________________________________________________________________________
+
+ This is the Info-ZIP file ZipPorts, last updated on 17 February 1996.
+__________________________________________________________________________
+
+
+This document defines a set of rules and guidelines for those who wish to
+contribute patches to Zip and UnZip (or even entire ports to new operating
+systems). The list below is something between a style sheet and a "Miss
+Manners" etiquette guide. While Info-ZIP encourages contributions and
+fixes from anyone who finds something worth changing, we are also aware
+of the fact that no two programmers have the programming style and that
+unrestrained changes by a few dozen contributors would result in hideously
+ugly (and unmaintainable) Frankenstein code. So consider the following an
+attempt by the maintainers to maintain sanity as well as useful code.
+
+(The first version of this document was called either "ZipRules" or the
+"No Feelthy ..." file and was compiled by David Kirschbaum in consulta-
+tion with Mark Adler, Cave McNewt and others. The current incarnation
+expands upon the original with insights gained from a few more years of
+happy hacking...)
+
+
+Summary:
+
+ (0) The Platinum Rule: DON'T BREAK EXISTING PORTS
+(0.1) The Golden Rule: DO UNTO THE CODE AS OTHERS HAVE DONE BEFORE
+(0.2) The Silver Rule: DO UNTO THE LATEST BETA CODE
+(0.3) The Bronze Rule: NO FEELTHY PIGGYBACKS
+
+ (1) NO FEELTHY TABS
+ (2) NO FEELTHY CARRIAGE RETURNS
+ (3) NO FEELTHY 8-BIT CHARS
+ (4) NO FEELTHY LEFT-JUSTIFIED DASHES
+ (5) NO FEELTHY FANCY_FILENAMES
+ (6) NO FEELTHY NON-ZIPFILES AND NO FEELTHY E-MAIL BETAS
+ (7) NO FEELTHY E-MAIL BINARIES
+
+
+Explanations:
+
+ (0) The Platinum Rule: DON'T BREAK EXISTING PORTS
+
+ No doubt about it, this is the one which really pisses us off and
+ pretty much guarantees that your port or patch will be ignored and/
+ or laughed at. Examples range from the *really* severe cases which
+ "port" by ripping out all of the existing multi-OS code, to more
+ subtle oopers like relying on a local capability which doesn't exist
+ on other OSes or in older compilers (e.g., the use of ANSI "#elif"
+ or "#pragma" or "##" constructs, C++ comments, GNU extensions, etc.).
+ As to the former, use #ifdefs for your new code (see rule 0.3). And
+ as to the latter, trust us--there are few things we'd like better
+ than to be able to use some of the elegant "new" features out there
+ (many of which have been around for a decade or more). But our code
+ still compiles on machines dating back even longer, at least in spirit
+ --e.g., the AT&T 3B1 family and Dynix/ptx. Until we say otherwise,
+ dinosaurs are supported.
+
+
+(0.1) The Golden Rule: DO UNTO THE CODE AS OTHERS HAVE DONE BEFORE
+
+ In other words, try to fit into the local style of programming--no
+ matter how painful it may be. This includes cosmetic aspects like
+ indenting the same amount (both in the main C code and in the in-
+ clude files), using braces and comments similarly, NO TABS (see rule
+ #1), etc.; but also more substantive things like (for UnZip) putting
+ character strings into static (far) variables and using the LoadFar-
+ String macros to avoid overflowing limited MS-DOS data segments, and
+ using the ugly Info() macro instead of the more usual *printf()
+ functions so that dynamic-link-library ports are simpler. NEVER put
+ single-OS code (e.g., OS/2) of more than two or three lines into the
+ main (generic) modules; those are shared by everybody, and nobody else
+ cares about it or wants to see it.
+
+ Note that not only do Zip and UnZip differ in these respects, so do
+ individual parts of each program. While it would be nice to have
+ global consistency, cosmetic changes are not a high priority; for
+ now we'll settle for local consistency--i.e., don't make things any
+ worse than they already are.
+
+ Exception (BIG exception): single-letter variable names. Despite
+ the prevailing practice in much of Zip and parts of UnZip, and de-
+ spite the fact that one-letter variables allow you to pack really
+ cool, compact and complicated expressions onto one line, they also
+ make the code very difficult to maintain and are therefore *strongly*
+ discouraged. Don't ask us who is responsible in the first place;
+ while this sort of brain damage is not uncommon among former BASIC
+ programmers, it is nevertheless a lifelong embarrassment, and we do
+ try to pity the poor sod (that is, when we're not chasing bugs and
+ cursing him). :-)
+
+
+(0.2) The Silver Rule: DO UNTO THE LATEST BETA CODE
+
+ Few things are as annoying as receiving a large patch which obviously
+ represents a lot of time and careful work but which is relative to
+ an old version of Info-ZIP code. As wonderful as Larry Wall's patch
+ program is at applying context diffs to modified code, we regularly
+ make near-global changes and/or reorganize big chunks of the sources
+ (particularly in UnZip), and "patch" can't work miracles--big changes
+ invariably break any patch which is relative to an old version of the
+ code.
+
+ Bottom line: contact the Info-ZIP core team FIRST (via the zip-bugs
+ e-mail address) and get up to date with the latest code before begin-
+ ning a big new port. And try to *stay* up to date while working on
+ your port--at least, as much as possible.
+
+
+(0.3) The Bronze Rule: NO FEELTHY PIGGYBACKS
+
+ UnZip is currently ported to something like 12 operating systems
+ (a few more or less depending on how one counts), and each of these,
+ with the possible exception of VM/CMS, has a unique macro identifying
+ it: AMIGA, ATARI_ST, __human68k__, MACOS, MSDOS, MVS, OS2, TOPS20,
+ UNIX, VMS, WIN32. Zip is moving in the same direction. New ports
+ should NOT piggyback one of the existing ports unless they are sub-
+ stantially similar--for example, Minix and Coherent are basically Unix
+ and therefore are included in the UNIX macro, but DOS djgpp ports and
+ OS/2 emx ports (both of which use the Unix-originated GNU C compiler
+ and often have "unix" defined by default) are obviously *not* Unix.
+ [The existing MTS port is a special exception; basically only one per-
+ son knows what MTS really is, and he's not telling. Presumably it's
+ not very close to Unix, but it's not worth arguing about it now.]
+ Along the same lines, neither OS/2 nor Human68K is the same as (or
+ even close to) MS-DOS. MVS and VM/CMS, on the other hand, are quite
+ similar to each other and are therefore combined in most places.
+
+ Bottom line: when adding a new port (e.g., QDOS), create a new macro
+ for it ("QDOS"), a new subdirectory ("qdos") and a new source file for
+ OS-specific code ("qdos/qdos.c"). Use #ifdefs to fit any OS-specific
+ changes into the existing code (e.g., unzpriv.h). If it's close enough
+ to an existing port that piggybacking is a temptation, define a new
+ "combination macro" (e.g., "CMS_MVS") and replace the old macros as
+ required. (This last applies to UnZip, at least; the old preference
+ in Zip was fewer macros and long #ifdef lines, so talk to Onno or Jean-
+ loup about that.) See also rule 0.1.
+
+ (Note that, for UnZip, new ports need not attempt to deal with all
+ features. Among other things, the wildcard-zipfile code in do_wild()
+ may be replaced with a supplied dummy version, since opendir/readdir/
+ closedir() or the equivalent can be difficult to implement.)
+
+
+ (1) NO FEELTHY TABS
+
+ Some editors and e-mail systems either have no capability to use
+ and/or display tab characters (ASCII 9) correctly, or they use non-
+ standard or variable-width tab columns, or other horrors. Some edi-
+ tors auto-convert spaces to tabs, after which the blind use of "diff
+ -c" results in a huge and mostly useless patch. Yes, *we* know about
+ diff's "-b" option, but not everyone does. And yes, we also know this
+ makes the source files bigger, even after compression; so be it. If
+ we *really* cared that much about the size of the sources, we'd still
+ be writing Unix-only utilities.
+
+ Bottom line: use spaces, not tabs.
+
+ Exception: some of the makefiles (the Unix one in particular) require
+ tabs as part of the syntax.
+
+ Related utility programs:
+ Unix, OS/2 and MS-DOS: expand, unexpand.
+ MS-DOS: Buerg's TABS; Toad Hall's TOADSOFT.
+ And some editors have the conversion built-in.
+
+
+ (2) NO FEELTHY CARRIAGE RETURNS
+
+ All source, documentation and other text files shall have Unix style
+ line endings (LF only, a.k.a. ctrl-J), not the DOS/OS2/NT CR+LF or Mac
+ CR-only line endings.
+
+ Reason: "real programmers" in any environment can convert back and
+ forth between Unix and DOS/Mac style. All PC compilers but a few old
+ Borland versions can use either Unix or MS-DOS end-of-lines. Buerg's
+ LIST (file-display utility) for MS-DOS can use Unix or MS-DOS EOLs.
+ Both Zip and UnZip can convert line-endings as appropriate. But Unix
+ utilities like diff and patch die a horrible death (or produce horrible
+ output) if the target files have CRs.
+
+ Related utilities: flip for Unix, OS/2 and MS-DOS; Unix "tr".
+
+ Exceptions: documentation in pre-compiled binary distributions should
+ be in the local (target) format.
+
+
+ (3) NO FEELTHY 8-BIT CHARS
+
+ Do all your editing in a plain-text ASCII editor. No WordPerfect, MS
+ Word, WordStar document mode, or other word processor files, thenkyew.
+ No desktop publishing. *Especially* no EBCDIC. No TIFFs, no GIFs, no
+ embedded pictures or dancing ladies (too bad, Cave Newt). [Sigh... -CN]
+
+ Reason: compatibility with different consoles. My old XT clone is
+ the most limited!
+
+ Exceptions: some Macintosh makefiles apparently require some 8-bit
+ characters; the Human68k port uses 8-bit characters for Kanji or Kana
+ comments (I think); etc.
+
+ Related utilities: vi, emacs, EDLIN, Turbo C editor, other programmers'
+ editors, various word processor -> text conversion utilities.
+
+
+ (4) NO FEELTHY LEFT-JUSTIFIED DASHES
+
+ Always precede repeated dashes (------) with one or more leading non-
+ dash characters: spaces, tabs, pound signs (#), comments (/*), what-
+ ever.
+
+ Reason: sooner or later your source file will be e-mailed through an
+ undigestifier utility, most of which treat leading dashes as end-of-
+ message separators. We'd rather not have your code broken up into a
+ dozen separate untitled messages, thank you.
+
+
+ (5) NO FEELTHY FANCY_FILENAMES
+
+ Assume the worst: that someone on a brain-damaged DOS system has to
+ work with everything your magic fingers produced. Keep the filenames
+ unimaginative and within MS-DOS limits (i.e., ordinary A..Z, 1..9,
+ "-$_!"-type characters, in the 8.3 "filename.ext" format). Mac and
+ Unix users, giggle all you want, but no spaces or multiple dots.
+
+ Reason: compatibility with different file systems. MS-DOS FAT is the
+ most limited, with the exception of CompuServe (6.3, argh).
+
+ Exceptions: slightly longer names are occasionally acceptable within
+ OS-specific subdirectories, but don't do that unless there's a good
+ reason for it.
+
+
+ (6) NO FEELTHY NON-ZIPFILES AND NO FEELTHY E-MAIL BETAS
+
+ Beta testers and developers are in general expected to have both
+ ftp capability and the ability to deal with zipfiles. Those without
+ should either find a friend who does or else learn about ftp-mailers.
+
+ Reason: the core development team barely has time to work on the
+ code, much less prepare oddball formats and/or mail betas out (and
+ the situation is getting worse, sigh).
+
+ Exceptions: anyone seriously proposing to do a new port will be
+ given special treatment, particularly with respect to UnZip; we
+ obviously realize that bootstrapping a completely new port can be
+ quite difficult and have no desire to make it even harder due to
+ lack of access to the latest code (rule 0.2).
+
+ Public releases of UnZip, on the other hand, will be available in
+ two formats: .tar.Z (16-bit compress'd tar) and .zip (either "plain"
+ or self-extracting). Zip sources and executables will generally only
+ be distributed in .zip format, since Zip is pretty much useless without
+ UnZip.
+
+
+ (7) NO FEELTHY E-MAIL BINARIES
+
+ Binary files (e.g., executables, test zipfiles, etc.) should NEVER
+ be mailed raw. Where possible, they should be uploaded via ftp in
+ BINARY mode; if that's impossible, Mark's "ship" ASCII-encoder should
+ be used; and if that's unavailable, uuencode or xxencode should be
+ used. Weirdo NeXTmail, mailtool and MIME formats are also Right Out.
+
+ Files larger than 50KB may need to be broken into pieces for mailing
+ (be sure to label them in order!), unless "ship" is used (it can
+ auto-split, label and mail files if told to do so). If Down Under
+ is involved, files must be broken into under-20KB chunks.
+
+ Reasons: to prevent sounds of gagging mailers from resounding through-
+ out the land. To be relatively efficient in the binary->ASCII conver-
+ sion. (Yeah, yeah, I know, there's better conversions out there. But
+ not as widely known, and they often break on BITNET gateways.)
+
+ Related utilities: ship, uuencode, uudecode, uuxfer20, quux, others.
+ Just make sure they don't leave embedded or trailing spaces (that is,
+ they should use the "`" character in place of ASCII 32). Otherwise
+ mailers are prone to truncate or whatever.
+
+
+Greg Roelofs (a.k.a. Cave Newt)
+Info-ZIP UnZip maintainer
+
+David Kirschbaum
+former Info-ZIP Coordinator
diff --git a/proginfo/algorith.txt b/proginfo/algorith.txt
new file mode 100644
index 0000000..867e30b
--- /dev/null
+++ b/proginfo/algorith.txt
@@ -0,0 +1,68 @@
+Zip's deflation algorithm is a variation of LZ77 (Lempel-Ziv 1977, see
+reference below). It finds duplicated strings in the input data. The
+second occurrence of a string is replaced by a pointer to the previous
+string, in the form of a pair (distance, length). Distances are
+limited to 32K bytes, and lengths are limited to 258 bytes. When a
+string does not occur anywhere in the previous 32K bytes, it is
+emitted as a sequence of literal bytes. (In this description,
+'string' must be taken as an arbitrary sequence of bytes, and is not
+restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when zip determines that it
+would be useful to start another block with fresh trees. (This is
+somewhat similar to compress.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (zip -1
+to -9). So zip does not always find the longest possible match but
+generally finds a match which is long enough.
+
+zip also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, zip searches for a
+longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the longer match is emitted afterwards. Otherwise,
+the original match is kept, and the next match search is attempted only
+N steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, zip reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, zip attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (speed options -1 to -3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+Jean-loup Gailly
+jloup@chorus.fr
+
+References:
+
+[LZ77] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
+Compression", IEEE Transactions on Information Theory", Vol. 23, No. 3,
+pp. 337-343.
+
+APPNOTE.TXT documentation file in PKZIP 1.93a. It is available by
+ftp in ftp.cso.uiuc.edu:/pc/exec-pc/pkz193a.exe [128.174.5.59]
+
+'Deflate' Compressed Data Format Specification:
+ftp://ftp.uu.net/pub/archiving/zip/doc/deflate-1.1.doc
diff --git a/proginfo/ebcdic.msg b/proginfo/ebcdic.msg
new file mode 100644
index 0000000..1a7bbad
--- /dev/null
+++ b/proginfo/ebcdic.msg
@@ -0,0 +1,63 @@
+From dima@mitrah.ru Mon Nov 10 02:25:38 2003
+Return-Path: <dima@mitrah.ru>
+Received: from b.mx.sonic.net (eth0.b.mx.sonic.net [209.204.159.4])
+ by eth0.a.lds.sonic.net (8.12.10/8.12.9) with ESMTP id hAAAPccT025257
+ for <roelofs@lds.sonic.net>; Mon, 10 Nov 2003 02:25:38 -0800
+Received: from icicle.pobox.com (icicle.pobox.com [207.8.214.2])
+ by b.mx.sonic.net (8.12.10/8.12.7) with ESMTP id hAAAPar9007141
+ for <roelofs@sonic.net>; Mon, 10 Nov 2003 02:25:37 -0800
+Received: from icicle.pobox.com (localhost[127.0.0.1])
+ by icicle.pobox.com (Postfix) with ESMTP id 9BA347A96B
+ for <roelofs@sonic.net>; Sat, 8 Nov 2003 06:15:13 -0500 (EST)
+Delivered-To: newt@pobox.com
+Received: from mail.ropnet.ru (mail.ropnet.ru[212.42.37.90])
+ by icicle.pobox.com (Postfix) with ESMTP id A96817A8F7
+ for <newt@pobox.com>; Sat, 8 Nov 2003 06:15:04 -0500 (EST)
+Received: from d34-67.ropnet.ru (d34-67.ropnet.ru [212.42.34.67])
+ by mail.ropnet.ru (8.11.7/8.11.7) with ESMTP id hA8BEjF76200
+ for <newt@pobox.com>; Sat, 8 Nov 2003 14:14:46 +0300 (MSK)
+Resent-Date: Sat, 8 Nov 2003 14:14:46 +0300 (MSK)
+Resent-Message-Id: <200311081114.hA8BEjF76200@mail.ropnet.ru>
+Date: Sat, 8 Nov 2003 14:18:18 +0300
+From: Dmitri Koulikov <dima@mitrah.ru>
+X-Mailer: The Bat! (v1.62r) Personal
+Reply-To: Dmitri Koulikov <dima@mitrah.ru>
+X-Priority: 3 (Normal)
+Message-ID: <815640011.20031108141818@mitrah.ru>
+To: newt@pobox.com
+Subject: unzip and zip lack NLS - 2
+Resent-From: Dmitri Koulikov <dima@mitrah.ru>
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="----------EB1581C42AB86662"
+Status: R
+
+------------EB1581C42AB86662
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+
+Hello Greg Roelofs,
+
+ By mistake I sent you wrong version of ebcdic.h. Now it is as it
+have to.
+ Additionally I found that zip works with Russian filenames good.
+But fails to process -D switch. So I have to chahge zipfile.c. Most
+probably this is not good but it works.
+
+--
+Best regards,
+ Dmitri
+
+mailto:dima@mitrah.ru
+------------EB1581C42AB86662
+Content-Type: application/octet-stream; name="ebcdic.h"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename="ebcdic.h"
+
+------------EB1581C42AB86662
+Content-Type: application/octet-stream; name="zipfile.c"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename="zipfile.c"
+
+------------EB1581C42AB86662--
+
+
diff --git a/proginfo/extrafld.txt b/proginfo/extrafld.txt
new file mode 100644
index 0000000..624e05c
--- /dev/null
+++ b/proginfo/extrafld.txt
@@ -0,0 +1,1372 @@
+The following are the known types of zipfile extra fields as of this
+writing. Extra fields are documented in PKWARE's appnote.txt and are
+intended to allow for backward- and forward-compatible extensions to
+the zipfile format. Multiple extra-field types may be chained together,
+provided that the total length of all extra-field data is less than 64KB.
+(In fact, PKWARE requires that the total length of the entire file header,
+including timestamp, file attributes, filename, comment, extra field, etc.,
+be no more than 64KB.)
+
+Each extra-field type (or subblock) must contain a four-byte header con-
+sisting of a two-byte header ID and a two-byte length (little-endian) for
+the remaining data in the subblock. If there are additional subblocks
+within the extra field, the header for each one will appear immediately
+following the data for the previous subblock (i.e., with no padding for
+alignment).
+
+All integer fields in the descriptions below are in little-endian (Intel)
+format unless otherwise specified. Note that "Short" means two bytes,
+"Long" means four bytes, and "Long-Long" means eight bytes, regardless
+of their native sizes. Unless specifically noted, all integer fields should
+be interpreted as unsigned (non-negative) numbers.
+
+Christian Spieler, 20010517
+
+Updated to include the Unicode extra fields. Added new Unix extra field.
+
+Ed Gordon, 20060819, 20070607, 20070909, 20080426, 20080509
+
+ -------------------------
+
+ Header ID's of 0 thru 31 are reserved for use by PKWARE.
+ The remaining ID's can be used by third party vendors for
+ proprietary usage.
+
+ The current Header ID mappings defined by PKWARE are:
+
+ 0x0001 ZIP64 extended information extra field
+ 0x0007 AV Info
+ 0x0009 OS/2 extended attributes (also Info-ZIP)
+ 0x000a NTFS (Win9x/WinNT FileTimes)
+ 0x000c OpenVMS (also Info-ZIP)
+ 0x000d Unix
+ 0x000f Patch Descriptor
+ 0x0014 PKCS#7 Store for X.509 Certificates
+ 0x0015 X.509 Certificate ID and Signature for
+ individual file
+ 0x0016 X.509 Certificate ID for Central Directory
+
+ The Header ID mappings defined by Info-ZIP and third parties are:
+
+ 0x0065 IBM S/390 attributes - uncompressed
+ 0x0066 IBM S/390 attributes - compressed
+ 0x07c8 Info-ZIP Macintosh (old, J. Lee)
+ 0x2605 ZipIt Macintosh (first version)
+ 0x2705 ZipIt Macintosh v 1.3.5 and newer (w/o full filename)
+ 0x334d Info-ZIP Macintosh (new, D. Haase's 'Mac3' field )
+ 0x4154 Tandem NSK
+ 0x4341 Acorn/SparkFS (David Pilling)
+ 0x4453 Windows NT security descriptor (binary ACL)
+ 0x4704 VM/CMS
+ 0x470f MVS
+ 0x4854 Theos, old inofficial port
+ 0x4b46 FWKCS MD5 (see below)
+ 0x4c41 OS/2 access control list (text ACL)
+ 0x4d49 Info-ZIP OpenVMS (obsolete)
+ 0x4d63 Macintosh SmartZIP, by Macro Bambini
+ 0x4f4c Xceed original location extra field
+ 0x5356 AOS/VS (binary ACL)
+ 0x5455 extended timestamp
+ 0x5855 Info-ZIP Unix (original; also OS/2, NT, etc.)
+ 0x554e Xceed unicode extra field
+ 0x6375 Info-ZIP Unicode Comment
+ 0x6542 BeOS (BeBox, PowerMac, etc.)
+ 0x6854 Theos
+ 0x7075 Info-ZIP Unicode Path
+ 0x756e ASi Unix
+ 0x7855 Info-ZIP Unix (previous new)
+ 0x7875 Info-ZIP Unix (new)
+ 0xfb4a SMS/QDOS
+
+The following are detailed descriptions of the known extra-field block types:
+
+ -OS/2 Extended Attributes Extra Field:
+ ====================================
+
+ The following is the layout of the OS/2 extended attributes "extra"
+ block. (Last Revision 19960922)
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (OS/2) 0x0009 Short tag for this extra block type
+ TSize Short total data size for this block
+ BSize Long uncompressed EA data size
+ CType Short compression type
+ EACRC Long CRC value for uncompressed EA data
+ (var.) variable compressed EA data
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (OS/2) 0x0009 Short tag for this extra block type
+ TSize Short total data size for this block (4)
+ BSize Long size of uncompressed local EA data
+
+ The value of CType is interpreted according to the "compression
+ method" section above; i.e., 0 for stored, 8 for deflated, etc.
+
+ The OS/2 extended attribute structure (FEA2LIST) is compressed and
+ then stored in its entirety within this structure. There will only
+ ever be one block of data in the variable-length field.
+
+
+ -OS/2 Access Control List Extra Field:
+ ====================================
+
+ The following is the layout of the OS/2 ACL extra block.
+ (Last Revision 19960922)
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (ACL) 0x4c41 Short tag for this extra block type ("AL")
+ TSize Short total data size for this block
+ BSize Long uncompressed ACL data size
+ CType Short compression type
+ EACRC Long CRC value for uncompressed ACL data
+ (var.) variable compressed ACL data
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (ACL) 0x4c41 Short tag for this extra block type ("AL")
+ TSize Short total data size for this block (4)
+ BSize Long size of uncompressed local ACL data
+
+ The value of CType is interpreted according to the "compression
+ method" section above; i.e., 0 for stored, 8 for deflated, etc.
+
+ The uncompressed ACL data consist of a text header of the form
+ "ACL1:%hX,%hd\n", where the first field is the OS/2 ACCINFO acc_attr
+ member and the second is acc_count, followed by acc_count strings
+ of the form "%s,%hx\n", where the first field is acl_ugname (user
+ group name) and the second acl_access. This block type will be
+ extended for other operating systems as needed.
+
+
+ -Windows NT Security Descriptor Extra Field:
+ ==========================================
+
+ The following is the layout of the NT Security Descriptor (another
+ type of ACL) extra block. (Last Revision 19960922)
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (SD) 0x4453 Short tag for this extra block type ("SD")
+ TSize Short total data size for this block
+ BSize Long uncompressed SD data size
+ Version Byte version of uncompressed SD data format
+ CType Short compression type
+ EACRC Long CRC value for uncompressed SD data
+ (var.) variable compressed SD data
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (SD) 0x4453 Short tag for this extra block type ("SD")
+ TSize Short total data size for this block (4)
+ BSize Long size of uncompressed local SD data
+
+ The value of CType is interpreted according to the "compression
+ method" section above; i.e., 0 for stored, 8 for deflated, etc.
+ Version specifies how the compressed data are to be interpreted
+ and allows for future expansion of this extra field type. Currently
+ only version 0 is defined.
+
+ For version 0, the compressed data are to be interpreted as a single
+ valid Windows NT SECURITY_DESCRIPTOR data structure, in self-relative
+ format.
+
+
+ -PKWARE Win95/WinNT Extra Field:
+ ==============================
+
+ The following description covers PKWARE's "NTFS" attributes
+ "extra" block, introduced with the release of PKZIP 2.50 for
+ Windows. (Last Revision 20001118)
+
+ (Note: At this time the Mtime, Atime and Ctime values may
+ be used on any WIN32 system.)
+ [Info-ZIP note: In the current implementations, this field has
+ a fixed total data size of 32 bytes and is only stored as local
+ extra field.]
+
+ Value Size Description
+ ----- ---- -----------
+ (NTFS) 0x000a Short Tag for this "extra" block type
+ TSize Short Total Data Size for this block
+ Reserved Long for future use
+ Tag1 Short NTFS attribute tag value #1
+ Size1 Short Size of attribute #1, in bytes
+ (var.) SubSize1 Attribute #1 data
+ .
+ .
+ .
+ TagN Short NTFS attribute tag value #N
+ SizeN Short Size of attribute #N, in bytes
+ (var.) SubSize1 Attribute #N data
+
+ For NTFS, values for Tag1 through TagN are as follows:
+ (currently only one set of attributes is defined for NTFS)
+
+ Tag Size Description
+ ----- ---- -----------
+ 0x0001 2 bytes Tag for attribute #1
+ Size1 2 bytes Size of attribute #1, in bytes (24)
+ Mtime 8 bytes 64-bit NTFS file last modification time
+ Atime 8 bytes 64-bit NTFS file last access time
+ Ctime 8 bytes 64-bit NTFS file creation time
+
+ The total length for this block is 28 bytes, resulting in a
+ fixed size value of 32 for the TSize field of the NTFS block.
+
+ The NTFS filetimes are 64-bit unsigned integers, stored in Intel
+ (least significant byte first) byte order. They determine the
+ number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
+ which is "01-Jan-1601 00:00:00 UTC".
+
+
+ -PKWARE OpenVMS Extra Field:
+ ==========================
+
+ The following is the layout of PKWARE's OpenVMS attributes "extra"
+ block. (Last Revision 12/17/91)
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (VMS) 0x000c Short Tag for this "extra" block type
+ TSize Short Total Data Size for this block
+ CRC Long 32-bit CRC for remainder of the block
+ Tag1 Short OpenVMS attribute tag value #1
+ Size1 Short Size of attribute #1, in bytes
+ (var.) Size1 Attribute #1 data
+ .
+ .
+ .
+ TagN Short OpenVMS attribute tage value #N
+ SizeN Short Size of attribute #N, in bytes
+ (var.) SizeN Attribute #N data
+
+ Rules:
+
+ 1. There will be one or more of attributes present, which
+ will each be preceded by the above TagX & SizeX values.
+ These values are identical to the ATR$C_XXXX and
+ ATR$S_XXXX constants which are defined in ATR.H under
+ OpenVMS C. Neither of these values will ever be zero.
+
+ 2. No word alignment or padding is performed.
+
+ 3. A well-behaved PKZIP/OpenVMS program should never produce
+ more than one sub-block with the same TagX value. Also,
+ there will never be more than one "extra" block of type
+ 0x000c in a particular directory record.
+
+
+ -Info-ZIP VMS Extra Field:
+ ========================
+
+ The following is the layout of Info-ZIP's VMS attributes extra
+ block for VAX or Alpha AXP. The local-header and central-header
+ versions are identical. (Last Revision 19960922)
+
+ Value Size Description
+ ----- ---- -----------
+ (VMS2) 0x4d49 Short tag for this extra block type ("JM")
+ TSize Short total data size for this block
+ ID Long block ID
+ Flags Short info bytes
+ BSize Short uncompressed block size
+ Reserved Long (reserved)
+ (var.) variable compressed VMS file-attributes block
+
+ The block ID is one of the following unterminated strings:
+
+ "VFAB" struct FAB
+ "VALL" struct XABALL
+ "VFHC" struct XABFHC
+ "VDAT" struct XABDAT
+ "VRDT" struct XABRDT
+ "VPRO" struct XABPRO
+ "VKEY" struct XABKEY
+ "VMSV" version (e.g., "V6.1"; truncated at hyphen)
+ "VNAM" reserved
+
+ The lower three bits of Flags indicate the compression method. The
+ currently defined methods are:
+
+ 0 stored (not compressed)
+ 1 simple "RLE"
+ 2 deflated
+
+ The "RLE" method simply replaces zero-valued bytes with zero-valued
+ bits and non-zero-valued bytes with a "1" bit followed by the byte
+ value.
+
+ The variable-length compressed data contains only the data corre-
+ sponding to the indicated structure or string. Typically multiple
+ VMS2 extra fields are present (each with a unique block type).
+
+
+ -Info-ZIP Macintosh Extra Field:
+ ==============================
+
+ The following is the layout of the (old) Info-ZIP resource-fork extra
+ block for Macintosh. The local-header and central-header versions
+ are identical. (Last Revision 19960922)
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac) 0x07c8 Short tag for this extra block type
+ TSize Short total data size for this block
+ "JLEE" beLong extra-field signature
+ FInfo 16 bytes Macintosh FInfo structure
+ CrDat beLong HParamBlockRec fileParam.ioFlCrDat
+ MdDat beLong HParamBlockRec fileParam.ioFlMdDat
+ Flags beLong info bits
+ DirID beLong HParamBlockRec fileParam.ioDirID
+ VolName 28 bytes volume name (optional)
+
+ All fields but the first two are in native Macintosh format
+ (big-endian Motorola order, not little-endian Intel). The least
+ significant bit of Flags is 1 if the file is a data fork, 0 other-
+ wise. In addition, if this extra field is present, the filename
+ has an extra 'd' or 'r' appended to indicate data fork or resource
+ fork. The 28-byte VolName field may be omitted.
+
+
+ -ZipIt Macintosh Extra Field (long):
+ ==================================
+
+ The following is the layout of the ZipIt extra block for Macintosh.
+ The local-header and central-header versions are identical.
+ (Last Revision 19970130)
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac2) 0x2605 Short tag for this extra block type
+ TSize Short total data size for this block
+ "ZPIT" beLong extra-field signature
+ FnLen Byte length of FileName
+ FileName variable full Macintosh filename
+ FileType Byte[4] four-byte Mac file type string
+ Creator Byte[4] four-byte Mac creator string
+
+
+ -ZipIt Macintosh Extra Field (short):
+ ===================================
+
+ The following is the layout of a shortened variant of the
+ ZipIt extra block for Macintosh (without "full name" entry).
+ This variant is used by ZipIt 1.3.5 and newer for entries that
+ do not need a "full Mac filename" record.
+ The local-header and central-header versions are identical.
+ (Last Revision 19980903)
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac2b) 0x2705 Short tag for this extra block type
+ TSize Short total data size for this block (12)
+ "ZPIT" beLong extra-field signature
+ FileType Byte[4] four-byte Mac file type string
+ Creator Byte[4] four-byte Mac creator string
+
+
+ -Info-ZIP Macintosh Extra Field (new):
+ ====================================
+
+ The following is the layout of the (new) Info-ZIP extra
+ block for Macintosh, designed by Dirk Haase.
+ All values are in little-endian.
+ (Last Revision 19981005)
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac3) 0x334d Short tag for this extra block type ("M3")
+ TSize Short total data size for this block
+ BSize Long uncompressed finder attribute data size
+ Flags Short info bits
+ fdType Byte[4] Type of the File (4-byte string)
+ fdCreator Byte[4] Creator of the File (4-byte string)
+ (CType) Short compression type
+ (CRC) Long CRC value for uncompressed MacOS data
+ Attribs variable finder attribute data (see below)
+
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (Mac3) 0x334d Short tag for this extra block type ("M3")
+ TSize Short total data size for this block
+ BSize Long uncompressed finder attribute data size
+ Flags Short info bits
+ fdType Byte[4] Type of the File (4-byte string)
+ fdCreator Byte[4] Creator of the File (4-byte string)
+
+ The third bit of Flags in both headers indicates whether
+ the LOCAL extra field is uncompressed (and therefore whether CType
+ and CRC are omitted):
+
+ Bits of the Flags:
+ bit 0 if set, file is a data fork; otherwise unset
+ bit 1 if set, filename will be not changed
+ bit 2 if set, Attribs is uncompressed (no CType, CRC)
+ bit 3 if set, date and times are in 64 bit
+ if zero date and times are in 32 bit.
+ bit 4 if set, timezone offsets fields for the native
+ Mac times are omitted (UTC support deactivated)
+ bits 5-15 reserved;
+
+
+ Attributes:
+
+ Attribs is a Mac-specific block of data in little-endian format with
+ the following structure (if compressed, uncompress it first):
+
+ Value Size Description
+ ----- ---- -----------
+ fdFlags Short Finder Flags
+ fdLocation.v Short Finder Icon Location
+ fdLocation.h Short Finder Icon Location
+ fdFldr Short Folder containing file
+
+ FXInfo 16 bytes Macintosh FXInfo structure
+ FXInfo-Structure:
+ fdIconID Short
+ fdUnused[3] Short unused but reserved 6 bytes
+ fdScript Byte Script flag and number
+ fdXFlags Byte More flag bits
+ fdComment Short Comment ID
+ fdPutAway Long Home Dir ID
+
+ FVersNum Byte file version number
+ may be not used by MacOS
+ ACUser Byte directory access rights
+
+ FlCrDat ULong date and time of creation
+ FlMdDat ULong date and time of last modification
+ FlBkDat ULong date and time of last backup
+ These time numbers are original Mac FileTime values (local time!).
+ Currently, date-time width is 32-bit, but future version may
+ support be 64-bit times (see flags)
+
+ CrGMTOffs Long(signed!) difference "local Creat. time - UTC"
+ MdGMTOffs Long(signed!) difference "local Modif. time - UTC"
+ BkGMTOffs Long(signed!) difference "local Backup time - UTC"
+ These "local time - UTC" differences (stored in seconds) may be
+ used to support timestamp adjustment after inter-timezone transfer.
+ These fields are optional; bit 4 of the flags word controls their
+ presence.
+
+ Charset Short TextEncodingBase (Charset)
+ valid for the following two fields
+
+ FullPath variable Path of the current file.
+ Zero terminated string (C-String)
+ Currently coded in the native Charset.
+
+ Comment variable Finder Comment of the current file.
+ Zero terminated string (C-String)
+ Currently coded in the native Charset.
+
+
+ -SmartZIP Macintosh Extra Field:
+ ====================================
+
+ The following is the layout of the SmartZIP extra
+ block for Macintosh, designed by Marco Bambini.
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ 0x4d63 Short tag for this extra block type ("cM")
+ TSize Short total data size for this block (64)
+ "dZip" beLong extra-field signature
+ fdType Byte[4] Type of the File (4-byte string)
+ fdCreator Byte[4] Creator of the File (4-byte string)
+ fdFlags beShort Finder Flags
+ fdLocation.v beShort Finder Icon Location
+ fdLocation.h beShort Finder Icon Location
+ fdFldr beShort Folder containing file
+ CrDat beLong HParamBlockRec fileParam.ioFlCrDat
+ MdDat beLong HParamBlockRec fileParam.ioFlMdDat
+ frScroll.v Byte vertical pos. of folder's scroll bar
+ fdScript Byte Script flag and number
+ frScroll.h Byte horizontal pos. of folder's scroll bar
+ fdXFlags Byte More flag bits
+ FileName Byte[32] full Macintosh filename (pascal string)
+
+ All fields but the first two are in native Macintosh format
+ (big-endian Motorola order, not little-endian Intel).
+ The extra field size is fixed to 64 bytes.
+ The local-header and central-header versions are identical.
+
+
+ -Acorn SparkFS Extra Field:
+ =========================
+
+ The following is the layout of David Pilling's SparkFS extra block
+ for Acorn RISC OS. The local-header and central-header versions are
+ identical. (Last Revision 19960922)
+
+ Value Size Description
+ ----- ---- -----------
+ (Acorn) 0x4341 Short tag for this extra block type ("AC")
+ TSize Short total data size for this block (20)
+ "ARC0" Long extra-field signature
+ LoadAddr Long load address or file type
+ ExecAddr Long exec address
+ Attr Long file permissions
+ Zero Long reserved; always zero
+
+ The following bits of Attr are associated with the given file
+ permissions:
+
+ bit 0 user-writable ('W')
+ bit 1 user-readable ('R')
+ bit 2 reserved
+ bit 3 locked ('L')
+ bit 4 publicly writable ('w')
+ bit 5 publicly readable ('r')
+ bit 6 reserved
+ bit 7 reserved
+
+
+ -VM/CMS Extra Field:
+ ==================
+
+ The following is the layout of the file-attributes extra block for
+ VM/CMS. The local-header and central-header versions are
+ identical. (Last Revision 19960922)
+
+ Value Size Description
+ ----- ---- -----------
+ (VM/CMS) 0x4704 Short tag for this extra block type
+ TSize Short total data size for this block
+ flData variable file attributes data
+
+ flData is an uncompressed fldata_t struct.
+
+
+ -MVS Extra Field:
+ ===============
+
+ The following is the layout of the file-attributes extra block for
+ MVS. The local-header and central-header versions are identical.
+ (Last Revision 19960922)
+
+ Value Size Description
+ ----- ---- -----------
+ (MVS) 0x470f Short tag for this extra block type
+ TSize Short total data size for this block
+ flData variable file attributes data
+
+ flData is an uncompressed fldata_t struct.
+
+
+ -PKWARE Unix Extra Field:
+ ========================
+
+ The following is the layout of PKWARE's Unix "extra" block.
+ It was introduced with the release of PKZIP for Unix 2.50.
+ Note: all fields are stored in Intel low-byte/high-byte order.
+ (Last Revision 19980901)
+
+ This field has a minimum data size of 12 bytes and is only stored
+ as local extra field.
+
+ Value Size Description
+ ----- ---- -----------
+ (Unix0) 0x000d Short Tag for this "extra" block type
+ TSize Short Total Data Size for this block
+ AcTime Long time of last access (UTC/GMT)
+ ModTime Long time of last modification (UTC/GMT)
+ UID Short Unix user ID
+ GID Short Unix group ID
+ (var) variable Variable length data field
+
+ The variable length data field will contain file type
+ specific data. Currently the only values allowed are
+ the original "linked to" file names for hard or symbolic
+ links, and the major and minor device node numbers for
+ character and block device nodes. Since device nodes
+ cannot be either symbolic or hard links, only one set of
+ variable length data is stored. Link files will have the
+ name of the original file stored. This name is NOT NULL
+ terminated. Its size can be determined by checking TSize -
+ 12. Device entries will have eight bytes stored as two 4
+ byte entries (in little-endian format). The first entry
+ will be the major device number, and the second the minor
+ device number.
+
+ [Info-ZIP note: The fixed part of this field has the same layout as
+ Info-ZIP's abandoned "Unix1 timestamps & owner ID info" extra field;
+ only the two tag bytes are different.]
+
+
+ -PATCH Descriptor Extra Field:
+ ============================
+
+ The following is the layout of the Patch Descriptor "extra"
+ block.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (Patch) 0x000f Short Tag for this "extra" block type
+ TSize Short Size of the total "extra" block
+ Version Short Version of the descriptor
+ Flags Long Actions and reactions (see below)
+ OldSize Long Size of the file about to be patched
+ OldCRC Long 32-bit CRC of the file about to be patched
+ NewSize Long Size of the resulting file
+ NewCRC Long 32-bit CRC of the resulting file
+
+
+ Actions and reactions
+
+ Bits Description
+ ---- ----------------
+ 0 Use for autodetection
+ 1 Treat as selfpatch
+ 2-3 RESERVED
+ 4-5 Action (see below)
+ 6-7 RESERVED
+ 8-9 Reaction (see below) to absent file
+ 10-11 Reaction (see below) to newer file
+ 12-13 Reaction (see below) to unknown file
+ 14-15 RESERVED
+ 16-31 RESERVED
+
+ Actions
+
+ Action Value
+ ------ -----
+ none 0
+ add 1
+ delete 2
+ patch 3
+
+ Reactions
+
+ Reaction Value
+ -------- -----
+ ask 0
+ skip 1
+ ignore 2
+ fail 3
+
+
+ -PKCS#7 Store for X.509 Certificates:
+ ===================================
+
+ This field is contains the information about each
+ certificate a file is signed with. This field should only
+ appear in the first central directory record, and will be
+ ignored in any other record.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (Store) 0x0014 2 bytes Tag for this "extra" block type
+ SSize 2 bytes Size of the store data
+ SData (variable) Data about the store
+
+ SData
+ Value Size Description
+ ----- ---- -----------
+ Version 2 bytes Version number, 0x0001 for now
+ StoreD (variable) Actual store data
+
+ The StoreD member is suitable for passing as the pbData
+ member of a CRYPT_DATA_BLOB to the CertOpenStore() function
+ in Microsoft's CryptoAPI. The SSize member above will be
+ cbData + 6, where cbData is the cbData member of the same
+ CRYPT_DATA_BLOB. The encoding type to pass to
+ CertOpenStore() should be
+ PKCS_7_ANS_ENCODING | X509_ASN_ENCODING.
+
+
+ -X.509 Certificate ID and Signature for individual file:
+ ======================================================
+
+ This field contains the information about which certificate
+ in the PKCS#7 Store was used to sign the particular file.
+ It also contains the signature data. This field can appear
+ multiple times, but can only appear once per certificate.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (CID) 0x0015 2 bytes Tag for this "extra" block type
+ CSize 2 bytes Size of Method
+ Method (variable)
+
+ Method
+ Value Size Description
+ ----- ---- -----------
+ Version 2 bytes Version number, for now 0x0001
+ AlgID 2 bytes Algorithm ID used for signing
+ IDSize 2 bytes Size of Certificate ID data
+ CertID (variable) Certificate ID data
+ SigSize 2 bytes Size of Signature data
+ Sig (variable) Signature data
+
+ CertID
+ Value Size Description
+ ----- ---- -----------
+ Size1 4 bytes Size of CertID, should be (IDSize - 4)
+ Size1 4 bytes A bug in version one causes this value
+ to appear twice.
+ IssSize 4 bytes Issuer data size
+ Issuer (variable) Issuer data
+ SerSize 4 bytes Serial Number size
+ Serial (variable) Serial Number data
+
+ The Issuer and IssSize members are suitable for creating a
+ CRYPT_DATA_BLOB to be the Issuer member of a CERT_INFO
+ struct. The Serial and SerSize members would be the
+ SerialNumber member of the same CERT_INFO struct. This
+ struct would be used to find the certificate in the store
+ the file was signed with. Those structures are from the MS
+ CryptoAPI.
+
+ Sig and SigSize are the actual signature data and size
+ generated by signing the file with the MS CryptoAPI using a
+ hash created with the given AlgID.
+
+
+ -X.509 Certificate ID and Signature for central directory:
+ ========================================================
+
+ This field contains the information about which certificate
+ in the PKCS#7 Store was used to sign the central directory.
+ It should only appear with the first central directory
+ record, along with the store. The data structure is the
+ same as the CID, except that SigSize will be 0, and there
+ will be no Sig member.
+
+ This field is also kept after the last central directory
+ record, as the signature data (ID 0x05054b50, it looks like
+ a central directory record of a different type). This
+ second copy of the data is the Signature Data member of the
+ record, and will have a SigSize that is non-zero, and will
+ have Sig data.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (CDID) 0x0016 2 bytes Tag for this "extra" block type
+ CSize 2 bytes Size of Method
+ Method (variable)
+
+
+ -ZIP64 Extended Information Extra Field:
+ ======================================
+
+ The following is the layout of the ZIP64 extended
+ information "extra" block. If one of the size or
+ offset fields in the Local or Central directory
+ record is too small to hold the required data,
+ a ZIP64 extended information record is created.
+ The order of the fields in the ZIP64 extended
+ information record is fixed, but the fields will
+ only appear if the corresponding Local or Central
+ directory record field is set to 0xFFFF or 0xFFFFFFFF.
+
+ Note: all fields stored in Intel low-byte/high-byte order.
+
+ Value Size Description
+ ----- ---- -----------
+ (ZIP64) 0x0001 2 bytes Tag for this "extra" block type
+ Size 2 bytes Size of this "extra" block
+ Original
+ Size 8 bytes Original uncompresseed file size
+ Compressed
+ Size 8 bytes Size of compressed data
+ Relative Header
+ Offset 8 bytes Offset of local header record
+ Disk Start
+ Number 4 bytes Number of the disk on which
+ this file starts
+
+ This entry in the Local header must include BOTH original
+ and compressed file sizes.
+
+
+ -Extended Timestamp Extra Field:
+ ==============================
+
+ The following is the layout of the extended-timestamp extra block.
+ (Last Revision 19970118)
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (time) 0x5455 Short tag for this extra block type ("UT")
+ TSize Short total data size for this block
+ Flags Byte info bits
+ (ModTime) Long time of last modification (UTC/GMT)
+ (AcTime) Long time of last access (UTC/GMT)
+ (CrTime) Long time of original creation (UTC/GMT)
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (time) 0x5455 Short tag for this extra block type ("UT")
+ TSize Short total data size for this block
+ Flags Byte info bits (refers to local header!)
+ (ModTime) Long time of last modification (UTC/GMT)
+
+ The central-header extra field contains the modification time only,
+ or no timestamp at all. TSize is used to flag its presence or
+ absence. But note:
+
+ If "Flags" indicates that Modtime is present in the local header
+ field, it MUST be present in the central header field, too!
+ This correspondence is required because the modification time
+ value may be used to support trans-timezone freshening and
+ updating operations with zip archives.
+
+ The time values are in standard Unix signed-long format, indicating
+ the number of seconds since 1 January 1970 00:00:00. The times
+ are relative to Coordinated Universal Time (UTC), also sometimes
+ referred to as Greenwich Mean Time (GMT). To convert to local time,
+ the software must know the local timezone offset from UTC/GMT.
+
+ The lower three bits of Flags in both headers indicate which time-
+ stamps are present in the LOCAL extra field:
+
+ bit 0 if set, modification time is present
+ bit 1 if set, access time is present
+ bit 2 if set, creation time is present
+ bits 3-7 reserved for additional timestamps; not set
+
+ Those times that are present will appear in the order indicated, but
+ any combination of times may be omitted. (Creation time may be
+ present without access time, for example.) TSize should equal
+ (1 + 4*(number of set bits in Flags)), as the block is currently
+ defined. Other timestamps may be added in the future.
+
+
+ -Info-ZIP Unix Extra Field (type 1):
+ ==================================
+
+ The following is the layout of the old Info-ZIP extra block for
+ Unix. It has been replaced by the extended-timestamp extra block
+ (0x5455) and the Unix type 2 extra block (0x7855).
+ (Last Revision 19970118)
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (Unix1) 0x5855 Short tag for this extra block type ("UX")
+ TSize Short total data size for this block
+ AcTime Long time of last access (UTC/GMT)
+ ModTime Long time of last modification (UTC/GMT)
+ UID Short Unix user ID (optional)
+ GID Short Unix group ID (optional)
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (Unix1) 0x5855 Short tag for this extra block type ("UX")
+ TSize Short total data size for this block
+ AcTime Long time of last access (GMT/UTC)
+ ModTime Long time of last modification (GMT/UTC)
+
+ The file access and modification times are in standard Unix signed-
+ long format, indicating the number of seconds since 1 January 1970
+ 00:00:00. The times are relative to Coordinated Universal Time
+ (UTC), also sometimes referred to as Greenwich Mean Time (GMT). To
+ convert to local time, the software must know the local timezone
+ offset from UTC/GMT. The modification time may be used by non-Unix
+ systems to support inter-timezone freshening and updating of zip
+ archives.
+
+ The local-header extra block may optionally contain UID and GID
+ info for the file. The local-header TSize value is the only
+ indication of this. Note that Unix UIDs and GIDs are usually
+ specific to a particular machine, and they generally require root
+ access to restore.
+
+ This extra field type is obsolete, but it has been in use since
+ mid-1994. Therefore future archiving software should continue to
+ support it. Some guidelines:
+
+ An archive member should either contain the old "Unix1"
+ extra field block or the new extra field types "time" and/or
+ "Unix2".
+
+ If both the old "Unix1" block type and one or both of the new
+ block types "time" and "Unix2" are found, the "Unix1" block
+ should be considered invalid and ignored.
+
+ Unarchiving software should recognize both old and new extra
+ field block types, but the info from new types overrides the
+ old "Unix1" field.
+
+ Archiving software should recognize "Unix1" extra fields for
+ timestamp comparison but never create it for updated, freshened
+ or new archive members. When copying existing members to a new
+ archive, any "Unix1" extra field blocks should be converted to
+ the new "time" and/or "Unix2" types.
+
+
+ -Info-ZIP Unix Extra Field (type 2):
+ ==================================
+
+ The following is the layout of the new Info-ZIP extra block for
+ Unix. (Last Revision 19960922)
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (Unix2) 0x7855 Short tag for this extra block type ("Ux")
+ TSize Short total data size for this block (4)
+ UID Short Unix user ID
+ GID Short Unix group ID
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (Unix2) 0x7855 Short tag for this extra block type ("Ux")
+ TSize Short total data size for this block (0)
+
+ The data size of the central-header version is zero; it is used
+ solely as a flag that UID/GID info is present in the local-header
+ extra field. If additional fields are ever added to the local
+ version, the central version may be extended to indicate this.
+
+ Note that Unix UIDs and GIDs are usually specific to a particular
+ machine, and they generally require root access to restore.
+
+
+ -ASi Unix Extra Field:
+ ====================
+
+ The following is the layout of the ASi extra block for Unix. The
+ local-header and central-header versions are identical.
+ (Last Revision 19960916)
+
+ Value Size Description
+ ----- ---- -----------
+ (Unix3) 0x756e Short tag for this extra block type ("nu")
+ TSize Short total data size for this block
+ CRC Long CRC-32 of the remaining data
+ Mode Short file permissions
+ SizDev Long symlink'd size OR major/minor dev num
+ UID Short user ID
+ GID Short group ID
+ (var.) variable symbolic link filename
+
+ Mode is the standard Unix st_mode field from struct stat, containing
+ user/group/other permissions, setuid/setgid and symlink info, etc.
+
+ If Mode indicates that this file is a symbolic link, SizDev is the
+ size of the file to which the link points. Otherwise, if the file
+ is a device, SizDev contains the standard Unix st_rdev field from
+ struct stat (includes the major and minor numbers of the device).
+ SizDev is undefined in other cases.
+
+ If Mode indicates that the file is a symbolic link, the final field
+ will be the name of the file to which the link points. The file-
+ name length can be inferred from TSize.
+
+ [Note that TSize may incorrectly refer to the data size not counting
+ the CRC; i.e., it may be four bytes too small.]
+
+
+ -BeOS Extra Field:
+ ================
+
+ The following is the layout of the file-attributes extra block for
+ BeOS. (Last Revision 19970531)
+
+ Local-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (BeOS) 0x6542 Short tag for this extra block type ("Be")
+ TSize Short total data size for this block
+ BSize Long uncompressed file attribute data size
+ Flags Byte info bits
+ (CType) Short compression type
+ (CRC) Long CRC value for uncompressed file attribs
+ Attribs variable file attribute data
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (BeOS) 0x6542 Short tag for this extra block type ("Be")
+ TSize Short total data size for this block (5)
+ BSize Long size of uncompr. local EF block data
+ Flags Byte info bits
+
+ The least significant bit of Flags in both headers indicates whether
+ the LOCAL extra field is uncompressed (and therefore whether CType
+ and CRC are omitted):
+
+ bit 0 if set, Attribs is uncompressed (no CType, CRC)
+ bits 1-7 reserved; if set, assume error or unknown data
+
+ Currently the only supported compression types are deflated (type 8)
+ and stored (type 0); the latter is not used by Info-ZIP's Zip but is
+ supported by UnZip.
+
+ Attribs is a BeOS-specific block of data in big-endian format with
+ the following structure (if compressed, uncompress it first):
+
+ Value Size Description
+ ----- ---- -----------
+ Name variable attribute name (null-terminated string)
+ Type Long attribute type (32-bit unsigned integer)
+ Size Long Long data size for this sub-block (64 bits)
+ Data variable attribute data
+
+ The attribute structure is repeated for every attribute. The Data
+ field may contain anything--text, flags, bitmaps, etc.
+
+
+ -SMS/QDOS Extra Field:
+ ====================
+
+ The following is the layout of the file-attributes extra block for
+ SMS/QDOS. The local-header and central-header versions are identical.
+ (Last Revision 19960929)
+
+ Value Size Description
+ ----- ---- -----------
+ (QDOS) 0xfb4a Short tag for this extra block type
+ TSize Short total data size for this block
+ LongID Long extra-field signature
+ (ExtraID) Long additional signature/flag bytes
+ QDirect 64 bytes qdirect structure
+
+ LongID may be "QZHD" or "QDOS". In the latter case, ExtraID will
+ be present. Its first three bytes are "02\0"; the last byte is
+ currently undefined.
+
+ QDirect contains the file's uncompressed directory info (qdirect
+ struct). Its elements are in native (big-endian) format:
+
+ d_length beLong file length
+ d_access byte file access type
+ d_type byte file type
+ d_datalen beLong data length
+ d_reserved beLong unused
+ d_szname beShort size of filename
+ d_name 36 bytes filename
+ d_update beLong time of last update
+ d_refdate beLong file version number
+ d_backup beLong time of last backup (archive date)
+
+
+ -AOS/VS Extra Field:
+ ==================
+
+ The following is the layout of the extra block for Data General
+ AOS/VS. The local-header and central-header versions are identical.
+ (Last Revision 19961125)
+
+ Value Size Description
+ ----- ---- -----------
+ (AOSVS) 0x5356 Short tag for this extra block type ("VS")
+ TSize Short total data size for this block
+ "FCI\0" Long extra-field signature
+ Version Byte version of AOS/VS extra block (10 = 1.0)
+ Fstat variable fstat packet
+ AclBuf variable raw ACL data ($MXACL bytes)
+
+ Fstat contains the file's uncompressed fstat packet, which is one of
+ the following:
+
+ normal fstat packet (P_FSTAT struct)
+ DIR/CPD fstat packet (P_FSTAT_DIR struct)
+ unit (device) fstat packet (P_FSTAT_UNIT struct)
+ IPC file fstat packet (P_FSTAT_IPC struct)
+
+ AclBuf contains the raw ACL data; its length is $MXACL.
+
+
+ -Tandem NSK Extra Field:
+ ======================
+
+ The following is the layout of the file-attributes extra block for
+ Tandem NSK. The local-header and central-header versions are
+ identical. (Last Revision 19981221)
+
+ Value Size Description
+ ----- ---- -----------
+ (TA) 0x4154 Short tag for this extra block type ("TA")
+ TSize Short total data size for this block (20)
+ NSKattrs 20 Bytes NSK attributes
+
+
+ -THEOS Extra Field:
+ =================
+
+ The following is the layout of the file-attributes extra block for
+ Theos. The local-header and central-header versions are identical.
+ (Last Revision 19990206)
+
+ Value Size Description
+ ----- ---- -----------
+ (Theos) 0x6854 Short 'Th' signature
+ size Short size of extra block
+ flags Byte reserved for future use
+ filesize Long file size
+ fileorg Byte type of file (see below)
+ keylen Short key length for indexed and keyed files,
+ data segment size for 16 bits programs
+ reclen Short record length for indexed,keyed and direct,
+ text segment size for 16 bits programs
+ filegrow Byte growing factor for indexed,keyed and direct
+ protect Byte protections (see below)
+ reserved Short reserved for future use
+
+ File types
+ ==========
+
+ 0x80 library (keyed access list of files)
+ 0x40 directory
+ 0x10 stream file
+ 0x08 direct file
+ 0x04 keyed file
+ 0x02 indexed file
+ 0x0e reserved
+ 0x01 16 bits real mode program (obsolete)
+ 0x21 16 bits protected mode program
+ 0x41 32 bits protected mode program
+
+ Protection codes
+ ================
+
+ User protection
+ ---------------
+ 0x01 non readable
+ 0x02 non writable
+ 0x04 non executable
+ 0x08 non erasable
+
+ Other protection
+ ----------------
+ 0x10 non readable
+ 0x20 non writable
+ 0x40 non executable Theos before 4.0
+ 0x40 modified Theos 4.x
+ 0x80 not hidden
+
+
+ -THEOS old inofficial Extra Field:
+ ================================
+
+ The following is the layout of an inoffical former version of a
+ Theos file-attributes extra blocks. This layout was never published
+ and is no longer created. However, UnZip can optionally support it
+ when compiling with the option flag OLD_THEOS_EXTRA defined.
+ Both the local-header and central-header versions are identical.
+ (Last Revision 19990206)
+
+ Value Size Description
+ ----- ---- -----------
+ (THS0) 0x4854 Short 'TH' signature
+ size Short size of extra block
+ flags Short reserved for future use
+ filesize Long file size
+ reclen Short record length for indexed,keyed and direct,
+ text segment size for 16 bits programs
+ keylen Short key length for indexed and keyed files,
+ data segment size for 16 bits programs
+ filegrow Byte growing factor for indexed,keyed and direct
+ reserved 3 Bytes reserved for future use
+
+
+ -FWKCS MD5 Extra Field:
+ =====================
+
+ The FWKCS Contents_Signature System, used in automatically
+ identifying files independent of filename, optionally adds
+ and uses an extra field to support the rapid creation of
+ an enhanced contents_signature.
+ There is no local-header version; the following applies
+ only to the central header. (Last Revision 19961207)
+
+ Central-header version:
+
+ Value Size Description
+ ----- ---- -----------
+ (MD5) 0x4b46 Short tag for this extra block type ("FK")
+ TSize Short total data size for this block (19)
+ "MD5" 3 bytes extra-field signature
+ MD5hash 16 bytes 128-bit MD5 hash of uncompressed data
+ (low byte first)
+
+ When FWKCS revises a .ZIP file central directory to add
+ this extra field for a file, it also replaces the
+ central directory entry for that file's uncompressed
+ file length with a measured value.
+
+ FWKCS provides an option to strip this extra field, if
+ present, from a .ZIP file central directory. In adding
+ this extra field, FWKCS preserves .ZIP file Authenticity
+ Verification; if stripping this extra field, FWKCS
+ preserves all versions of AV through PKZIP version 2.04g.
+
+ FWKCS, and FWKCS Contents_Signature System, are
+ trademarks of Frederick W. Kantor.
+
+ (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer
+ Science and RSA Data Security, Inc., April 1992.
+ ll.76-77: "The MD5 algorithm is being placed in the
+ public domain for review and possible adoption as a
+ standard."
+
+
+ -Info-ZIP Unicode Path Extra Field:
+ =================================
+
+ Stores the UTF-8 version of the entry path as stored in the
+ local header and central directory header.
+ (Last Revision 20070912)
+
+ Value Size Description
+ ----- ---- -----------
+ (UPath) 0x7075 Short tag for this extra block type ("up")
+ TSize Short total data size for this block
+ Version 1 byte version of this extra field, currently 1
+ NameCRC32 4 bytes File Name Field CRC32 Checksum
+ UnicodeName Variable UTF-8 version of the entry File Name
+
+ Currently Version is set to the number 1. If there is a need
+ to change this field, the version will be incremented. Changes
+ may not be backward compatible so this extra field should not be
+ used if the version is not recognized.
+
+ The NameCRC32 is the standard zip CRC32 checksum of the File Name
+ field in the header. This is used to verify that the header
+ File Name field has not changed since the Unicode Path extra field
+ was created. This can happen if a utility renames the entry but
+ does not update the UTF-8 path extra field. If the CRC check fails,
+ this UTF-8 Path Extra Field should be ignored and the File Name field
+ in the header used instead.
+
+ The UnicodeName is the UTF-8 version of the contents of the File Name
+ field in the header. As UnicodeName is defined to be UTF-8, no UTF-8
+ byte order mark (BOM) is used. The length of this field is determined
+ by subtracting the size of the previous fields from TSize. If both
+ the File Name and Comment fields are UTF-8, the new General Purpose
+ Bit Flag, bit 11 (Language encoding flag (EFS)), can be used to
+ indicate that both the header File Name and Comment fields are UTF-8
+ and, in this case, the Unicode Path and Unicode Comment extra fields
+ are not needed and should not be created. Note that, for backward
+ compatibility, bit 11 should only be used if the native character set
+ of the paths and comments being zipped up are already in UTF-8. The
+ same method, either bit 11 or extra fields, should be used in both
+ the local and central directory headers.
+
+
+ -Info-ZIP Unicode Comment Extra Field:
+ ====================================
+
+ Stores the UTF-8 version of the entry comment as stored in the
+ central directory header.
+ (Last Revision 20070912)
+
+ Value Size Description
+ ----- ---- -----------
+ (UCom) 0x6375 Short tag for this extra block type ("uc")
+ TSize Short total data size for this block
+ Version 1 byte version of this extra field, currently 1
+ ComCRC32 4 bytes Comment Field CRC32 Checksum
+ UnicodeCom Variable UTF-8 version of the entry comment
+
+ Currently Version is set to the number 1. If there is a need
+ to change this field, the version will be incremented. Changes
+ may not be backward compatible so this extra field should not be
+ used if the version is not recognized.
+
+ The ComCRC32 is the standard zip CRC32 checksum of the Comment
+ field in the central directory header. This is used to verify that
+ the comment field has not changed since the Unicode Comment extra field
+ was created. This can happen if a utility changes the Comment field
+ but does not update the UTF-8 Comment extra field. If the CRC check
+ fails, this Unicode Comment extra field should be ignored and the
+ Comment field in the header used.
+
+ The UnicodeCom field is the UTF-8 version of the entry comment field
+ in the header. As UnicodeCom is defined to be UTF-8, no UTF-8 byte
+ order mark (BOM) is used. The length of this field is determined by
+ subtracting the size of the previous fields from TSize. If both the
+ File Name and Comment fields are UTF-8, the new General Purpose Bit
+ Flag, bit 11 (Language encoding flag (EFS)), can be used to indicate
+ both the header File Name and Comment fields are UTF-8 and, in this
+ case, the Unicode Path and Unicode Comment extra fields are not
+ needed and should not be created. Note that, for backward
+ compatibility, bit 11 should only be used if the native character set
+ of the paths and comments being zipped up are already in UTF-8. The
+ same method, either bit 11 or extra fields, should be used in both
+ the local and central directory headers.
+
+
+ -Info-ZIP New Unix Extra Field:
+ ====================================
+
+ Currently stores Unix UIDs/GIDs up to 32 bits.
+ (Last Revision 20080509)
+
+ Value Size Description
+ ----- ---- -----------
+ (UnixN) 0x7875 Short tag for this extra block type ("ux")
+ TSize Short total data size for this block
+ Version 1 byte version of this extra field, currently 1
+ UIDSize 1 byte Size of UID field
+ UID Variable UID for this entry
+ GIDSize 1 byte Size of GID field
+ GID Variable GID for this entry
+
+ Currently Version is set to the number 1. If there is a need
+ to change this field, the version will be incremented. Changes
+ may not be backward compatible so this extra field should not be
+ used if the version is not recognized.
+
+ UIDSize is the size of the UID field in bytes. This size should
+ match the size of the UID field on the target OS.
+
+ UID is the UID for this entry in standard little endian format.
+
+ GIDSize is the size of the GID field in bytes. This size should
+ match the size of the GID field on the target OS.
+
+ GID is the GID for this entry in standard little endian format.
+
+ If both the old 16-bit Unix extra field (tag 0x7855, Info-ZIP Unix)
+ and this extra field are present, the values in this extra field
+ supercede the values in that extra field.
diff --git a/proginfo/fileinfo.cms b/proginfo/fileinfo.cms
new file mode 100644
index 0000000..9d21935
--- /dev/null
+++ b/proginfo/fileinfo.cms
@@ -0,0 +1,231 @@
+[Quoting from a C/370 manual, courtesy of Carl Forde.]
+
+ C/370 supports three types of input and output: text streams, binary
+ streams, and record I/O. Text and binary streams are both ANSI
+ standards; record I/O is a C/370 extension.
+
+[...]
+
+ Record I/O is a C/370 extension to the ANSI standard. For files
+ opened in record format, C/370 reads and writes one record at a
+ time. If you try to write more data to a record than the record
+ can hold, the data is truncated. For record I/O, C/370 only allows
+ the use of fread() and fwrite() to read and write to the files. Any
+ other functions (such as fprintf(), fscanf(), getc(), and putc())
+ fail. For record-orientated files, records do not change size when
+ you update them. If the new data has fewer characters than the
+ original record, the new data fills the first n characters, where
+ n is the number of characters of the new data. The record will
+ remain the same size, and the old characters (those after) n are
+ left unchanged. A subsequent update begins at the next boundary.
+ For example, if you have the string "abcdefgh":
+
+ abcdefgh
+
+ and you overwrite it with the string "1234", the record will look
+ like this:
+
+ 1234efgh
+
+ C/370 record I/O is binary. That is, it does not interpret any of
+ the data in a record file and therefore does not recognize control
+ characters.
+
+
+ The record model consists of:
+
+ * A record, which is the unit of data transmitted to and from a
+ program
+ * A block, which is the unit of data transmitted to and from a
+ device. Each block may contain one or more records.
+
+ In the record model of I/O, records and blocks have the following
+ attributes:
+
+ RECFM Specifies the format of the data or how the data is organized
+ on the physical device.
+ LRECL Specifies the length of logical records (as opposed to
+ physical ones).
+
+ BLKSIZE Specifies the length of physical records (blocks on the
+ physical device).
+
+
+ Opening a File by Filename
+
+ The filename that you specify on the call to fopen() or freopen()
+ must be in the following format:
+
+ >> ----filename---- ----filetype--------------------
+ | | | |
+ --.-- -- --filemode--
+ | |
+ --.--
+ where
+
+ filename is a 1- to 8-character string of any of the characters,
+ A-Z, a-z, 0-9, and +, -, $, #, @, :, and _. You can separate it
+ from the filetype with one or more spaces, or with a period.
+ [Further note: filenames are fully case-sensitive, as in Unix.]
+
+ filetype is a 1- to 8-character string of any of the characters,
+ A-Z, a-z, 0-9, and +, -, $, #, @, :, and _. You can separate it
+ from the filemode with one or more spaces, or with a period. The
+ separator between filetype and filemode must be the same as the
+ one between filename and filetype.
+
+ filemode is a 1- to 2-character string. The first must be any of
+ the characters A-Z, a-z, or *. If you use the asis parameter on
+ the fopen() or freopen() call, the first character of the filemode
+ must be a capital letter or an asterisk. Otherwise, the function
+ call fails. The second character of filemode is optional; if you
+ specify it, it must be any of the digits 0-6. You cannot specify
+ the second character if you have specified * for the first one.
+
+ If you do not use periods as separators, there is no limit to how
+ much whitespace you can have before and after the filename, the
+ filetype, and filemode.
+
+
+ Opening a File without a File Mode Specified
+
+ If you omit the file mode or specify * for it, C/370 does one
+ of the following when you call fopen() or freopen():
+
+ * If you have specified a read mode, C/370 looks for the named file
+ on all the accessed readable disks, in order. If it does not find
+ the file, the fopen() or freopen() call fails.
+ * If you have specified any of the write modes, C/370 writes the file
+ on the first writable disk you have accessed. Specifying a write
+ mode on an fopen() or freopen() call that contains the filename of
+ an existing file destroys that file. If you do not have any
+ writable disks accessed, the call fails.
+
+
+ fopen() and freopen() parameters
+
+ recfm
+ CMS supports only two RECFMs, V and F. [note that MVS supports
+ 27(!) different RECFMs.] If you do not specify the RECFM for a
+ file, C/370 determines whether is is in fixed or variable format.
+
+ lrecl and blksize
+ For files in fixed format, CMS allows records to be read and
+ written in blocks. To have a fixed format CMS file treated as a
+ fixed blocked CMS file, you can open the file with recfm=fb and
+ specify the lrecl and blksize. If you do not specify a recfm on
+ the open, the blksize can be a multiple of the lrecl, and the
+ file is treated as if it were blocked.
+
+ For files in variable format, the CMS LRECL is different from the
+ LRECL for the record model. In the record model, the LRECL is
+ equal to the data length plus 4 bytes (for the record descriptor
+ word), and the BLKSIZE is equal to the LRECL plus 4 bytes (for
+ the block descriptor word). In CMS, BDWs and RDWs do not exist,
+ but because CMS follows the record model, you must still account
+ for them. When you specify V, you must still allocate the record
+ descriptor word and block descriptor word. That is, if you want
+ a maximum of n bytes per record, you must specify a minimum LRECL
+ of n+4 and a minimum BLKSIZE of n+8.
+
+ When you are appending to V files, you can enlarge the record size
+ dynamically, but only if you have not specified LRECL or BLKSIZE
+ on the fopen() or freopen() command that opened the file.
+
+ type
+ If you specify this parameter, the only valid value for CMS disk
+ files is type =record. This opens a file for record I/O.
+
+ asis
+ If you use this parameter, you can open files with mixed-case
+ filenames such as JaMeS dAtA or pErCy.FILE. If you specify this
+ parameter, the file mode that you specify must be a capital letter
+ (if it is not an asterisk); otherwise; the function call fails and
+ the value returned is NULL.
+
+
+ Reading from Record I/O Files
+ fread() is the only interface allowed for reading record I/O files.
+ Each time you call fread() for a record I/O file, fread() reads
+ one record from the system. If you call fread() with a request for
+ less than a complete record, the requested bytes are copied to your
+ buffer, and the file position is set to the start fo the next
+ record. If the request is for more bytes that are in the record,
+ one record is read and the position is set to the start of the next
+ record. C/370 does not strip any blank characters or interpret any
+ data.
+
+ fread() returns the number of items read successfully, so if you
+ pass a size argument equal to 1 and a count argument equal to the
+ maximum expected length of the record, fread() returns the length,
+ in bytes, of the record read. If you pass a size argument equal
+ to the maximum expected length of the record, and a count argument
+ equal to 1, fread() returns either 0 or 1, indicating whether a
+ record of length size read. If a record is read successfully but
+ is less than size bytes long, fread() returns 0.
+
+
+ Writing to Record I/O Files
+ fwrite() is the only interface allowed for writing to a file
+ opened for record I/O. Only one record is written at a time. If
+ you attempt to write more new data than a full record can hold or
+ try to update a record with more data than it currently has, C/370
+ truncates your output at the record boundary. When C/370 performs
+ a truncation, it sets errno and raises SIGIOERR, if SIGIOERR is not
+ set to SIG_IGN.
+
+ When you are writing new records to a fixed-record I/O file, if you
+ try to write a short record, C/370 pads the record with nulls out
+ to LRECL.
+
+ At the completion of an fwrite(), the file position is at the start
+ of the next record. For new data, the block is flushed out to the
+ system as soon as it is full.
+
+
+ fldata() Behavior
+ When you call the fldata() function for an open CMS minidisk file,
+ it returns a data structure that looks like this:
+
+ struct __filedata {
+ unsigned int __recfmF : 1, /* fixed length records */
+ __recfmV : 1, /* variable length records */
+ __recfmU : 1, /* n/a */
+ __recfmS : 1, /* n/a */
+ __recfmBlk : 1, /* n/a */
+ __recfmASA : 1, /* text mode and ASA */
+ __recfmM : 1, /* n/a */
+ __dsorgPO : 1, /* n/a */
+ __dsorgPDSmem : 1, /* n/a */
+ __dsorgPDSdir : 1, /* n/a */
+ __dsorgPS : 1, /* sequential data set */
+ __dsorgConcat : 1, /* n/a */
+ __dsorgMem : 1, /* n/a */
+ __dsorgHiper : 1, /* n/a */
+ __dsorgTemp : 1, /* created with tmpfile() */
+ __dsorgVSAM : 1, /* n/a */
+ __reserve1 : 1, /* n/a */
+ __openmode : 2, /* see below 1 */
+ __modeflag : 4, /* see below 2 */
+ __reserve2 : 9, /* n/a */
+
+ char __device; __DISK
+ unsigned long __blksize, /* see below 3 */
+ __maxreclen; /* see below 4 */
+ unsigned short __vsamtype; /* n/a */
+ unsigned long __vsamkeylen; /* n/a */
+ unsigned long __vsamRKP; /* n/a */
+ char * __dsname; /* fname ftype fmode */
+ unsigned int __reserve4; /* n/a */
+
+ /* note 1: values are: __TEXT, __BINARY, __RECORD
+ note 2: values are: __READ, __WRITE, __APPEND, __UPDATE
+ these values can be added together to determine
+ the return value; for example, a file opened with
+ a+ will have the value __READ + __APPEND.
+ note 3: total block size of the file, including ASA
+ characters as well as RDW information
+ note 4: maximum record length of the data only (includes
+ ASA characters but excludes RDW information).
+ */
+ };
diff --git a/proginfo/infozip.who b/proginfo/infozip.who
new file mode 100644
index 0000000..994851c
--- /dev/null
+++ b/proginfo/infozip.who
@@ -0,0 +1,242 @@
+These members of the Info-ZIP group contributed to the development and
+testing of portable Zip. They are responsible for whatever works in
+Zip. Whatever doesn't work is solely the fault of the authors of Zip
+(Mark Adler, Rich Wales, Jean-loup Gailly, Kai Uwe Rommel, Igor Mandrichenko,
+Onno van der Linden, Christian Spieler, John Bush, Paul Kienitz, Sergio Monesi
+and Karl Davis, but see the license for the latest list). If you have
+contributed and your name has been forgotten, please send a reminder to us
+using the contact information in the Readme file. The names are given here
+in alphabetical order, because it's impossible to classify them by importance
+of the contribution. Some have made a complete port to a new target, some
+have provided a one line fix. All are to be thanked.
+
+
+Mark Adler madler@tybalt.caltech.edu NeXT 2.x, Mac
+ alan@spri.levels.unisa.edu.au Linux
+Jeffrey Altman jaltman@watsun.cc.columbia.edu fseek bug on NT
+Glenn J. Andrews oper1%drcv06.decnet@drcvax.af.mil VAX VMS
+James Van Artsdalen james@raid.dell.com bug report
+Eric Backus ericb@lsid.hp.com bug report
+Quentin Barnes qbarnes@urbana.css.mot.com unix/Makefile mode of
+ installed files
+Elmar Bartel bartel@informatik.tu-muenchen.de
+Mark E. Becker mbecker@cs.uml.edu bug report
+Paul von Behren Paul_von_Behren@stortek.com OS/390 port
+Jon Bell swy@wsdot.wa.gov Intergraph/CLIX
+Myles Bennett - Initial UnZip 6.0 large
+ files beta
+Michael Bernardi mike@childsoc.demon.co.uk RS6000
+Tom Betz marob!upaya!tbetz@phri.nyu.edu SCO Xenix 2.3.1
+James Birdsall jwbirdsa@picarefy.com AT&T 3B1
+George boer@fwi.uva.nl OS/2
+Michael Bolton bolton@vaxc.erim.org VAX/VMS
+Wim Bonner 27313853@WSUVM1.CSC.WSU.EDU HP 9000/840a HPUX
+Paul Borman prb@cray.com Cray-X/YMP,2 UNICOS 6-8
+Kurt Van den Branden kvd2@bipsy.se.bel.alcatel.be VAX VMS
+Scott Briggs briggs@nashua.progress.com Windows NT
+Leslie C. Brown lbrown@BRL.MIL Pyramid MIS-4
+Ralf Brown ralf@b.gp.cs.cmu.edu Pyramid MIS-4
+Rodney Brown rdb@cmutual.com.au SunOS 4.1.3 DGUX OSF/1
+ HP-UX CRC optimization
+Jeremy Daniel Buhler jbuhler@owlnet.rice.edu BC++
+John Bush john.bush@east.sun.com Amiga (SAS/C)
+Pietro Caselli zaphod@petruz.sublink.org Minix 1.5.10
+Andrew A. Chernov ache@astral.msk.su FreeBSD
+Jeff Coffler jeffcof@microsoft.com Windows NT
+David Dachtera David.Dachtera@advocatehealth.com VMS
+ link_zip.com bug
+Bill Davidsen davidsen@crdos1.crd.ge.com Xenix (on what?)
+Karl Davis riscman@geko.com.au Acorn
+Daniel Deimert daniel@pkmab.se zeus3.21 Zilog S8000
+David Denholm denholm@sotona.physics.southampton.ac.uk VMS
+Harald Denker harry@hal.westfalen.de ATARI
+Matthew J. D'Errico doc@magna.com Bull
+L. Peter Deutsch ghost@aladdin.com Linux
+Uwe Doering gemini@geminix.in-berlin.de 386 Unix
+Jean-Michel Dubois jmdubois@ibcfrance.fr Theos support
+James P. Dugal jpd@usl.edu Pyramid 90X OSx4.1
+"Evil Ed" esaffle@gmuvax2.gmu.edu Ultrix-32 V3.1 (Rev. 9)
+Patrick Ellis pellis@aic.mdc.com VMS zip -h appearance
+Thomas Esken esken@uni-muenster.de Acorn fix
+Dwight Estep estep@dlo10.enet.dec.com MSDOS
+David A. Feinleib t-davefe@microsoft.com Windows NT
+Joshua Felsteiner joshua@phys1.technion.ac.il Linux
+Greg Flint afc@klaatu.cc.purdue.edu ETA-10P* hybrid Sys V
+Carl Forde cforde@bcsc02.gov.bc.ca VM/CMS
+Jeff Foy jfoy@glia.biostr.washington.edu IRIX Sys V Rel 3.3.1
+Mike Freeman mikef@pacifier.com Vax VMS
+Kevin M. Fritz kmfritz@apgea.army.mil Turbo C++ 1.0
+ Pyramid
+Jean-loup Gailly jloup@chorus.fr MS-DOS Microsoft C 5.1
+Scott D. Galloway sgallowa@letterkenn-emh1.army.mil Sperry 5000 SysV.3
+Rainer Gerling gerling@faupt101.physik.uni-erlangen.de HPUX, MSDOS
+Henry Gessau henryg@kullmar.kullmar.se Windows NT
+Ed Gordon - Zip 3.0, VB, Unicode,
+ large files, splits, DLLs
+Ian E. Gorman ian@iosphere.net ported zip 2.2 to VM/CMS
+Wayne R. Graves graves@csa2.lbl.gov Vax VMS
+George Grimes grimes@netcom.com Apollo Domain SR10.4
+Hunter Goatley goathunter@MadGoat.com VMS (VAX & Alpha),
+ web and ftp sites
+Arnt Gulbrandsen agulbra@pvv.unit.no Linux
+David Gundlach david@rolf.stat.uga.edu Sun SS1+ SunOS 4.1
+Peter Gutmann pgut1@cs.aukuni.ac.nz bug report
+Dirk Haase d_haase@sitec.de MacOS port
+Mark Hanning-Lee markhl@iris-355.jpl.nasa.gov SGI
+Walter Haidinger e9225662@student.tuwien.ac.at Amiga and general fixes
+Charles Hannum mycroft@ai.mit.edu bug report
+Greg Hartwig ghartwig@ix.netcom.com VM/CMS cleanup
+Tanvir Hassan tanvir.hassan@autodesk.com NT
+Bob Hardy hardy@lucid.com Power C on MSDOS
+Zachary Heilig heilig@plains.nodak.edu Turbo C++ 3.0
+Chris Herborth chrish@pobox.com BeOS port
+Jonathan Hudson jrhudson@bigfoot.com QDOS port
+Mark William Jacobs mark@mensch.stanford.edu MSDOS
+Aubrey Jaffer jaffer@martigny.ai.mit.edu Pixel
+Peter Jones jones.peter@uqam.ca MIPS UMIPS 4.0
+ +Onolimit fix for HP-UX
+Kjetil W. J{\o}rgensen jorgens@lise.unit.no OSF/1, DJGPP v2
+Bruce Kahn bkahn@archive.webo.dg.com MS-DOS Microsoft C 5.1
+Jonathan I. Kamens jik@pit-manager.mit.edu ultrix on DECstation
+Dave Kapalko d.kapalko@att.com bug report
+Bob Kemp Robert.V.Kemp@att.com AT&T 3B2 SysV 3.2v2
+Vivek Khera khera@cs.duke.edu SunOS
+Earl Kiech KIECH@utkvx.utk.edu VAX VMS V5.4-1A
+Paul Kienitz Paul.Kienitz@shelter.sf.ca.us Amiga, Watcom C
+David Kirschbaum kirsch@usasoc.soc.mil He got us all in this
+ mess in the first place
+Thomas Klausner wiz@danbala.tuwien.ac.at cygwin32 and -k fix
+D. Krumbholz krumbh00@marvin.informatik.uni-dortmund.de
+ Acorn filetype and
+ timestamp bug report
+
+Bo Kullmar bk@kullmar.se DNIX 5.3, SunOS 4.1
+Baden Kudrenecky baden@unixg.ubc.ca OS/2
+Giuseppe La Sala lasala@mail.esa.esrin.it VMS
+Jean-Marc Lasgouttes jean-marc.lasgouttes@inria.fr Bug report
+Harry Langenbacher harry@neuron6.Jpl.Nasa.Gov Sun SS1+ SunOS 4.1
+Michael D. Lawler mdlawler@gwmicro.com Mt.Xinu BSD 4.3 on VAX
+ Borland C++ 4.51
+Johnny Lee johnnyl@microsoft.com Microsoft C 7.0
+Michael Lemke michael@io.as.utexas.edu VMS
+David Lemson lemson@ux1.cso.uiuc.edu Sequent Dynix 3.0.17
+Tai-Shan Lin tlin@snakeyes.eecs.wsu.edu OS/2
+Onno van der Linden onno@simplex.nl NetBSD, Borland C++,
+ MSC 7.0, DJGPP 2
+
+Michel loehden%mv13.decnet@vax.hrz.uni-marburg.de VMS
+Warner Losh imp@Solbourne.COM packing algorithm help
+Dave Lovelace davel@grex.cyberspace.org DG AOS/VS
+Erik Luijten erik@tntnhb3.tn.tudelft.nl problem report
+John Lundin lundin@urvax.urich.edu VAX VMS
+Igor Mandrichenko mandrichenko@m10.ihep.su VAX VMS
+Cliff Manis root@csoftec.csf.com SCO 2.3.1 (386)
+Fulvio Marino fulvio@iconet.ico.olivetti.it X/OS 2.3 & 2.4
+Bill Marsh bmarsh@cod.nosc.mil SGI Iris 4D35
+Michael Mauch mauch@gmx.de djgpp LFN attribute fix
+Peter Mauzey ptm@mtdcr.mt.lucent.com AT&T 6300, 7300
+Rafal Z. Maszkowski rzm@mat.torun.edu.pl Convex
+Robert McBroom (?) rm3@ornl.gov DECsystem 5810
+Tom McConnell tmcconne@sedona.intel.com NCR SVR4
+Frank P. McIngvale frankm@eng.auburn.edu Bug report
+Conor McMenamin C.S.McMenamin@sussex.ac.uk MSDOS
+Will Menninger Win32, MinGW
+John Messenger jlm@proteon.com Bug report
+Michael kuch@mailserv.zdv.uni-tuebingen.de SGI
+Dan Mick dmick@pongo.west.sun.com Solaris
+Alan Modra alan@spri.levels.unisa.edu.au Linux
+Laszlo Molnar lmolnar@goliat.eik.bme.hu DJGPP v2
+Jim Mollmann jmq@nccibm1.bitnet OS/2 & MVS
+Sergio Monesi pel0015@cdc8g5.cdc.polimi.it Acorn
+J. Mukherjee jmukherj@ringer.cs.utsa.edu OS/2
+Anthony Naggs amn@ubik.demon.co.uk bug report
+Matti Narkia matti.narkia@ntc.nokia.com VAX VMS
+Rainer Nausedat Zip 3.0, large files
+Robert E. Newman Jr. newmanr@ssl.msfc.nasa.gov bug report
+Robert Nielsen NielsenRJ@ems.com 2.2 -V VMS bug report
+Christian Michel cmichel@de.ibm.com 2.2 check_dup OS/2 bug
+ report
+Thomas S. Opheys opheys@kirk.fmi.uni-passau.de OS/2
+Humberto Ortiz-Zuazaga zuazaga@ucunix.san.uc.edu Linux
+James E. O'Dell jim@fpr.com MacOS
+William O'Shaughnessy williamo@hpcupt1.cup.hp.com HPUX
+Neil Parks neil.parks@pcohio.com MSDOS
+Enrico Renato Palmerini palmer@vxscaq.cineca.it UNISYS 7000 Sys 5 r2.3
+Geoff Pennington Geoff.Pennington@sgcs.co.uk -q output bug
+Keith Petersen w8sdz@simtel20.army.mil Pyramid UCB OSx4.4c
+George Petrov VM/CMS, MVS
+Alan Phillips postmaster@lancaster.ac.uk Dynix/ptx 1.3
+Bruno Pillard bp@chorus.fr SunOS 4.1
+Piet W. Plomp piet@icce.rug.nl MSC 7.0, SCO 3.2v4.0
+John Poltorak j.poltorak@bradford.ac.uk problem report
+Kenneth Porter 72420.2436@compuserve.com OS/2
+Norbert Pueschel pueschel@imsdd.meb.uni-bonn.de Amiga time.lib
+Yuval Rakavy yuval@cs.huji.ac.il MSDOS
+David A Rasmussen dave@convex.csd.uwm.edu Convex C220 with 9.0 OS
+Eric Raymond esr@snark.thyrsus.com Unix
+Jim Read 74312.3103@compuserve.com OS/2
+Michael Regoli mr@cica.indiana.edu Ultrix 3.1 VAX 8650
+ BSD 4.3 IBM RT/125
+ BSD 4.3 MicroVAX 3500
+ SunOS 4.0.3 Sun 4/330
+Jochen Roderburg roderburg@rrz.uni-koeln.de Digital Unix with
+ AFS/NFS converter
+Rick Rodgers rodgers@maxwell.mmwb.ucsf.EDU Unix man page
+Greg Roelofs roe2@midway.uchicago.edu SunOS 4.1.1,4.1.2 Sun 4
+ Unicos 5.1--6.1.5 Cray
+ OS/2 1.3 MS C 6.0
+ Ultrix 4.1,4.2 DEC 5810
+ VMS 5.2, 5.4 VAX 8600
+ Irix 3.3.2, SGI Iris 4D
+ UTS 1.2.4 Amdahl 5880
+Phil Ritzenthaler phil@cgrg.ohio-state.edu SYSV
+Kai Uwe Rommel rommel@ars.de or rommel@leo.org OS/2
+Markus Ruppel m.ruppel@imperial.ac.uk OS/2
+Shimazaki Ryo eririn@ma.mailbank.ne.jp human68k
+Jon Saxton jrs@panix.com Microsoft C 6.0
+Steve Salisbury stevesa@msn.com Microsoft C 8.0
+Timo Salmi ts@uwasa.fi bug report
+Darren Salt ds@youmustbejoking.demon.co.uk RISC OS
+NIIMI Satoshi a01309@cfi.waseda.ac.jp Human68K
+Tom Schmidt tschmidt@micron.com SCO 286
+Martin Schulz martin.schulz@isltd.insignia.com Windows NT, Atari
+Steven Schweda VMS, Unix, large files
+Dan Seyb dseyb@halnet.com AIX
+Mark Shadley shadcat@catcher.com unix fixes
+Timur Shaporev tim@rd.relcom.msk.su MSDOS
+W. T. Sidney sidney@picard.med.ge.com bug report
+Dave Sisson daves@vtcosy.cns.vt.edu AIX 1.1.1 PS/2 & 3090
+Dave Smith smithdt@bp.com Tandem port
+Fred Smith fredex@fcshome.stoneham.ma.us Coherent
+Christian Spieler spieler@ikp.tu-darmstadt.de VMS, MSDOS, emx, djgpp,
+ WIN32, Linux
+Ron Srodawa srodawa@vela.acs.oakland.edu SCO Xenix/386 2.3.3
+Adam Stanley astanley@winternet.com MSDOS
+Bertil Stenstr|m stenis@heron.dafa.se HP-UX 7.0 HP9000/835
+Carl Streeter streeter@oshkoshw.bitnet OS/2
+Reuben Sumner rasumner@undergrad.math.uwaterloo.ca Suggestions
+E-Yen Tan e-yen.tan@brasenose.oxford.ac.uk Borland C++ win32
+Yoshioka Tsuneo tsuneo-y@is.aist-nara.ac.jp Multibyte charset
+ support
+Paul Telles paul@pubnet.com SCO Xenix
+Julian Thompson jrt@oasis.icl.co.uk bug report
+Christopher C. Tjon tjon@plains.nodak.edu bug report
+Robert F Tobler rft@cs.stanford.edu bug report
+Eric Tomio tomio@acri.fr bug report
+Cosmin Truta cosmint@cs.ubbcluj.ro win32 gcc based + asm
+Anthony R. Venson cevens@unix1.sncc.lsu.edu MSDOS/emx
+Antoine Verheijen antoine@sysmail.ucs.ualberta.ca envargs fix
+Arjan de Vet devet@info.win.tue.nl SunOS 4.1, MSC 5.1
+Santiago Vila Doncel sanvila@ba.unex.es MSDOS
+Johan Vromans jv@mh.nl bug report
+Rich Wales wales@cs.ucla.edu SunOS 4.0.3 Sun-3/50
+Scott Walton scottw@io.com BSD/386
+Frank J. Wancho wancho@wsmr-simtel20.army.mil TOPS-20
+ oyvind@stavanger.sgp.slb.com Bug report.
+Takahiro Watanabe wata@first.tsukuba.ac.jp fixes for INSTALL
+Mike White mwhite@pumatech.com wizzip DLL
+Ray Wickert wickert@dc-srv.pa-x.dec.com MSDOS/DJGPP
+Winfried Winkler willi@wap0109.chem.tu-berlin.de AIX
+Norman J. Wong as219@freenet.carleton.ca MSDOS
+Martin Zinser m.zinser@gsi.de VMS 7.x
+
diff --git a/proginfo/ntsd.txt b/proginfo/ntsd.txt
new file mode 100644
index 0000000..8ac31ba
--- /dev/null
+++ b/proginfo/ntsd.txt
@@ -0,0 +1,111 @@
+Info-ZIP portable Zip/UnZip Windows NT security descriptor support
+==================================================================
+Scott Field (sfield@microsoft.com), 8 October 1996
+
+
+This version of Info-ZIP's Win32 code allows for processing of Windows
+NT security descriptors if they were saved in the .zip file using the
+appropriate Win32 Zip running under Windows NT. This also requires
+that the file system that Zip/UnZip operates on supports persistent
+Acl storage. When the operating system is not Windows NT and the
+target file system does not support persistent Acl storage, no security
+descriptor processing takes place.
+
+A Windows NT security descriptor consists of any combination of the
+following components:
+
+ an owner (Sid)
+ a primary group (Sid)
+ a discretionary ACL (Dacl)
+ a system ACL (Sacl)
+ qualifiers for the preceding items
+
+By default, Zip will save all aspects of the security descriptor except
+for the Sacl. The Sacl contains information pertaining to auditing of
+the file, and requires a security privilege be granted to the calling
+user in addition to being enabled by the calling application. In order
+to save the Sacl during Zip, the user must specify the -! switch on the
+Zip commandline. The user must also be granted either the SeBackupPrivilege
+"Backup files and directories" or the SeSystemSecurityPrivilege "Manage
+auditing and security log".
+
+By default, UnZip will not restore any aspects of the security descriptor.
+If the -X option is specified to UnZip, the Dacl is restored to the file.
+The other items in the security descriptor on the new file will receive
+default values. If the -XX option is specified to UnZip, as many aspects
+of the security descriptor as possible will be restored. If the calling
+user is granted the SeRestorePrivilege "Restore files and directories",
+all aspects of the security descriptor will be restored. If the calling
+user is only granted the SeSystemSecurityPrivilege "Manage auditing and
+security log", only the Dacl and Sacl will be restored to the new file.
+
+Note that when operating on files that reside on remote volumes, the
+privileges specified above must be granted to the calling user on that
+remote machine. Currently, there is no way to directly test what privileges
+are present on a remote machine, so Zip and UnZip make a remote privilege
+determination based on an indirect method.
+
+UnZip considerations
+--------------------
+
+In order for file security to be processed correctly, any directory entries
+that have a security descriptor will be processed at the end of the unzip
+cycle. This allows for unzip to process files within the newly created
+directory regardless of the security descriptor associated with the directory
+entry. This also prevents security inheritance problems that can occur as
+a result of creating a new directory and then creating files in that directory
+that will inherit parent directory permissions; such inherited permissions may
+prevent the security descriptor taken from the zip file from being applied
+to the new file.
+
+If directories exist which match directory/extract paths in the .zip file,
+file security is not updated on the target directory. It is assumed that if
+the target directory already exists, then appropriate security has already
+been applied to that directory.
+
+"unzip -t" will test the integrity of stored security descriptors when
+present and the operating system is Windows NT.
+
+ZipInfo (unzip -Z) will display information on stored security descriptor
+when "unzip -Zv" is specifed.
+
+
+Potential uses
+==============
+
+The obvious use for this new support is to better support backup and restore
+operations in a Windows NT environment where NTFS file security is utilized.
+This allows individuals and organizations to archive files in a portable
+fashion and transport these files across the organization.
+
+Another potential use of this support is setup and installation. This
+allows for distribution of Windows NT based applications that have preset
+security on files and directories. For example, prior to creation of the
+.zip file, the user can set file security via File Manager or Explorer on
+the files to be contained in the .zip file. In many cases, it is appropriate
+to only grant Everyone Read access to .exe and .dll files, while granting
+Administrators Full control. Using this support in conjunction with the
+unzipsfx.exe self-extractor stub can yield a useful and powerful way to
+install software with preset security (note that -X or -XX should be
+specified on the self-extractor commandline).
+
+When creating .zip files with security which are intended for transport
+across systems, it is important to take into account the relevance of
+access control entries and the associated Sid of each entry. For example,
+if a .zip file is created on a Windows NT workstation, and file security
+references local workstation user accounts (like an account named Fred),
+this access entry will not be relevant if the .zip file is transported to
+another machine. Where possible, take advantage of the built-in well-known
+groups, like Administrators, Everyone, Network, Guests, etc. These groups
+have the same meaning on any Windows NT machine. Note that the names of
+these groups may differ depending on the language of the installed Windows
+NT, but this isn't a problem since each name has well-known ID that, upon
+restore, translates to the correct group name regardless of locale.
+
+When access control entries contain Sid entries that reference Domain
+accounts, these entries will only be relevant on systems that recognize
+the referenced domain. Generally speaking, the only side effects of
+irrelevant access control entries is wasted space in the stored security
+descriptor and loss of complete intended access control. Such irrelevant
+access control entries will show up as "Account Unknown" when viewing file
+security with File Manager or Explorer.
diff --git a/proginfo/perform.dos b/proginfo/perform.dos
new file mode 100644
index 0000000..98744ee
--- /dev/null
+++ b/proginfo/perform.dos
@@ -0,0 +1,183 @@
+Date: Wed, 27 Mar 1996 01:31:50 CET +0100
+From: Christian Spieler (IKDA, THD, D-64289 Darmstadt)
+Subject: More detailed comparison of MSDOS Info-ZIP programs' performance
+
+Hello all,
+
+In response to some additional questions and requests concerning
+my previous message about DOS performance of 16/32-bit Info-ZIP programs,
+I have produced a more detailed comparison:
+
+System:
+Cx486DX-40, VL-bus, 8MB; IDE hard disk;
+DOS 6.2, HIMEM, EMM386 NOEMS NOVCPI, SMARTDRV 3MB, write back.
+
+I have used the main directory of UnZip 5.20p as source, including the
+objects and executable of an EMX compile for unzip.exe (to supply some
+binary test files).
+
+Tested programs were (my current updated sources!) Zip 2.0w and UnZip 5.20p
+- 16-bit MSC 5.1, compressed with LZEXE 0.91e
+- 32-bit Watcom C 10.5, as supplied by Kai Uwe Rommel (PMODE 1.22)
+- 32-bit EMX 0.9b
+- 32-bit DJGPP v2
+- 32-bit DJGPP v1.12m4
+
+The EMX and DJ1 (GO32) executables were bound with the full extender, to
+create standalone executables.
+
+A) Tests of Zip
+ Command : "<system>\zip.exe -q<#> tes.zip unz/*" (unz/*.* for Watcom!!)
+ where <#> was: 0, 1, 6, 9.
+ The test archive "tes.zip" was never deleted, this test
+ measured "time to update archive".
+
+ The following table contains average execution seconds (averaged over
+ at least 3 runs, with the first run discarted to fill disk cache);
+ numbers in parenteses specify the standard deviation of the last
+ digits.
+
+ cmpr level| 0 | 1 | 6 | 9
+ ===============================================================
+ EMX win95 | 7.77 | 7.97 | 12.82 | 22.31
+ ---------------------------------------------------------------
+ EMX | 7.15(40) | 8.00(6) | 12.52(25) | 20.93
+ DJ2 | 13.50(32) | 14.20(7) | 19.05 | 28.48(9)
+ DJ1 | 13.56(30) | 14.48(3) | 18.70 | 27.43(13)
+ WAT | 6.94(22) | 8.93 | 15.73(34) | 30.25(6)
+ MSC | 5.99(82) | 9.40(4) | 13.59(9) | 20.77(4)
+ ===============================================================
+
+ The "EMX win95" line was created for comparison, to check the performance
+ of emx 0.9 with the RSX extender in a DPMI environment. (This line was
+ produced by applying the "stubbed" EMX executable in a full screen DOS box.)
+
+
+B) Tests of UnZip
+ Commands : <system>\unzip.exe -qt tes.zip (testing performance)
+ <system>\unzip.exe -qo tes.zip -dtm (extracting performance)
+
+ The tes.zip archive created by maximum compression with the Zip test
+ was used as example archive. Contents (archive size was 347783 bytes):
+ 1028492 bytes uncompressed, 337235 bytes compressed, 67%, 85 files
+
+ The extraction directory tm was not deleted between the individual runs,
+ thus this measurement checks the "overwrite all" time.
+
+ | testing | extracting
+ ===================================================================
+ EMX | 1.98 | 6.43(8)
+ DJ2 | 2.09 | 11.85(39)
+ DJ1 | 2.09 | 7.46(9)
+ WAT | 2.42 | 7.10(27)
+ MSC | 4.94 | 9.57(31)
+
+Remarks:
+
+The executables compiled by me were generated with all "performance"
+options enabled (ASM_CRC, and ASMV for Zip), and with full crypt support.
+For DJ1 and DJ2, the GCC options were "-O2 -m486", for EMX "-O -m486".
+
+The Watcom UnZip was compiled with ASM_CRC code enabled as well,
+but the Watcom Zip example was made without any optional assembler code!
+
+
+
+Discussion of the results:
+
+In overall performance, the EMX executables clearly win.
+For UnZip, emx is by far the fastest program, and the Zip performance is
+comparable to the 16-bit "reference".
+
+Whenever "real" work including I/O is requested, the DJGPP versions
+lose badly because of poor I/O performance, this is the case especially
+for the "newer" DJGPP v2 !!!
+(I tried to tweak with the transfer buffer size, but without any success.)
+An interesting result is that DJ v1 UnZip works remarkably better than
+DJ v2 (in contrast to Zip, where both executables' performance is
+approximately equal).
+
+The Watcom C programs show a clear performance deficit in the "computational
+part" (Watcom C compiler produces code that is far from optimal), but
+the extender (which is mostly responsible for the I/O throughput) seems
+to be quite fast.
+
+The "natural" performance deficit of the 16-bit MSC code, which can be
+clearly seen in the "testing task" comparison for UnZip, is (mostly,
+for Zip more than) compensated by the better I/O throughput (due to the
+"direct interface" between "C RTL" and "DOS services", without any mode
+switching).
+
+But performance is only one aspect when choosing which compiler should
+be used for official distribution:
+
+Sizes of the executables:
+ | Zip || UnZip
+ | standalone stub || standalone | stub
+======================================================================
+EMX | 143,364 (1) | 94,212 || 159,748 (1) | 110,596
+DJ2 | 118,272 (2) | -- || 124,928 (2) | --
+DJ1 | 159,744 | 88,064 || 177,152 | 105,472
+WAT | 140,073 | -- || 116,231 | --
+MSC | 49,212 (3) | -- || 45,510 (3) | --
+
+(1) does not run in "DPMI only" environment (Windows DOS box)
+(2) requires externally supplied DPMI server
+(3) compressed with LZexe 0.91
+
+Caveats/Bugs/Problems of the different extenders:
+
+EMX:
+- requires two different extenders to run in all DOS-compatible environments,
+ EMX for "raw/himem/vcpi" and RSX for "dpmi" (Windows).
+- does not properly support time zones (no daylight savings time)
+
+DJv2:
+- requires an external (freely available) DPMI extender when run on plain
+ DOS; this extender cannot (currently ??) be bound into the executable.
+
+DJv1:
+- uses up large amount of "low" dos memory (below 1M) when spawning
+ another program, each instance of a DJv1 program requires its private
+ GO32 extender copy in low dos memory (may be problem for the zip
+ "-T" feature)
+
+Watcom/PMODE:
+- extended memory is allocated statically (default: ALL available memory)
+ This means that a spawned program does not get any extended memory.
+ You can work around this problem by setting a hard limit on the amount
+ of extended memory available to the PMODE program, but this limit is
+ "hard" and restricts the allocatable memory for the program itself.
+ In detail:
+ The Watcom zip.exe as distributed did not allow the "zip -T" feature;
+ there was no extended memory left to spawn unzip.
+ I could work around this problem by applying PMSETUP to change the
+ amount of allocated extended memory to 2.0 MByte (I had 4MB free extended
+ memory on my test system). But, this limit cannot be enlarged at
+ runtime, when zip needs more memory to store "header info" while
+ zipping up a huge drive, and on a system with less free memory, this
+ method is not applicable, either.
+
+Summary:
+
+For Zip:
+Use the 16-bit executable whenever possible (unless you need the
+larger memory capabilities when zipping up a huge amount of files)
+
+As 32-bit executable, we may distribute Watcom C (after we have confirmed
+that enabling ASMV and ASM_CRC give us some better computational
+performance.)
+The alternative for 32-bit remains DJGPP v1, which shows the least problems
+(to my knowledge); v2 and EMX cannot be used because of their lack of
+"universality".
+
+For UnZip:
+Here, the Watcom C 32-bit executable is probably the best compromise,
+but DJ v1 could be used as well.
+And, after all, the 16-bit version does not lose badly when doing
+"real" extraction! For the SFX stub, the 16-bit version remains first
+choice because of its much smaller size!
+
+Best regards
+
+Christian Spieler
diff --git a/proginfo/timezone.txt b/proginfo/timezone.txt
new file mode 100644
index 0000000..7868093
--- /dev/null
+++ b/proginfo/timezone.txt
@@ -0,0 +1,85 @@
+Timezone strings:
+-----------------
+This is a description of valid timezone strings for ENV[ARC]:TZ:
+"XPG3TZ - time zone information"
+The form of the time zone information is based on the XPG3 specification of
+the TZ environment variable. Spaces are allowed only in timezone
+designations, where they are significant. The following description
+closely follows the XPG3 specification, except for the paragraphs starting
+**CLARIFICATION**.
+
+<std><offset>[<dst>[<offset>],<start>[/<time>],<end>[/<time>]]
+
+Where:
+<std> and <dst>
+ Are each three or more bytes that are the designation for the
+ standard (<std>) and daylight savings time (<dst>) timezones.
+ Only <std> is required - if <dst> is missing, then daylight
+ savings time does not apply in this locale. Upper- and
+ lower-case letters are allowed. Any characters except a
+ leading colon (:), digits, a comma (,), a minus (-) or a plus
+ (+) are allowed.
+ **CLARIFICATION** The two-byte designation `UT' is permitted.
+<offset>
+ Indicates the value one must add to the local time to arrive
+ at Coordinated Universal Time. The offset has the form:
+ <hh>[:<mm>[:<ss>]]
+ The minutes <mm> and seconds <ss> are optional. The hour <hh>
+ is required and may be a single digit. The offset following
+ <std> is required. If no offset follows <dst>, daylight savings
+ time is assumed to be one hour ahead of standard time. One or
+ more digits may be used; the value is always interpreted as a
+ decimal number. The hour must be between 0 and 24, and the
+ minutes (and seconds) if present between 0 and 59. Out of
+ range values may cause unpredictable behavior. If preceded by
+ a `-', the timezone is east of the Prime Meridian; otherwise
+ it is west (which may be indicated by an optional preceding
+ `+' sign).
+ **CLARIFICATION** No more than two digits are allowed in any
+ of <hh>, <mm> or <ss>. Leading zeros are permitted.
+<start>/<time> and <end>/<time>
+ Indicates when to change to and back from daylight savings
+ time, where <start>/<time> describes when the change from
+ standard time to daylight savings time occurs, and
+ <end>/<time> describes when the change back happens. Each
+ <time> field describes when, in current local time, the change
+ is made.
+ **CLARIFICATION** It is recognized that in the Southern
+ hemisphere <start> will specify a date later than <end>.
+ The formats of <start> and <end> are one of the following:
+ J<n> The Julian day <n> (1 <= <n> <= 365). Leap days are not
+ counted. That is, in all years, February 28 is day 59
+ and March 1 is day 60. It is impossible to refer to
+ the occasional February 29.
+ <n> The zero-based Julian day (0 <= <n> <= 365). Leap days
+ are counted, and it is possible to refer to February
+ 29.
+ M<m>.<n>.<d>
+ The <d>th day, (0 <= <d> <= 6) of week <n> of month <m>
+ of the year (1 <= <n> <= 5, 1 <= <m> <= 12), where week
+ 5 means `the last <d>-day in month <m>' (which may
+ occur in either the fourth or the fifth week). Week 1
+ is the first week in which the <d>th day occurs. Day
+ zero is Sunday.
+ **CLARIFICATION** Neither <n> nor <m> may have a
+ leading zero. <d> must be a single digit.
+ **CLARIFICATION** The default <start> and <end> values
+ are from the first Sunday in April until the last Sunday
+ in October. This allows United States users to leave out
+ the <start> and <end> parts, as most are accustomed to
+ doing.
+ <time> has the same format as <offset> except that no leading
+ sign (`-' or `+') is allowed. The default, if <time> is not
+ given is 02:00:00.
+ **CLARIFICATION** The number of hours in <time> may be up
+ to 167, to allow encoding of rules such as `00:00hrs on the
+ Sunday after the second Friday in September'
+
+Example (for Central Europe):
+-----------------------------
+MET-1MEST,M3.5.0,M10.5.0/03
+
+Another example, for the US East Coast:
+---------------------------------------
+EST5EDT4,M4.1.0/02,M10.5.0/02
+This string describes the default values when no time zone is set.
diff --git a/proginfo/txtvsbin.txt b/proginfo/txtvsbin.txt
new file mode 100644
index 0000000..6ba2805
--- /dev/null
+++ b/proginfo/txtvsbin.txt
@@ -0,0 +1,112 @@
+A Fast Method of Identifying Plain Text Files
+=============================================
+
+
+Introduction
+------------
+
+Given a file coming from an unknown source, it is generally impossible
+to conclude automatically, and with 100% accuracy, whether that file is
+a plain text file, without performing a heavy-duty semantic analysis on
+the file contents. It is, however, possible to obtain a fairly high
+degree of accuracy, by employing various simple heuristics.
+
+Previous versions of the zip tools were using a crude detection scheme,
+originally used by PKWare in its PKZip programs: if more than 80% (4/5)
+of the bytes are within the range [7..127], the file is labeled as plain
+text, otherwise it is labeled as binary. A prominent limitation of this
+scheme is the restriction to Latin-based alphabets. Other alphabets,
+like Greek, Cyrillic or Asian, make extensive use of the bytes within
+the range [128..255], and texts using these alphabets are most often
+mis-identified by this scheme; in other words, the rate of false
+negatives is sometimes too high, which means that the recall is low.
+Another weakness of this scheme is a reduced precision, due to the false
+positives that may occur when binary files containing a large amount of
+textual characters are mis-identified as plain text.
+
+In this article we propose a new detection scheme, with a much increased
+accuracy and precision, and a near-100% recall. This scheme is designed
+to work on ASCII and ASCII-derived alphabets, and it handles single-byte
+alphabets (ISO-8859, OEM, KOI-8, etc.), and variable-sized alphabets
+(DBCS, UTF-8, etc.). However, it cannot handle fixed-sized, multi-byte
+alphabets (UCS-2, UCS-4), nor UTF-16. The principle used by this scheme
+can easily be adapted to non-ASCII alphabets like EBCDIC.
+
+
+The Algorithm
+-------------
+
+The algorithm works by dividing the set of bytes [0..255] into three
+categories:
+- The white list of textual bytecodes:
+ 9 (TAB), 10 (LF), 13 (CR), 20 (SPACE) to 255
+- The gray list of tolerated bytecodes:
+ 7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC)
+- The black list of undesired, non-textual bytecodes:
+ 0 (NUL) to 6, 14 to 31.
+
+If a file contains at least one byte that belongs to the white list, and
+no byte that belongs to the black list, then the file is categorized as
+plain text. Otherwise, it is categorized as binary.
+
+
+Rationale
+---------
+
+The idea behind this algorithm relies on two observations.
+
+The first observation is that, although the full range of 7-bit codes
+(0..127) is properly specified by the ASCII standard, most control
+characters in the range 0..31 are not used in practice. The only
+widely-used, almost universally-portable control codes are 9 (TAB),
+10 (LF), and 13 (CR). There are a few more control codes that are
+recognized on a reduced range of platforms and text viewers/editors:
+7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), and 27 (ESC); but these
+codes are rarely (if ever) used alone, without being accompanied by
+some printable text. Even the newer, portable text formats, such as
+XML, avoid using control characters outside the list mentioned here.
+
+The second observation is that most of the binary files tend to contain
+control characters, especially 0 (NUL); even though the older text
+detection schemes observe the presence of non-ASCII codes from the range
+[128..255], the precision rarely has to suffer if this upper range is
+labeled as textual, because the files that are genuinely binary tend to
+contain both control characters, and codes from the upper range. On the
+other hand, the upper range needs to be labeled as textual, because it
+is being used by virtually all ASCII extensions. In particular, this
+range is being heavily used to encode non-Latin scripts.
+
+Given the two observations, the plain text detection algorithm becomes
+straightforward. There must be at least some printable material, or
+some portable whitespace such as TAB, CR or LF, otherwise the file is
+not labeled as plain text. (The boundary case, when the file is empty,
+automatically falls into this category.) However, there must be no
+non-portable control characters, otherwise it's very likely that the
+intended reader of that file is a machine, rather than a human.
+
+Since there is no counting involved, other than simply observing the
+presence or the absence of some byte values, the algorithm produces
+uniform results on any particular text file, no matter what alphabet
+encoding is being used for that text. (In contrast, if counting were
+involved, it could be possible to obtain different results on a text
+encoded, say, using ISO-8859-2 versus UTF-8.) There is the category
+of plain text files that are "polluted" with one or a few black-listed
+codes, either by mistake, or by peculiar design considerations. In such
+cases, a scheme that tolerates a small percentage of black-listed codes
+would provide an increased recall (i.e. more true positives). This,
+however, incurs a reduced precision, since false positives are also more
+likely to appear in binary files that contain large chunks of textual
+data. "Polluted" plain text may, in fact, be regarded as binary, on
+which text conversions should not be performed. Under this premise, it
+is safe to say that the detection method provides a near-100% recall.
+
+Experiments have been run on a large set of files of various categories,
+including plain old texts, system logs, source code, formatted office
+documents, compiled object code, etcetera. The results confirm the
+optimistic assumptions about the high accuracy, precision and recall
+offered by this algorithm.
+
+
+--
+Cosmin Truta
+Last updated: 2005-Feb-27
diff --git a/proginfo/ziplimit.txt b/proginfo/ziplimit.txt
new file mode 100644
index 0000000..feacabb
--- /dev/null
+++ b/proginfo/ziplimit.txt
@@ -0,0 +1,243 @@
+ziplimit.txt
+
+Zip 3 and UnZip 6 now support many of the extended limits of Zip64.
+
+A) Hard limits of the Zip archive format:
+
+ Number of entries in Zip archive: 64 k (2^16 - 1 entries)
+ Compressed size of archive entry: 4 GByte (2^32 - 1 Bytes)
+ Uncompressed size of entry: 4 GByte (2^32 - 1 Bytes)
+ Size of single-volume Zip archive: 4 GByte (2^32 - 1 Bytes)
+ Per-volume size of multi-volume archives: 4 GByte (2^32 - 1 Bytes)
+ Number of parts for multi-volume archives: 64 k (1^16 - 1 parts)
+ Total size of multi-volume archive: 256 TByte (4G * 64k)
+
+ The number of archive entries and of multivolume parts are limited by
+ the structure of the "end-of-central-directory" record, where the these
+ numbers are stored in 2-Byte fields.
+ Some Zip and/or UnZip implementations (for example Info-ZIP's) allow
+ handling of archives with more than 64k entries. (The information
+ from "number of entries" field in the "end-of-central-directory" record
+ is not really neccessary to retrieve the contents of a Zip archive;
+ it should rather be used for consistency checks.)
+
+ Length of an archive entry name: 64 kByte (2^16 - 1)
+ Length of archive member comment: 64 kByte (2^16 - 1)
+ Total length of "extra field": 64 kByte (2^16 - 1)
+ Length of a single e.f. block: 64 kByte (2^16 - 1)
+ Length of archive comment: 64 KByte (2^16 - 1)
+
+ Additional limitation claimed by PKWARE:
+ Size of local-header structure (fixed fields of 30 Bytes + filename
+ local extra field): < 64 kByte
+ Size of central-directory structure (46 Bytes + filename +
+ central extra field + member comment): < 64 kByte
+
+ Note:
+ In 2001, PKWARE has published version 4.5 of the Zip format specification
+ (together with the release of PKZIP for Windows 4.5). This specification
+ defines new extra field blocks that allow to break the size limits of the
+ standard zipfile structures. In this extended Zip format, the size limits
+ of zip entries (and the complete zip archive) have been extended to
+ (2^64 - 1) Bytes and the maximum number of archive entries to (2^32-1).
+ Zip 3.0 supports these Zip64 extensions and should be released shortly.
+ UnZip 6.0 should support these standards.
+
+B) Implementation limits of UnZip:
+
+ Note:
+ This section should be updated when UnZip 6.0 is near release.
+
+ 1. Size limits caused by file I/O and decompression handling:
+ Size of Zip archive: 2 GByte (2^31 - 1 Bytes)
+ Compressed size of archive entry: 2 GByte (2^31 - 1 Bytes)
+
+ Note: On some systems, UnZip may support archive sizes up to 4 GByte.
+ To get this support, the target environment has to meet the following
+ requirements:
+ a) The compiler's intrinsic "long" data types must be able to hold
+ integer numbers of 2^32. In other words - the standard intrinsic
+ integer types "long" and "unsigned long" have to be wider than
+ 32 bit.
+ b) The system has to supply a C runtime library that is compatible
+ with the more-than-32-bit-wide "long int" type of condition a)
+ c) The standard file positioning functions fseek(), ftell() (and/or
+ the Unix style lseek() and tell() functions) have to be capable
+ to move to absolute file offsets of up to 4 GByte from the file
+ start.
+ On 32-bit CPU hardware, you generally cannot expect that a C compiler
+ provides a "long int" type that is wider than 32-bit. So, many of the
+ most popular systems (i386, PowerPC, 680x0, et. al) are out of luck.
+ You may find environment that provide all requirements on systems
+ with 64-bit CPU hardware. Examples might be Cray number crunchers
+ or Compaq (former DEC) Alpha AXP machines.
+
+ The number of Zip archive entries is unlimited. The "number-of-entries"
+ field of the "end-of-central-dir" record is checked against the "number
+ of entries found in the central directory" modulus 64k (2^16).
+
+ Multi-volume archive extraction is not supported.
+
+ Memory requirements are mostly independent of the archive size
+ and archive contents.
+ In general, UnZip needs a fixed amount of internal buffer space
+ plus the size to hold the complete information of the currently
+ processed entry's local header. Here, a large extra field
+ (could be up to 64 kByte) may exceed the available memory
+ for MSDOS 16-bit executables (when they were compiled in small
+ or medium memory model, with a fixed 64kByte limit on data space).
+
+ The other exception where memory requirements scale with "larger"
+ archives is the "restore directory attributes" feature. Here, the
+ directory attributes info for each restored directory has to be held
+ in memory until the whole archive has been processed. So, the amount
+ of memory needed to keep this info scales with the number of restored
+ directories and may cause memory problems when a lot of directories
+ are restored in a single run.
+
+C) Implementation limits of the Zip executables:
+
+ Note:
+ This section has been updated to reflect Zip 3.0.
+
+ 1. Size limits caused by file I/O and compression handling:
+ Without Zip64 extensions:
+ Size of Zip archive: 2 GByte (2^31 - 1 Bytes)
+ Compressed size of archive entry: 2 GByte (2^31 - 1 Bytes)
+ Uncompressed size of entry: 2 GByte (2^31 - 1 Bytes),
+ (could/should be 4 GBytes...)
+ Using Zip64 extensions:
+ Size of Zip archive: 2^63 - 1 Bytes
+ Compressed size of archive entry: 2^63 - 1 Bytes
+ Uncompressed size of entry: 2^63 - 1 Bytes
+
+ Multi-volume archive creation now supported in the form of split
+ archvies. Currently up to 99,999 splits are supported.
+
+ 2. Limits caused by handling of archive contents lists
+
+ 2.1. Number of archive entries (freshen, update, delete)
+ a) 16-bit executable: 64k (2^16 -1) or 32k (2^15 - 1),
+ (unsigned vs. signed type of size_t)
+ a1) 16-bit executable: <16k ((2^16)/4)
+ (The smaller limit a1) results from the array size limit of
+ the "qsort()" function.)
+
+ 32-bit executables: <1G ((2^32)/4)
+ (usual system limit of the "qsort()" function on 32-bit systems)
+
+ b) stack space needed by qsort to sort list of archive entries
+
+ NOTE: In the current executables, overflows of limits a) and b) are NOT
+ checked!
+
+ c) amount of free memory to hold "central directory information" of
+ all archive entries; one entry needs:
+ 96 bytes (32-bit) resp. 80 bytes (16-bit)
+ + 3 * length of entry name
+ + length of zip entry comment (when present)
+ + length of extra field(s) (when present, e.g.: UT needs 9 bytes)
+ + some bytes for book-keeping of memory allocation
+
+ Conclusion:
+ For systems with limited memory space (MSDOS, small AMIGAs, other
+ environments without virtual memory), the number of archive entries
+ is most often limited by condition c).
+ For example, with approx. 100 kBytes of free memory after loading and
+ initializing the program, a 16-bit DOS Zip cannot process more than 600
+ to 1000 (+) archive entries. (For the 16-bit Windows DLL or the 16-bit
+ OS/2 port, limit c) is less important because Windows or OS/2 executables
+ are not restricted to the 1024k area of real mode memory. These 16-bit
+ ports are limited by conditions a1) and b), say: at maximum approx.
+ 16000 entries!)
+
+
+ 2.2. Number of "new" entries (add operation)
+ In addition to the restrictions above (2.1.), the following limits
+ caused by the handling of the "new files" list apply:
+
+ a) 16-bit executable: <16k ((2^64)/4)
+
+ b) stack size required for "qsort" operation on "new entries" list.
+
+ NOTE: In the current executables, the overflow checks for these limits
+ are missing!
+
+ c) amount of free memory to hold the directory info list for new entries;
+ one entry needs:
+ 24 bytes (32-bit) resp. 22 bytes (16-bit)
+ + 3 * length of filename
+
+ NOTE: For larger systems, the actual limits may be more performance
+ issues (how long you want to wait) rather than available memory and other
+ resources.
+
+D) Some technical remarks:
+
+ 1. For executables compiled without LARGE_FILE_SUPPORT and ZIP64_SUPPORT
+ enabled, the 2GByte size limit on archive files is a consequence of
+ the portable C implementation of the Info-ZIP programs. Zip archive
+ processing requires random access to the archive file for jumping
+ between different parts of the archive's structure. In standard C,
+ this is done via stdio functions fseek()/ftell() resp. unix-io functions
+ lseek()/tell(). In many (most?) C implementations, these functions use
+ "signed long" variables to hold offset pointers into sequential files.
+ In most cases, this is a signed 32-bit number, which is limited to
+ ca. 2E+09. There may be specific C runtime library implementations
+ that interpret the offset numbers as unsigned, but for us, this is not
+ reliable in the context of portable programming.
+
+ If LARGE_FILE_SUPPORT and ZIP64_SUPPORT are defined and supported by
+ the system, 64-bit off_t file offsets are supported and the above
+ larger limits are supported. As off_t is signed, the maximum offset
+ is usually limited to 2^63 - 1.
+
+ 2. The 2GByte limit on the size of a single compressed archive member
+ is again a consequence of the implementation in C.
+ The variables used internally to count the size of the compressed
+ data stream are of type "long", which is guaranted to be at least
+ 32-bit wide on all supported environments.
+
+ But, why do we use "signed" long and not "unsigned long"?
+
+ Throughout the I/O handling of the compressed data stream, the
+ sign bit of the "long" numbers is (mis-)used as a kind of overflow
+ detection. In the end, this is caused by the fact that standard C
+ lacks any overflow checking on integer arithmetics and does not
+ support access to the underlying hardware's overflow detection
+ (the status bits, especially "carry" and "overflow" of the CPU's
+ flags-register) in a system-independent manner.
+
+ So, we "misuse" the most-significant bit of the compressed data
+ size counters as carry bit for efficient overflow/underflow detection.
+ We could change the code to a different method of overflow detection,
+ by using a bunch of "sanity" comparisons (kind of "is the calculated
+ result plausible when compared with the operands"). But, this would
+ "blow up" the code of the "inner loop", with remarkable loss of
+ processing speed. Or, we could reduce the amount of consistency checks
+ of the compressed data (e.g. detection of premature end of stream) to
+ an absolute minimum, at the cost of the programs' stability when
+ processing corrupted data.
+
+ Summary: Changing the compression/decompression core routines to
+ be "unsigned safe" would require excessive recoding, with little
+ gain on maximum processable uncompressed size (a gain can only be
+ expected for hardly compressable data), but at severe costs on
+ performance, stability and maintainability. Therefore, it is
+ quite unlikely that this will ever happen for Zip/UnZip.
+
+ With LARGE_FILE_SUPPORT and ZIP64_SUPPORT enabled and supported,
+ the above arguments still apply, but the limits are based on 64 bits
+ instead of 32 and should allow most large files and archives to be
+ processed.
+
+ Anyway, the Zip archive format is more and more showing its age...
+ The effort to lift the 2GByte limits should be better invested in
+ creating a successor for the Zip archive format and tools. But given
+ the latest improvements to the format and the wide acceptance of zip
+ files, the format will probably be around for awhile more.
+
+Please report any problems using the web contact form at: www.Info-ZIP.org
+
+Last updated: 26 January 2002, Christian Spieler
+ 25 May 2008, Ed Gordon
diff --git a/qdos/IZREADME.SMS b/qdos/IZREADME.SMS
new file mode 100644
index 0000000..9ad1503
--- /dev/null
+++ b/qdos/IZREADME.SMS
@@ -0,0 +1,600 @@
+IZREADME_SMS (IZREADME.SMS): Info-ZIP for SMS/QDOS, last revised: 15-Jun-1998
+===============================================================================
+[was "InfoZIP_SMSQDOS_ReadMe" in J. Hudson's original ports, ca. 08/1995]
+
+Info-ZIP Programs
+=================
+
+Zip
+UnZip
+UnZipSFX
+fUnZip
+
+Introduction
+------------
+
+This archive is a result of frustrations with contemporary (August 95)
+versions of Zip and UnZip. While they use the same compression
+algorithms as the Info-ZIP programs, there the compatibility ends. If
+you just use Zip/UnZip only on SMS/QDOS, then perhaps this is not a
+problem (but I know for some users it still is); if you use Zip/UnZip
+to transport source code and data between diverse systems, then the
+disregard for Info-ZIP standards is inconvenient, particularly the
+fact that directories are not supported and files are always stored
+underscored.
+
+This release of Zip/UnZip offers:
+
+ o zipfile/directory compatibility with all other supported
+ platforms
+
+ o SMS/QDOS compatibility and back-compatible with earlier
+ versions.
+
+ o Improved performance (Zip is typically 50% faster)
+
+ o Command-line compatibility with Info-ZIP
+
+ o Self-extracting archives (but not very elegantly)
+
+ o Archives are marked as 'created by SMS/QDOS'.
+
+ o Optional recursion into directories
+
+ o Directory structure restored on unzip of Info-ZIP/PKZIP-
+ compatible archives.
+
+ o Config'urable for listing and unpack formats (Info-ZIP (.) or
+ SMS/QDOS (_) and 'Press any key' timeouts. Override options
+ from command line.
+
+Info-ZIP Standards
+------------------
+
+This (rather long-winded and waffling) section discusses the
+conventions and standards used by Info-ZIP-compatible archivers and how
+"Info-ZIP for SMS/QDOS" achieves compatibility.
+
+Info-ZIP Zip/UnZip on all supported platforms (Unix, DOS, OS/2, NT,
+VAX/VMS, Amiga etc etc), works in a specific way. (Until now SMS/QDOS
+was neither 'supported' nor Info-ZIP-compliant.)
+
+ a. The zipfile directory is in (/.) (Unix) format.
+
+ b. When zips are listed, it is in 'zipfile' (Unix) format.
+
+ c. When files are added, they are defined in native format.
+
+ d. When files are added, this is shown in 'zipfile' format.
+
+ e. When files are unpacked, this is done to native format, but
+ selection is done in 'zipfile' format.
+
+Basically, the listing and stored format of a file is that of the
+destination.
+
+So, given a file structure at some arbitrary 'root' level.
+
+ Makefile
+ src (Dir)
+ afile.c
+ bfile.c
+ docs (Dir)
+ prog.txt
+ hdr (Dir)
+ cfile.h
+ dfile.h
+
+Then these would be in Unix (and Amiga) as
+
+ Makefile
+ src/afile.c
+ src/bfile.c
+ src/docs/prog.txt
+ hdr/cfile.h
+ hdr/dfile.h
+
+This is also how the zipfile directory appears.
+
+And in DOS/OS2/NT
+
+ Makefile
+ src\afile.c
+ src\docs\prog.txt
+ hdr\cfile.h .. etc
+
+And in VMS (we SHOUT in VMS and have a silly file system)
+
+ MAKEFILE
+ [SRC]AFILE.C
+ [SRC.DOC]PROG.TXT
+ [HDR]CFILE.H .. etc
+ (OK VMS purist, [.SRC] etc. Only an example)
+
+And in SMS/QDOS (quiet again, but slightly ludicrous !)
+
+ Makefile
+ src_afile_c
+ src_doc_prog_txt
+ hdr_cfile_h .. etc
+
+The main problem regarding SMS/QDOS is not that of extensions - (after
+all, only VMS and DOS _really_ have extensions; Unix, AmigaDOS, NT and
+OS/2 (and Win95) allow multiple '.' in.long.file.names.
+
+The SMS/QDOS problem is that '_' is both a legal file name character
+and a directory separator. This creates the difficulties, as
+directories and files are somewhat different objects.
+
+It is the intention that these versions of SMS/QDOS Zip/UnZip will
+follow the Info-ZIP rules, thus providing compatibility with the other
+platforms. It is possible to zip the file structure described above on
+SMS/QDOS and unpack it on VMS and get the VMS structure as shown in the
+example (and vice-versa). [We only choose the most obtuse file
+systems for the examples].
+
+In order to achieve this, SMS/QDOS names are mapped into Unix-style
+ones when the zipfile is created and un-mapped when it is unpacked.
+There is an option to unpack in 'zipfile' format (i.e. with '.' rather
+than '_'), but there will be no option to pack to all '_'. That would
+contravene the standard. However, a file
+
+ src_split_name_c (which is src->split_name_c !)
+ src/split_name.c)
+
+where src is a hard directory, would be stored in the zip directory as
+
+ src/split_name.c
+
+It does handle '_' with a little intelligence.
+
+The default UnZip option will be to translate '.' to '_'; this is
+because there are still many QDOS/Minerva users that cannot handle '.'
+without quotes, which is immensely inconvenient. For many SMS users
+'_' is also the most natural and convenient option. It also means that
+SMS/QDOS <-> SMS/QDOS Zip - UnZip sequences are transparent.
+
+There will, however, be two ways around this in UnZip.
+
+ 1. It is possible to Config the UnZip default to be '.'
+ translations (or not).
+
+ 2. The UnZip -Q1 option will toggle the default (Config'ed)
+ state.
+
+Examples:
+
+Given that we want/have
+
+ Makefile (Makefile)
+ src/afile.c (src_afile_c)
+ src/bfile.c (src_bfile_c)
+ src/docs/prog.txt (src_docs_prog_txt)
+ hdr/cfile.h (hdr_cfile_h)
+ hdr/dfile.h (hdr_dfile_h)
+
+Then on SMS/QDOS we might have added the *.c files as
+
+ ex zip;'-r test *_c'
+
+(or VMS, just to do something different)
+
+ zip -r test [.src]*.c
+
+In both cases the file lists as above (left).
+
+To unpack on SMS/QDOS (just the _c/.c files)
+
+ ex unzip;'test src/*.c'
+
+ (and VMS, unzip test src/*.c)
+
+i.e. in both cases using the 'zipfile' format. As a concession to
+SMS/QDOS, you could also have:
+
+ ex unzip;'test src_*_c'
+
+ but not unzip test [.src]*.c on VMS !!!!! Sorry, dinosaurs.
+
+Both SMS/QDOS commands unpack to
+
+ src_afile_c etc, where src_ is a hard sub-directory.
+
+(and the VMS example would unpack to [.src]afile.c, (or to src\afile.c on
+DOS/NT/OS2 etc).
+
+Options & SMS/QDOS Features
+---------------------------
+
+The options supported by Zip/UnZip are basically those documented in
+the Info-ZIP documents and shown in on-line 'usage'. In particular, -r
+and -j work as intended.
+
+PLEASE NOTE: Previous SMS/QDOS zip/unzips have NOT followed these
+conventions, for example -r was not implemented and -j was reversed.
+
+A number of -Q (SMS/QDOS-specific) options (not yet in the current
+documents or usage screens) are implemented.
+
+The Zip 2.0.1 (and later) default is to add SMS/QDOS headers where
+file type = 1 (exe) or 2 (rel) or (type > 0 && != 255 and (filesize %
+64) != 0). Directories are included anyway, unless you zip -D.
+
+Where a header is added for an 'exe' file a '*' is displayed after the
+name in the zip display (and '#' for 'rel' files).
+
+The -Q options for Zip are:
+
+ -Q1 Don't add headers for ANY files
+ -Q2 Add headers for all files
+ -Q4 Don't wait for interactive key press
+
+ (additive, so -Q5 => no headers, no wait, -Q6 all headers,
+ no wait etc)
+
+ (the default is exec/rel headers, 5 sec wait)
+
+Zip has rationalised the file header storage in zipfiles. The
+previous Zip used to store a QDOS header for each file. This was very
+wasteful, for example compressing a SMS/QDOS release of PGP in this
+way came to 730Kb, too large for a DD disk. Changing the Zip program
+just to add a header record for the single PGP exe and the zipfile
+size went down to around 690Kb.
+
+And for UnZip
+
+ -Q1 Toggle unpack format status ('.' <-> '_')
+ -Q2 Toggle listing format
+ -Q4 Don't wait for key press
+
+Files Types
+-----------
+
+The history of QDOS suffers from incompatible feature
+implementations. For example, Thor directories have file type 3, CST
+have type 4 and Level 2 have type 255. Some software writers (both
+amateur and otherwise) have used type 3 or 4 for other purposes
+(backward compatibility ?? who cares ??).
+
+In order to bypass problems cause by incompatible (inconsiderate ?)
+usage of file types, the file type denoting a directory is a
+Config'urable item. The default is set to -1 (65535 in Config terms),
+which means "determine directory type from the file header of the root
+directory". If this is appears unsuccessful on your system, the value
+can be Config'ed in the range 3-255.
+
+Zip assumes a file is a directory if:
+
+ ((type == CONFIGed_type) && (file_size % 64) == 0)
+
+If you are unfortunate enough have files of that pass this test but
+are not directories, then Zip will loop endless, as SMS/QDOS opens the
+root directory again !!! (recursion: see recursion etc).
+
+I suggest you refrain from zipping such files and contact the software
+supplier and point out the error of their ways.
+
+File Naming Issues
+------------------
+
+Zip will append a '_zip' suffix to the archive filename when the
+supplied name (i.e. excluding device/directory parts) does not
+contain a '_' or a '.'. This is broadly compatible with Info-ZIP,
+taking into account the '_' aberation.
+
+So
+ ex zip;'ram2_test ...' >> ram2_test_zip
+
+ ex zip;'ram2_test.zip ...' >> ram2_test.zip
+
+ ex zip;'ram2_test_rep ... ' >> ram2_test_rep
+
+ ex zip;'ram2_fdbbs.rep ... ' >> ram2_fdbbs.rep
+
+ ex zip;'ram2_test_rep.zip ...' >> ram2_test_rep.zip
+
+This implies that if a file ram2_test.zip exists, and you do:
+
+ ex zip;'ram2_test ...'
+
+Then a new file (test_zip) is created, rather than 'test.zip' being
+updated.
+
+Zip supports extensive recursive wild-carding, again the fact that '_'
+can be a directory separator as well as part of a file name makes this
+a bit tricky, but given the example:
+
+ test1_bas
+ test2_bas
+ dir1->demo1_bas where -> indicates a sub dir
+ dir2->demo2_bas
+
+ ex zip;'ram2_test *_bas'
+ just finds test1_bas, test2_bas
+
+ ex zip;'-r ram2_test *_bas'
+ recurses and finds all the files
+
+You might think that
+
+ ex zip;'-r ram2_test *_*_bas'
+
+would just find the files in the subdirectories--well yes, but it will
+also find very other sub-dir'ed _bas file on the disk too. This is
+a feature.
+
+The pattern matching supports Unix-style 'regex' so you could:
+
+ ex zip;'ram2_test dir?_*_bas'
+ or
+ ex zip;'ram2_test dir[12]_*_bas
+
+
+UnZip has now got a fixed -d option. This is used to specify the
+directory to unpack the zipfile into, it must follow immediately
+after the zip name.
+
+ ex unzip;'ram2_test_zip -d ram3_ *_txt'
+
+would unpack all *_txt files to ram3_ .
+
+It is not necessary to set the default directory to pack files, Zip
+will remove any device names (and store any hard directory names,
+unless you zip -j).
+
+ ex zip;'ram1_test flp1_*'
+
+ ----->
+ adding: file.dat (deflated 50%)
+ adding: menu.rext # (deflated xx%)
+ adding: zip * (deflated yy%)
+ adding: hard_one (stored 0%)
+ adding: hard_one/stuff.bas (deflated ...)
+
+Due to the way the file-mapping is implemented, it is not supported
+over the nX_ type network device.
+
+Config Options
+--------------
+
+A limited number of SMS/QDOS specific functions can be set using the
+QJump Config program.
+
+ For Zip:
+
+ Timeout for interactive 'Press any key' prompt
+
+ 65535 Wait forever (aka -1)
+ 0 No wait
+ n (1-32767) Wait for 'n' clocks (1/50 sec)
+
+ Other values are unsupported. Note Config works on 'unsigned'
+ integer values (at least according to my manual).
+
+ Directory file type key.
+
+ Config will accept any value in the range 3-255, known useful
+ values are 3 (Thor), 4 (CST) and 255 (Level 2 devices). A value
+ of 65535 (aka -1) means "determine from device info".
+
+ For UnZip:
+
+ Timeout as above
+
+ Unpack mode (SMS/QOS ('_') or Info-ZIP ('.')
+
+ List format (Info-ZIP ('.') or SMS/QDOS ('_')
+
+
+When the 'Press a key' text is displayed, if you press ESC, then it
+waits until you press any other key, infinite timeout. This may be
+useful if you want (much) more time to study a listing etc.
+
+Defaults for timeout and directory type are 250 and -1 respectively.
+
+More Goodies
+------------
+
+Part of the Zip compression code is now in assembler; it runs
+noticably faster than the previous version. Compressing some arbitrary
+files with the previous Zip it took 251 seconds, with Zip 2.0.1 it
+took (a mere) 170 seconds (68008 QL).
+
+More good news is that SMS/QDOS is just another system option on top
+of standard Info-ZIP, unlike the previous ports that were much more
+SMS/QDOS specific. For example, compiling the standard source with c68
+(i.e. #define QDOS), then you get an SMS/QDOS version.
+
+Compile with Linux/gcc and get the standard Linux version. Now, here's
+the cool bit; compile with Linux/gcc and "-DQLZIP", and get a standard
+Linux Zip/UnZip with SMS/QDOS (header) extensions.
+
+so, on Linux:
+
+ zip -Q stuff.zip qtpi zip unzip
+
+the -Q tells Zip to look for XTc68/Lux68 cross-compiler data size
+blocks and produce a zipfile with SMS/QDOS headers in it (for exec
+type programs). This works for exec files produced by the XTc68/Lux68
+cross compilers and ANY SMS/QDOS files copied to a Unix or MS-DOS disk
+from an SMS/QDOS floppy using 'qltools v2.2' (or later).
+
+Self Extracting Archives
+------------------------
+
+Info-ZIP self-extracting archives (_sfx) are created in a rather
+'brute-force' way. The UnZipSFX program is prepended to a zipfile.
+
+i.e. file_sfx = unzipsfx + file_zip
+ ex file_sfx
+
+Although the UnZipSFX program is a cut-down UnZip, it is still around
+30Kb - 50Kb, depending on platform.
+
+The success of this approach depends on how the operating system
+loader loads executable files. On most systems where the loader only
+loads the actual program part (Unix, VMS, DOS et al), the this is
+quite efficient; if you make, say, a 4Mb zipfile and prepend a 30Kb
+UnZipSFX image, then the system only loads the 30Kb program and the
+process is efficient as the zipped data part is still unpacked from
+disk. These systems also supply the running UnZipSFX program stub with
+the path name of the file it was loaded from, so the program knows
+what it has to unpack (so on Linux, for example):
+
+ cat /usr/bin/unzipsfx test.zip > test.sfx # concatenate the files
+ chmod 755 test.sfx # make executable
+ test.sfx # to extract, it
+ # 'knows' it is "test.sfx"
+
+Unfortunately, the more simplistic nature of SMS/QDOS makes this much
+more difficult and rather less efficient as: (see note 1)
+
+ a. The SMS/QDOS 'loader' loads the whole file into memory.
+
+ b. The SMS/DOS 'loader'/c68 run-time system does not return the
+ name of the file from which it was loaded.
+
+ c. You cannot so easily create a image file by concatenating two
+ files, it is also necessary to ensure the executable file
+ header is set correctly.
+
+ d. The show stopper. The data space required for the
+ self-extracting archive is required, as not easily maintained
+ during electronic transfer.
+
+
+If anyone is still interested, then the following support for UnZipSFX
+is provided.
+
+ o A program 'makesfx' will combine a stub (callstub), UnZipSFX image
+ and a zipfile to produce a sfx (self-extracting zip) file.
+
+ o A callable interface is supplied. The user calls the SFX file,
+ which creates the files necessary to do the extraction.
+
+The makesfx program concatenates the supplied files to standard
+output.
+
+So, to create a sfx of all the _c files in the default directory.
+
+ # 1st create a zipfile of the required files
+
+ ex zip;'ram1_test_zip *_c'
+
+ # Now create the sfx file (ram2_test_sfx)
+ # our UnZipSFX image is in 'win1_bin'
+ # as is the call stub.
+
+ex makesfx;'-o test_sfx -x win1_bin_unzipsfx -s win1_bin_callstub -z ram1_test_zip'
+
+The arguments to makesfx are:
+
+ -s stubfile
+ -x UnZipSFX_program
+ -z Zip_file
+ -o Output_file
+
+You can now unpack the _sfx file on any SMS/QDOS-compatible
+system.
+
+ f$ = "win2_tmp_test_sfx"
+ a = alchp(flen(\f$))
+ lbytes f$,a
+ call a
+ rechp(a)
+
+ZipInfo
+-------
+
+Given the above note concerning SMS/QDOS programs not knowing the name
+by which the program was invoked, then the usual symbolic-link-of-unzip-
+to-zipinfo trick is unavailable (presupposing there is some some SMS/QDOS
+trick to emulate symbolic links).
+
+ZipInfo functionality is only available via 'unzip -Z'. There is no
+separate ZipInfo program.
+
+Caveat ATP Users
+----------------
+
+ATP for SMS/QDOS users should pay particular attention to the
+Zip/UnZip options in their atprc and compare with Info-ZIP Zip/UnZip
+usage. Older versions of Zip/UnZip screwed up -j.
+
+
+ zip -jk
+ unzip -jo
+
+Distribution & Copyright
+------------------------
+
+This software is written by and largely copyrighted by the 'Info-ZIP'
+group whose members are noted in the accompanying documentation. This
+particular SMS/QDOS port plus 'makesfx' was written by, but is not
+copyrighted by, Jonathan R Hudson. The SMS/QDOS code in this release
+is written from scratch and is not dependent on previous SMS/QDOS
+releases, but is (largely) compatible.
+
+As a courtesy to the authors of this package, please ensure that the
+documentation is supplied when it is re-distributed.
+
+In particular, if this archive is split into Zip and UnZip components,
+ensure that this document ("IZREADME_SMS") is supplied in
+each component.
+
+SMS/QDOS version by:
+Jonathan R Hudson (jrhudson@bigfoot.com)
+
+I am grateful to Graham Goodwin for finding some most imaginative
+means of breaking the beta code.
+
+I'd also like to thank Thierry Godefroy for providing the 2.1/5.2
+source code and making the initial contact with the Info-ZIP group.
+
+And of course, many, many thanks to the Info-ZIP workers for making
+this code freely available.
+
+Note 1
+------
+
+The 'C' language FAQ ('frequently asked questions' [comp.lang.c])
+notes on the matter of obtaining the load file name of a 'C' program:
+
+16.5: How can my program discover the complete pathname to the
+ executable file from which it was invoked?
+
+A: argv[0] may contain all or part of the pathname, or it may
+ contain nothing. You may be able to duplicate the command
+ language interpreter's search path logic to locate the
+ executable if the name in argv[0] is present but incomplete.
+ However, there is no guaranteed or portable solution.
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Note 2
+------
+
+NUL files for SMS2. There appears to be a conflict between SMS2/LBASIC
+compiled programs and c68 programs using nul as stdin.
+
+ EW zip,nul;'ram1_test *_bas' # will not work
+
+ # This does work !
+ EW zip,#FOP_IN('nul');'ram2_test *_bas' : CLOSE
+
+Note 3
+------
+
+version number incremented to 2.0.1a and 5.12a to accomodate Erling
+Jacobsen's exit message requirements
+
+version number incremented to Zip 2.0.1b to fix bug on zipping files
+starting with leading underscore.
+
+version number incremented to UnZip 5.12b to fix UnZip problem on
+files zipped with leading './', and linked with revised (fixed) c68
+'utime' function (could corrupt level 1 files). (source code _only_ as
+IZQ004.zip).
+
+Ported Zip 2.1 and UnZip 5.2 (July 1996). Released as INZIP005.zip
+
+All later versions --- see Info-ZIP release notes and documentation.
diff --git a/qdos/Makefile.qdos b/qdos/Makefile.qdos
new file mode 100644
index 0000000..df68aad
--- /dev/null
+++ b/qdos/Makefile.qdos
@@ -0,0 +1,145 @@
+include /etc/ql.mak
+
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+MAKE = make
+SHELL = /bin/sh
+
+#
+BIND = $(CC)
+
+# probably can change this to 'install' if you have it
+INSTALL = cp
+
+# target directories - where to install executables and man pages to
+BINDIR =
+manext=1
+MANDIR =
+ZIPMANUAL = MANUAL
+
+# flags
+# CFLAGS flags for C compile
+# LFLAGS1 flags after output file spec, before obj file list
+# LFLAGS2 flags after obj file list (libraries, etc)
+CFLAGS = -O -DASMV -DASM_CRC
+LFLAGS1 = -v
+#LFLAGS2 = -lutime
+
+all: zip
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o qdos.o ttyio.o
+OBJI = deflate.o trees.o qfileio.o crc32.o
+OBJA = config.o crc68.o match.o
+# crc32.o
+OBJQ = qdos_.o config.o qfileio_.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o $(OBJQ)
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o
+OBJS = zipsplit.o $(OBJU)
+
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+ rm -f $*_.c; ln $< $*_.c
+ $(CC) $(CFLAGS) -DUTIL -c $*_.c
+ rm -f $*_.c
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+.1.doc:
+ nroff -man $< | col -b | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and zip.doc.
+$(OBJZ): zip.h ziperr.h tailor.h
+$(OBJI): zip.h ziperr.h tailor.h
+$(OBJN): zip.h ziperr.h tailor.h
+$(OBJS): zip.h ziperr.h tailor.h
+$(OBJC): zip.h ziperr.h tailor.h
+zip.o zipup.o crc32.o crypt.o fileio.o zipfile.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o zipup_.o zipcloak.o crypt_.o: crypt.h
+
+qfileio.o: qdos/qfileio.c
+ cp qdos/qfileio.c qfileio.c
+ $(CC) $(CFLAGS) -c qfileio.c
+ rm -f qfileio.c
+
+qfileio_.o: qdos/qfileio.c
+ cp qdos/qfileio.c qfileio_.c
+ $(CC) $(CFLAGS) -DUTIL -c qfileio_.c
+ rm -f qfileio_.c
+
+match.o: qdos/match.s
+ cp qdos/match.s ./_match.s
+ $(AS) _match.s -o match.o
+ rm -f _match.s
+
+crc68.o: qdos/crc68.s
+ cp qdos/crc68.s ./crc68.s
+ $(AS) crc68.s -o crc68.o
+ rm -f crc68.s
+
+config.o: qdos/config.s
+ cp qdos/config.s ./config.x
+ $(CC) -c -DZIP config.x -o config.o
+ rm -f config.x
+
+ZIPS = zip$E zipnote$E zipsplit$E zipcloak$E
+
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+qdos.o: qdos/qdos.c
+ cp qdos/qdos.c .
+ $(CC) -c -oqdos.o qdos.c
+ rm -f qdos.c
+
+qdos_.o: qdos/qdos.c
+ cp qdos/qdos.c ./qdos_.c
+ $(CC) -DUTIL -c -oqdos_.o qdos_.c
+ rm -f qdos_.c
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA)
+ $(BIND) -o zip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+ $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC)
+ $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+ $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+ nroff -man man/zip.1 | col -b | uniq > $(ZIPMANUAL)
+
+# install
+install: $(ZIPS)
+ $(INSTALL) $(ZIPS) $(BINDIR)
+ $(INSTALL) man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+ -cd $(BINDIR); rm -f $(ZIPS)
+ -cd $(MANDIR); rm -f zip.$(manext)
+
+flags: configure
+ sh configure flags
+
+# These symbols, when #defined using -D have these effects on compilation:
+# ZMEM - includes C language versions of memset(), memcpy(), and
+# memcmp() (util.c).
+# SYSV - use <sys/dirent.h> and the library opendir()
+# DIRENT - use <sys/dirent.h> and getdents() instead of <sys/dir.h>
+# and opendir(), etc. (fileio.c).
+# NODIR - used for 3B1, which has neither getdents() nor opendir().
+# NDIR - use "ndir.h" instead of <sys/dir.h> (fileio.c).
+# UTIL - select routines for utilities (note, cloak, and split).
+# PROTO - enable function prototypes.
+# RMDIR - remove directories using a system("rmdir ...") call.
+# CONVEX - for Convex make target.
+# AIX - for AIX make target.
+# LINUX - for linux make target.
+
+# end of Makefile
diff --git a/qdos/Makefile.qlzip b/qdos/Makefile.qlzip
new file mode 100644
index 0000000..d69009a
--- /dev/null
+++ b/qdos/Makefile.qlzip
@@ -0,0 +1,141 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# what you can make ...
+all: zip
+
+#MAKE = make -f unix/Makefile
+SHELL = /bin/sh
+
+# (to use the Gnu compiler, change cc to gcc in CC and BIND)
+CC = cc
+BIND = $(CC)
+AS = $(CC) -c
+E =
+CPP = /lib/cpp
+
+# probably can change this to 'install' if you have it
+INSTALL = cp
+
+# target directories - where to install executables and man pages to
+prefix = /usr/local
+BINDIR = $(prefix)/bin
+manext=1
+MANDIR = $(prefix)/man/man$(manext)
+ZIPMANUAL = MANUAL
+
+# flags
+# CFLAGS flags for C compile
+# LFLAGS1 flags after output file spec, before obj file list
+# LFLAGS2 flags after obj file list (libraries, etc)
+CFLAGS = -O2 -fno-strength-reduce -I. -DUNIX -DQLZIP -DASM_CRC
+LFLAGS1 =
+LFLAGS2 = -s
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+ unix.o crc_gcc.o crc32.o qdos.o
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o unix_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h unix/osdep.h
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+ rm -f $*_.c; ln $< $*_.c
+ $(CC) -c $(CFLAGS) -DUTIL $*_.c
+ rm -f $*_.c
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+ nroff -man $< | col -b | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUAL.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o zipup.o crypt.o fileio.o zipfile.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: unix/zipup.h
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(AS) _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+unix.o: unix/unix.c
+ $(CC) -c $(CFLAGS) unix/unix.c
+
+unix_.o: unix/unix.c
+ rm -f $*_.c; ln unix/unix.c $*_.c
+ $(CC) -c $(CFLAGS) -DUTIL $*_.c
+ rm -f $*_.c
+
+qdos.o: qdos/qdos.c
+ $(CC) -c $(CFLAGS) qdos/qdos.c
+
+crc_gcc.o: crc_i386.S # 32bit, GNU AS
+ gcc -O3 -I. -DASM_CRC -Di386 -x assembler-with-cpp -c -o $@ crc_i386.S
+
+ZIPS = zip$E zipnote$E zipsplit$E zipcloak$E
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUAL)
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA)
+ $(BIND) -o qlzip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+ $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC)
+ $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+ $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+ nroff -man man/zip.1 | col -b | uniq > $(ZIPMANUAL)
+
+# install
+install: $(ZIPS)
+ $(INSTALL) $(ZIPS) $(BINDIR)
+ $(INSTALL) man/zip.1 $(MANDIR)/zip.$(manext)
+
+uninstall:
+ -cd $(BINDIR); rm -f $(ZIPS)
+ -cd $(MANDIR); rm -f zip.$(manext)
+
+dist:
+ zip -u9T zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+ -e s/[.]//g -e q revision.h` \
+ `awk '/^Makefile/,/vms_zip.rnh/ {print $$1}' < contents`
+
+flags: unix/configure
+ sh unix/configure "${CC}" "${CFLAGS}"
+
+# These symbols, when #defined using -D have these effects on compilation:
+# ZMEM - includes C language versions of memset(), memcpy(),
+# and memcmp() (util.c).
+# HAVE_DIRENT_H - use <dirent.h> instead of <sys/dir.h>
+# NODIR - for 3B1, which has neither getdents() nor opendir().
+# HAVE_NDIR_H - use <ndir.h> (unix/unix.c).
+# HAVE_SYS_DIR_H - use <sys/dir.h>
+# HAVE_SYS_NDIR_H - use <sys/ndir.h>
+# UTIL - select routines for utilities (note, cloak, split)
+# NO_RMDIR - remove directories using a system("rmdir ...") call.
+# NO_PROTO - cannot handle ANSI prototypes
+# NO_CONST - cannot handle ANSI const
+
+# Generic targets:
+
+# end of Makefile
diff --git a/qdos/config.s b/qdos/config.s
new file mode 100644
index 0000000..56a2a85
--- /dev/null
+++ b/qdos/config.s
@@ -0,0 +1,153 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+#
+.globl _qlflag
+.globl _qlwait
+#ifdef ZIP
+.globl _dtype
+#endif
+
+.data
+ ds.w 0
+ dc.b '<<QCFX>>01'
+#ifdef ZIP
+ dc.w 8
+ dc.b 'Info-ZIP'
+* 12345678901234567890
+ ds.w 0
+ dc.w 4
+ dc.b 'qdos'
+ ds.w 0
+#else
+ dc.w 10
+ dc.b 'Info-UNZIP'
+* 12345678901234567890
+ ds.w 0
+ dc.w 4
+ dc.b 'qdos'
+ ds.w 0
+#endif
+ dc.b 10
+ dc.b 0
+l_4: dc.w _qlwait-l_4
+ dc.w 0
+ dc.w 0
+l_5: dc.w hpt-l_5
+l_6: dc.w hxx-l_6
+
+#ifdef ZIP
+ dc.b 10
+ dc.b 0
+d_4: dc.w _dtype-d_4
+ dc.w 0
+ dc.w 0
+d_5: dc.w dpt-d_5
+d_6: dc.w dxx-d_6
+
+#else
+ dc.b 4
+ dc.b 0
+l5:
+ dc.w list1-l5
+ dc.w 0
+l5a:
+ dc.w Postit-l5a ; post proc
+l6:
+ dc.w apt-l6
+l7:
+ dc.w axx-l7
+* -------------------------------------
+ dc.b 4
+ dc.b 0
+l8:
+ dc.w list2-l8
+ dc.w 0
+l8a:
+ dc.w Postit-l8a ; post proc
+l9:
+ dc.w bpt-l9
+la:
+ dc.w bxx-la
+* -------------------------------------
+#endif
+ dc.w -1 ; end
+
+_qlflag:
+ dc.w 0
+_qlwait:
+ dc.w 250
+_dtype:
+ dc.w 255
+
+hpt: dc.w 10
+ dc.b 'Exit Delay'
+* 12345678901234567890
+ ds.w 0
+hxx: dc.w 0
+ dc.w $ffff
+ dc.w -1
+#ifdef ZIP
+dpt: dc.w 14
+ dc.b 'Directory Type'
+* 12345678901234567890
+ ds.w 0
+dxx: dc.w 3
+ dc.w $ff
+ dc.w -1
+#else
+
+list1:
+ dc.b 0
+list2:
+ dc.b 0
+
+apt:
+ dc.w 11
+ dc.b 'Unpack Mode'
+* 12345678901234567890
+.even
+axx: dc.b 0
+ dc.b 0
+ dc.w 8
+ dc.b 'SMS/QDOS'
+.even
+ dc.b 1
+ dc.b 0
+ dc.w 7
+ dc.b 'Default'
+.even
+ dc.w -1
+.even
+bpt:
+ dc.w 12
+ dc.b 'Listing Mode'
+* 12345678901234567890
+.even
+bxx:
+ dc.w 0
+ dc.w 7
+ dc.b 'Default'
+.even
+ dc.b 2
+ dc.b 0
+ dc.w 8
+ dc.b 'SMS/QDOS'
+* 12345678901234567890
+.even
+ dc.w -1
+Postit:
+ lea.l _qlflag,a0
+ move.b list1,d0
+ move.b d0,(a0)
+ move.b list2,d0
+ or.b d0,(a0)
+ moveq #0,d0
+ rts
+#endif
+ end
diff --git a/qdos/crc68.s b/qdos/crc68.s
new file mode 100644
index 0000000..9ee9df3
--- /dev/null
+++ b/qdos/crc68.s
@@ -0,0 +1,99 @@
+;===========================================================================
+; Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+.text
+
+.globl _crc32 ; (ulg val, uch *buf, extent bufsize)
+.globl _get_crc_table ; ulg *get_crc_table(void)
+
+_crc32:
+ move.l 8(sp),d0
+ bne valid
+ moveq #0,d0
+ rts
+valid: movem.l d2/d3,-(sp)
+ jsr _get_crc_table
+ move.l d0,a0
+ move.l 12(sp),d0
+ move.l 16(sp),a1
+ move.l 20(sp),d1
+ not.l d0
+
+ move.l d1,d2
+ lsr.l #3,d1
+ bra decr8
+loop8: moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+ moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+ moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+ moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+ moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+ moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+ moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+ moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+decr8: dbra d1,loop8
+ and.w #7,d2
+ bra decr1
+loop1: moveq #0,d3
+ move.b (a1)+,d3
+ eor.b d0,d3
+ lsl.w #2,d3
+ move.l 0(a0,d3.w),d3
+ lsr.l #8,d0
+ eor.l d3,d0
+decr1: dbra d2,loop1
+done: movem.l (sp)+,d2/d3
+ not.l d0
+ rts
diff --git a/qdos/match.s b/qdos/match.s
new file mode 100644
index 0000000..53b3013
--- /dev/null
+++ b/qdos/match.s
@@ -0,0 +1,138 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match.a -- optional optimized asm version of longest match in deflate.c
+; Written by Jean-loup Gailly
+;
+; Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+; using the code in match.S.
+; The major change in this code consists of removing all unaligned
+; word accesses, because they cause 68000-based Amigas to crash.
+; For maximum speed, UNALIGNED_OK can be defined in Makefile.sasc.
+; The program will then only run on 68020-based Amigas, though.
+;
+; This code will run with registerized parameters too, unless SAS
+; changes parameter passing conventions between new releases of SAS/C.
+
+
+;;Cur_Match equr d0 ; Must be in d0!
+;;Best_Len equr d1
+;;Loop_Counter equr d2
+;;Scan_Start equr d3
+;;Scan_End equr d4
+;;Limit equr d5
+;;Chain_Length equr d6
+;;Scan_Test equr d7
+;;Scan equr a0
+;;Match equr a1
+;;Prev_Address equr a2
+;;Scan_Ini equr a3
+;;Match_Ini equr a4
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+WSIZE equ 32768
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+
+
+ .globl _max_chain_length
+ .globl _prev_length
+ .globl _prev
+ .globl _window
+ .globl _strstart
+ .globl _good_match
+ .globl _match_start
+ .globl _nice_match
+
+ .text
+ .globl _match_init
+ .globl _longest_match
+
+_match_init:
+ rts
+
+
+_longest_match:
+ move.l 4(sp),d0
+ movem.l d2-d7/a2-a4,-(sp)
+ move.l _max_chain_length,d6
+ move.l _prev_length,d1
+ lea _prev,a2
+ lea _window+MIN_MATCH,a4
+ move.l _strstart,d5
+ move.l a4,a3
+ add.l d5,a3
+ subi.w #MAX_DIST,d5
+ bhi limit_ok
+ moveq #0,d5
+limit_ok:
+ cmp.l _good_match,d1
+ bcs length_ok
+ lsr.l #2,d6
+length_ok:
+ subq.l #1,d6
+
+ move.b -MIN_MATCH(a3),d3
+ lsl.w #8,d3
+ move.b -MIN_MATCH+1(a3),d3
+ move.b -MIN_MATCH-1(a3,d1),d4
+ lsl.w #8,d4
+ move.b -MIN_MATCH(a3,d1),d4
+
+ bra do_scan
+
+long_loop:
+
+ move.b -MIN_MATCH-1(a3,d1),d4
+ lsl.w #8,d4
+ move.b -MIN_MATCH(a3,d1),d4
+
+short_loop:
+ lsl.w #1,d0
+ move.w 0(a2,d0.l),d0
+ cmp.w d5,d0
+ dbls d6,do_scan
+ bra return
+
+do_scan:
+ move.l a4,a1
+ add.l d0,a1
+
+ move.b -MIN_MATCH-1(a1,d1),d7
+ lsl.w #8,d7
+ move.b -MIN_MATCH(a1,d1),d7
+ cmp.w d7,d4
+ bne short_loop
+ move.b -MIN_MATCH(a1),d7
+ lsl.w #8,d7
+ move.b -MIN_MATCH+1(a1),d7
+ cmp.w d7,d3
+ bne short_loop
+
+ move.w #(MAX_MATCH-MIN_MATCH),d2
+ move.l a3,a0
+
+scan_loop:
+ cmpm.b (a1)+,(a0)+
+ dbne d2,scan_loop
+
+ sub.l a3,a0
+ addq.l #(MIN_MATCH-1),a0
+ cmp.l d1,a0
+ bls short_loop
+ move.l a0,d1
+ move.l d0,_match_start
+ cmp.l _nice_match,d1
+ bcs long_loop
+return:
+ move.l d1,d0
+ movem.l (sp)+,d2-d7/a2-a4
+ rts
+ end
+
+
diff --git a/qdos/osdep.h b/qdos/osdep.h
new file mode 100644
index 0000000..72169c1
--- /dev/null
+++ b/qdos/osdep.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef _QDOS_OPDEP
+#define _QDOS_OPDEP
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+char * ql2Unix(char *);
+char * Unix2ql(char *, char **);
+int wild (char *);
+char *LastDir(char *);
+void QDOSexit(void);
+short devlen(char *);
+
+/*
+ * XXX NO_RENAME instead of the following define ?
+ */
+#define link rename
+#define USE_CASE_MAP
+#define USE_EF_UT_TIME
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+#endif
diff --git a/qdos/qdos.c b/qdos/qdos.c
new file mode 100644
index 0000000..906519a
--- /dev/null
+++ b/qdos/qdos.c
@@ -0,0 +1,879 @@
+/*
+ qdos/qdos.c
+
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * Yes this file is necessary; the QDOS file system is the most
+ * ludicrous known to man (even more so than VMS!).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include "zip.h"
+#include "crypt.h"
+#include "ttyio.h"
+
+#ifdef QDOS
+
+# include <qdos.h>
+
+#if CRYPT
+
+char *getp(m, p, n)
+ ZCONST char *m; /* prompt for password */
+ char *p; /* return value: line input */
+ int n; /* bytes available in p[] */
+{
+ int c; /* one-byte buffer for read() to use */
+ int i; /* number of characters input */
+ char *w; /* warning on retry */
+
+ /* get password */
+ w = "";
+ sd_cure(getchid(0), -1); /* enable cursor */
+ do {
+ fputs(w, stderr); /* warning if back again */
+ fputs(m, stderr); /* display prompt and flush */
+ fflush(stderr);
+ i = 0;
+ do {
+ c = getch();
+ if (c == 0xc2) {
+ if (i > 0) {
+ i--; /* the `del' keys works */
+ fputs("\b \b", stderr);
+ }
+ }
+ else if (i < n) {
+ p[i++] = c; /* truncate past n */
+ if(c != '\n') putc('*', stderr);
+ }
+ } while (c != '\n');
+
+ putc('\n', stderr); fflush(stderr);
+ w = "(line too long--try again)\n";
+ } while (p[i-1] != '\n');
+
+ p[i-1] = 0; /* terminate at newline */
+ sd_curs(getchid(0), -1); /* suppress cursor */
+ return p; /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* CRYPT */
+
+
+#define __attribute__(p)
+
+int newname(char *, int, int);
+
+#else /* !QDOS */
+#define QDOS_FLMAX 36
+
+short qlflag = 0;
+
+struct qdirect {
+ long d_length __attribute__ ((packed)); /* file length */
+ unsigned char d_access __attribute__ ((packed)); /* file access type */
+ unsigned char d_type __attribute__ ((packed)); /* file type */
+ long d_datalen __attribute__ ((packed)); /* data length */
+ long d_reserved __attribute__ ((packed));/* Unused */
+ short d_szname __attribute__ ((packed)); /* size of name */
+ char d_name[QDOS_FLMAX] __attribute__ ((packed));/* name area */
+ long d_update __attribute__ ((packed)); /* last update */
+ long d_refdate __attribute__ ((packed));
+ long d_backup __attribute__ ((packed)); /* EOD */
+ } ;
+#endif /* ?QDOS */
+
+#define SHORTID 0x4afb /* in big-endian order !! */
+#define LONGID "QDOS02"
+#define EXTRALEN (sizeof(struct qdirect) + 8)
+
+typedef struct
+{
+ unsigned short shortid __attribute__ ((packed));
+ struct
+ {
+ unsigned char lo __attribute__ ((packed));
+ unsigned char hi __attribute__ ((packed));
+ } len __attribute__ ((packed));
+ char longid[8] __attribute__ ((packed));
+ struct qdirect header __attribute__ ((packed));
+} qdosextra;
+
+#ifdef USE_EF_UT_TIME
+local int GetExtraTime(struct zlist far *z, iztimes *z_utim, unsigned ut_flg);
+#endif
+
+#ifdef QDOS
+
+#define rev_short(x) (x)
+#define rev_long(x) (x)
+
+char _prog_name[] = "zip";
+char _copyright[] = "(c) Info-ZIP Group";
+long _stack = 16*1024;
+char * _endmsg = NULL;
+
+extern void consetup_title(chanid_t,struct WINDOWDEF *);
+void (*_consetup)(chanid_t,struct WINDOWDEF *) = consetup_title;
+
+struct WINDOWDEF _condetails =
+{
+ 2,
+ 1,
+ 0,
+ 7,
+ 500,
+ 220,
+ 2,
+ 30
+};
+
+extern short qlwait;
+extern short dtype;
+
+#define CHECKDIR(p1) (((p1).d_type == dtype) && (((p1).d_length % 64) == 0))
+
+char * stpcpy (char *d, ZCONST char *s)
+{
+ while(*d++ = *s++)
+ ; /* Null loop */
+ return d-1;
+}
+
+static jobid_t chowner(chanid_t chan)
+{
+ extern char *_sys_var;
+ char *scht;
+ long *cdb;
+ long jid;
+
+ scht = *((char **)(_sys_var + 0x78));
+ cdb = *(long **)((long *)scht + (chan & 0xffff));
+ jid = *(cdb + 2);
+ return jid;
+}
+
+void QDOSexit(void)
+{
+ jobid_t me,you;
+
+ me = getpid();
+ you = chowner(getchid(0));
+
+ if((me == you) && ((qlflag & 4) == 0))
+ {
+ if(isatty(0) && isatty(2) && qlwait)
+ {
+ char c = 0;
+ fputs("Press a key to exit", stderr);
+ if((io_fbyte(getchid(0), qlwait, &c) == 0) && c == 27)
+ {
+ io_fbyte(getchid(0), -1, &c);
+ }
+ }
+ }
+ exit(ZE_OK);
+}
+
+/* Access seems to be *always* broken in c68 */
+/* Not accurate, just works */
+
+int access (char *f, int mode)
+{
+ struct stat st;
+ int fd;
+
+ if((fd = stat(f, &st)) == 0)
+ {
+ switch(fd)
+ {
+ case F_OK:
+ break;
+ case R_OK:
+ fd = (st.st_mode & 0444) == 0;
+ break;
+ case W_OK:
+ fd = (st.st_mode & 0222) == 0;
+ break;
+ case X_OK:
+ fd = (st.st_mode & 0111) == 0;
+ break;
+ default:
+ fd = -1;
+ break;
+ }
+ }
+ return fd;
+}
+
+/* Fixup a Mickey Mouse file naming system */
+
+char * Unix2ql (char *qlname, char **dot)
+{
+ static char path[64];
+ char name[64];
+ char *q, *r, *s;
+
+ strcpy(name, qlname);
+ if(*name == '~')
+ {
+ r = name+1;
+ getcwd(path, sizeof(path));
+ q = path + strlen(path);
+ if(*(q-1) != '_')
+ {
+ *q++ = '_';
+ }
+ }
+ else
+ {
+ q = path;
+ r = name;
+ }
+
+ if(*r == '/')
+ {
+ r++;
+ }
+
+ strcpy(q, r);
+
+ while (*q)
+ {
+ if(*q == '/' || *q == '.')
+ {
+ if(*q == '.' && dot)
+ {
+ *dot = name + (q - path);
+ }
+ *q = '_';
+ }
+
+ q++;
+ }
+ return path;
+}
+
+#if 0 /* Not used in ZIP */
+
+GuessAltName(char *name, char *dot)
+{
+ if(dot)
+ {
+ *dot = '.';
+ }
+ else
+ {
+ if((dot = strrchr(name, '_')))
+ {
+ *dot = '.';
+ }
+ }
+}
+
+#endif /* 0 */
+
+short devlen(char *p)
+{
+ char defpath[40];
+ short deflen = 0, ok = 0;
+
+ getcwd(defpath, sizeof(defpath));
+ deflen = strlen(defpath);
+ if(deflen)
+ {
+ if(strnicmp(p, defpath, deflen) == 0)
+ {
+ ok = 1;
+ }
+ }
+
+ if(!ok)
+ {
+ if(isdirdev(p))
+ {
+ deflen = 5;
+ }
+ else
+ {
+ deflen = 0;
+ }
+ }
+ return deflen;
+}
+
+char * ql2Unix (char *qlname)
+{
+ struct stat st;
+ int sts;
+ char *p, *r, *s, *ldp;
+ char *pnam = NULL;
+ static char path[64];
+ short deflen;
+ char name[64];
+
+ strcpy(name, qlname);
+ strcpy(path, name);
+
+ deflen = devlen(qlname);
+
+ p = name + deflen;
+ pnam = path + deflen;
+
+ if(s = strrchr(p, '_'))
+ {
+ *s = 0;
+ sts = stat(name, &st);
+ if(deflen && sts ==0 && (st.st_mode & S_IFDIR))
+ {
+ *(path+(s-name)) = '/';
+ }
+ else
+ {
+ *(path+(s-name)) = '.';
+ }
+ }
+
+ ldp = p;
+ for(r = p; *r; r++)
+ {
+ if(r != ldp && *r == '_')
+ {
+ *r = 0;
+ if(deflen)
+ {
+ sts = stat(name, &st);
+ }
+ else
+ sts = -1;
+
+ if(sts ==0 && (st.st_mode & S_IFDIR))
+ {
+ *(path+(r-name)) = '/';
+ ldp = r + 1;
+ }
+ else
+ {
+ *(path+(r-name)) = '_';
+ }
+ *r = '_';
+ }
+ }
+ return pnam;
+}
+
+char *LastDir(char *ws)
+{
+ char *p;
+ char *q = ws;
+ struct stat s;
+
+ for(p = ws; *p; p++)
+ {
+ if(p != ws && *p == '_')
+ {
+ char c;
+
+ p++;
+ c = *p;
+ *p = 0;
+ if(stat(ws, &s) == 0 && S_ISDIR(s.st_mode))
+ {
+ q = p;
+ }
+ *p = c;
+ }
+ }
+ return q;
+}
+
+# ifndef UTIL
+
+static int add_dir(char * dnam)
+{
+ int e = ZE_OK;
+ char *p;
+ short nlen;
+
+ nlen = strlen(dnam);
+ if(p = malloc(nlen + 2))
+ {
+ strncpy (p, dnam, nlen);
+ if(*(p+nlen) != '_')
+ {
+ *(p+nlen) = '_';
+ *(p+nlen+1) = '\0';
+ }
+ if ((e = newname(p, 1, 0)) != ZE_OK)
+ {
+ free(p);
+ }
+ }
+ else
+ {
+ e = ZE_MEM;
+ }
+ return e;
+}
+
+int qlwild (char *dnam, short dorecurse, short l)
+{
+ static char match[40] = {0};
+ static char ddev[8] = {0};
+ static short nc;
+ static short llen;
+ static char base[40];
+
+ int chid;
+ struct qdirect qd;
+ char *dp;
+ int e = ZE_MISS;
+
+ if (l == 0)
+ {
+ nc = 0;
+ *base = '\0';
+ if (isdirdev (dnam))
+ {
+ dp = dnam;
+ strncpy (ddev, dnam, 5);
+ }
+ else
+ {
+
+ char *p;
+ char temp[40];
+
+ getcwd (temp, 40);
+
+ llen = strlen(temp);
+ p = (temp + llen - 1);
+ if (*p != '_')
+ {
+ *p++ = '_';
+ *p = 0;
+ }
+
+ strncpy (ddev, temp, 5);
+ dp = base;
+ p = stpcpy (dp, temp);
+ strcpy (p, dnam);
+ }
+
+ {
+ char *q = isshexp (dp);
+ if(q)
+ {
+ strcpy (match, dp + 5);
+ if (q)
+ {
+ while (q != dp && *q != '_')
+ {
+ q--;
+ }
+ *(++q) = '\0';
+ }
+ }
+ else
+ {
+ struct stat s;
+ if (stat(dp, &s) == 0)
+ {
+ if (!(s.st_mode & S_IFDIR))
+ {
+ return procname(dp, 0);
+ }
+ }
+ else
+ {
+ return ZE_MISS; /* woops, no wildcards! */
+ }
+ }
+
+ }
+ }
+ else
+ {
+ dp = dnam;
+ }
+
+ if ((chid = io_open (dp, 4L)) > 0)
+ {
+ int id = 0;
+ while (io_fstrg (chid, -1, &qd, 64) > 0)
+ {
+ short j;
+
+ if (qd.d_szname)
+ {
+ if (CHECKDIR(qd))
+ {
+ if(dorecurse)
+ {
+ char fnam[256], *p;
+
+ p = stpcpy (fnam, ddev);
+ strncpy (p, qd.d_name, qd.d_szname);
+ *(p + qd.d_szname) = 0;
+ e = qlwild (fnam, dorecurse, l+1);
+ }
+ else
+ {
+ continue;
+ }
+ }
+ else
+ {
+ char nam[48];
+ strcpy(nam, ddev);
+
+ strncpy (nam + 5, qd.d_name, qd.d_szname);
+ *(nam + 5 + qd.d_szname) = 0;
+
+ if (MATCH (match, nam + 5, 0) == 1)
+ {
+ if(dirnames && l && id == 0)
+ {
+ id = 1;
+ if((e = add_dir(dp)) != ZE_OK)
+ {
+ return e;
+ }
+ }
+
+ if((e = procname(nam, 0)) == ZE_OK)
+ {
+ nc++;
+ }
+ }
+ }
+ }
+ }
+ io_close (chid);
+ }
+
+ if (l == 0)
+ {
+ *ddev = 0;
+ *match = 0;
+ e = (nc) ? ZE_OK : ZE_MISS;
+ }
+ return e;
+
+}
+
+int wild(char *p)
+{
+ return qlwild(p, recurse, 0);
+}
+# endif /* !UTIL */
+
+/*
+ * Return QDOS error, 0 if exec 1 if found but not exe or rel
+ */
+int qlstat(char *name, struct qdirect *qs, char *flag)
+{
+ int r;
+ r = qstat(name, qs);
+ if(r == 0)
+ {
+ if(qs->d_type == 0)
+ {
+ r = 1;
+ }
+ else if(CHECKDIR(*qs))
+ {
+ r = 255;
+ }
+ }
+ return r;
+}
+
+#else /* !QDOS */
+
+long rev_long (ulg l)
+{
+ uch cc[4];
+ cc[0] = (uch)(l >> 24);
+ cc[1] = (uch)((l >> 16) & 0xff);
+ cc[2] = (uch)((l >> 8) & 0xff);
+ cc[3] = (uch)(l & 0xff);
+ return *(ulg *)cc;
+}
+
+short rev_short (ush s)
+{
+ uch cc[2];
+ cc[0] = (uch)((s >> 8) & 0xff);
+ cc[1] = (uch)(s & 0xff);
+ return *(ush *)cc;
+}
+
+#define O_BINARY 0
+
+int qlstat(char *name, struct qdirect *qs, char *flag)
+{
+ int r = -1;
+ int n, fd;
+ struct stat s;
+ struct _ntc_
+ {
+ long id;
+ long dlen;
+ } ntc;
+
+ *flag = 0;
+ if((fd = open(name, O_RDONLY | O_BINARY)) > 0)
+ {
+ short nl;
+
+ fstat(fd, &s);
+ lseek(fd, -8, SEEK_END);
+ read(fd, &ntc, 8);
+ qs->d_length = rev_long(s.st_size);
+ qs->d_update = rev_long(s.st_ctime + 283996800);
+
+ nl = strlen(name);
+ if(nl > QDOS_FLMAX)
+ {
+ nl = QDOS_FLMAX;
+ *flag = 1;
+ }
+ qs->d_szname = rev_short(nl);
+ memcpy(qs->d_name, name, nl);
+
+ if(ntc.id == *(long *)"XTcc")
+ {
+ qs->d_datalen = ntc.dlen; /* This is big endian */
+ qs->d_type = 1;
+ r = 0;
+ }
+ else
+ {
+ qs->d_type = 0;
+ qs->d_datalen = 0;
+ r = 1;
+ }
+ close(fd);
+ return r;
+ }
+ else
+ {
+ fprintf(stderr, "Fails %d\n", fd);
+ return r;
+ }
+}
+
+#endif /* ?QDOS */
+
+#ifdef USE_EF_UT_TIME
+
+#define EB_L_UT_SIZE (EB_HEADSIZE + eb_l_ut_len)
+#define EB_C_UT_SIZE (EB_HEADSIZE + eb_c_ut_len)
+
+#ifdef UNIX
+#define EB_L_UX2_SIZE (EB_HEADSIZE + EB_UX2_MINLEN)
+#define EB_C_UX2_SIZE EB_HEADSIZE
+#define EF_L_UT_UX2_SIZE (EB_L_UT_SIZE + EB_L_UX2_SIZE)
+#define EF_C_UT_UX2_SIZE (EB_C_UT_SIZE + EB_C_UX2_SIZE)
+#else
+#define EF_L_UT_UX2_SIZE EB_L_UT_SIZE
+#define EF_C_UT_UX2_SIZE EB_C_UT_SIZE
+#endif
+
+local int GetExtraTime(struct zlist far *z, iztimes *z_utim, unsigned ut_flg)
+{
+ char *eb_l_ptr;
+ char *eb_c_ptr;
+ char *eb_pt;
+ extent eb_l_ut_len = 0;
+ extent eb_c_ut_len = 0;
+
+#ifdef UNIX
+ struct stat s;
+
+ /* For the full sized UT local field including the UID/GID fields, we
+ * have to stat the file, again. */
+ if (stat(z->name, &s))
+ return ZE_OPEN;
+ /* update times in z_utim, stat() call might have changed atime... */
+ z_utim->mtime = s.st_mtime;
+ z_utim->atime = s.st_atime;
+ z_utim->ctime = s.st_mtime; /* best guess (st_ctime != creation time) */
+#endif /* UNIX */
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ ut_flg = 0; /* disable UT e.f creation if no valid TZ info */
+#endif
+ if (ut_flg != 0) {
+ if (ut_flg & EB_UT_FL_MTIME)
+ eb_l_ut_len = eb_c_ut_len = 1;
+ if (ut_flg & EB_UT_FL_ATIME)
+ eb_l_ut_len++;
+ if (ut_flg & EB_UT_FL_CTIME)
+ eb_l_ut_len++;
+
+ eb_l_ut_len = EB_UT_LEN(eb_l_ut_len);
+ eb_c_ut_len = EB_UT_LEN(eb_c_ut_len);
+ }
+
+ if (EF_L_UT_UX2_SIZE > EB_HEADSIZE) {
+ if(z->ext)
+ eb_l_ptr = realloc(z->extra, (z->ext + EF_L_UT_UX2_SIZE));
+ else
+ eb_l_ptr = malloc(EF_L_UT_UX2_SIZE);
+
+ if (eb_l_ptr == NULL)
+ return ZE_MEM;
+
+ if(z->cext)
+ eb_c_ptr = realloc(z->cextra, (z->cext + EF_C_UT_UX2_SIZE));
+ else
+ eb_c_ptr = malloc(EF_C_UT_UX2_SIZE);
+
+ if (eb_c_ptr == NULL)
+ return ZE_MEM;
+
+ z->extra = eb_l_ptr;
+ eb_l_ptr += z->ext;
+ z->ext += EF_L_UT_UX2_SIZE;
+
+ if (ut_flg != 0) {
+ eb_l_ptr[0] = 'U';
+ eb_l_ptr[1] = 'T';
+ eb_l_ptr[2] = eb_l_ut_len; /* length of data part of e.f. */
+ eb_l_ptr[3] = 0;
+ eb_l_ptr[4] = ut_flg;
+ eb_pt = eb_l_ptr + 5;
+ if (ut_flg & EB_UT_FL_MTIME) {
+ *eb_pt++ = (char)(z_utim->mtime);
+ *eb_pt++ = (char)(z_utim->mtime >> 8);
+ *eb_pt++ = (char)(z_utim->mtime >> 16);
+ *eb_pt++ = (char)(z_utim->mtime >> 24);
+ }
+ if (ut_flg & EB_UT_FL_ATIME) {
+ *eb_pt++ = (char)(z_utim->atime);
+ *eb_pt++ = (char)(z_utim->atime >> 8);
+ *eb_pt++ = (char)(z_utim->atime >> 16);
+ *eb_pt++ = (char)(z_utim->atime >> 24);
+ }
+ if (ut_flg & EB_UT_FL_CTIME) {
+ *eb_pt++ = (char)(z_utim->ctime);
+ *eb_pt++ = (char)(z_utim->ctime >> 8);
+ *eb_pt++ = (char)(z_utim->ctime >> 16);
+ *eb_pt++ = (char)(z_utim->ctime >> 24);
+ }
+ }
+#ifdef UNIX
+ else {
+ eb_pt = eb_l_ptr;
+ }
+ *eb_pt++ = 'U';
+ *eb_pt++ = 'x';
+ *eb_pt++ = EB_UX2_MINLEN; /* length of data part of local e.f. */
+ *eb_pt++ = 0;
+ *eb_pt++ = (char)(s.st_uid);
+ *eb_pt++ = (char)(s.st_uid >> 8);
+ *eb_pt++ = (char)(s.st_gid);
+ *eb_pt++ = (char)(s.st_gid >> 8);
+#endif /* UNIX */
+
+ z->cextra = eb_c_ptr;
+ eb_c_ptr += z->cext;
+ z->cext += EF_C_UT_UX2_SIZE;
+
+ if (ut_flg != 0) {
+ memcpy(eb_c_ptr, eb_l_ptr, EB_C_UT_SIZE);
+ eb_c_ptr[EB_LEN] = eb_c_ut_len;
+ }
+#ifdef UNIX
+ memcpy(eb_c_ptr+EB_C_UT_SIZE, eb_l_ptr+EB_L_UT_SIZE, EB_C_UX2_SIZE);
+ eb_c_ptr[EB_LEN+EB_C_UT_SIZE] = 0;
+#endif /* UNIX */
+ }
+
+ return ZE_OK;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+
+int set_extra_field (struct zlist *z, iztimes *z_utim )
+{
+ int rv = 0;
+ int last_rv = 0;
+ char flag = 0;
+
+ if ((qlflag & 3) != 1)
+ {
+ qdosextra *lq, *cq;
+ if ((lq = (qdosextra *) calloc(sizeof(qdosextra), 1)) == NULL)
+ return ZE_MEM;
+ if ((cq = (qdosextra *) calloc(sizeof(qdosextra), 1)) == NULL)
+ return ZE_MEM;
+
+ rv = qlstat(z->name, &(lq->header), &flag);
+
+ if (rv == 0 || (rv == 1 && (qlflag & 2)))
+ {
+ lq->shortid = rev_short((short) SHORTID);
+ lq->len.lo = (unsigned char)(EXTRALEN & 0xff);
+ lq->len.hi = (unsigned char)(EXTRALEN >> 8);
+ strcpy(lq->longid, LONGID);
+
+ memcpy(cq, lq, sizeof(qdosextra));
+
+ z->ext = sizeof(qdosextra);
+ z->cext = sizeof(qdosextra);
+ z->extra = (void *) lq;
+ z->cextra = (void *) cq;
+ fprintf (stderr, " %c",
+ lq->header.d_datalen ? '*' : '#');
+ }
+ else if (rv == -1)
+ {
+ fprintf(stderr,
+ "%s: warning: cannot stat %s, no file header added\n",
+ "zip", z->name);
+ }
+ if(flag)
+ {
+ fputs (" !", stderr);
+ }
+ }
+ last_rv = (rv == -1 ? ZE_OPEN : ZE_OK);
+
+#ifdef USE_EF_UT_TIME
+# ifdef QDOS
+# define IZ_UT_FLAGS EB_UT_FL_MTIME
+# endif
+# ifdef UNIX
+# define IZ_UT_FLAGS (EB_UT_FL_MTIME | EB_UT_FL_ATIME)
+# endif
+# ifndef IZ_UT_FLAGS
+# define IZ_UT_FLAGS EB_UT_FL_MTIME
+# endif
+
+ rv = GetExtraTime(z, z_utim, IZ_UT_FLAGS);
+ if (rv != ZE_OK)
+ last_rv = rv;
+#endif /* USE_EF_UT_TIME */
+
+ return last_rv;
+}
diff --git a/qdos/qfileio.c b/qdos/qfileio.c
new file mode 100644
index 0000000..0029b8f
--- /dev/null
+++ b/qdos/qfileio.c
@@ -0,0 +1,233 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+#include <utime.h>
+
+#include <errno.h>
+
+#ifdef S_IWRITE
+# undef S_IWRITE
+#endif /* S_IWRITE */
+#define S_IWRITE S_IWUSR
+
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+
+typedef time_t statime;
+#define PAD 0
+#define PATH_END '/'
+
+/* Local functions */
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (SSTAT(n, &s) )
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free(p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ }
+ return ZE_OK;
+}
+
+
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+ t = ql2Unix(x);
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Discard directory names with zip -rj */
+ if (*t == '\0')
+ return t;
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, Unix2ql(n, NULL));
+ return x;
+}
+
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ struct utimbuf u; /* argument for utime() const ?? */
+
+ /* Convert DOS time to time_t format in u */
+ u.actime = u.modtime = dos2unixtime(d);
+ utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* from FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFMT) == S_IFDIR) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ return rmdir(d);
+}
+
+#endif /* !UTIL */
+
+
+void version_local()
+{
+ puts ("Compiled with c68 v4.2x on " __DATE__);
+}
diff --git a/qdos/zipup.h b/qdos/zipup.h
new file mode 100644
index 0000000..1de3f61
--- /dev/null
+++ b/qdos/zipup.h
@@ -0,0 +1,19 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/revision.h b/revision.h
new file mode 100644
index 0000000..7348cb7
--- /dev/null
+++ b/revision.h
@@ -0,0 +1,139 @@
+/*
+ revision.h - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * revision.h by Mark Adler.
+ */
+
+#ifndef __revision_h
+#define __revision_h 1
+
+/* For api version checking */
+#define Z_MAJORVER 3
+#define Z_MINORVER 0
+#define Z_PATCHLEVEL 0
+#define Z_BETALEVEL "i BETA"
+
+#define VERSION "3.0"
+#define REVDATE "July 5th 2008"
+
+#define DW_MAJORVER Z_MAJORVER
+#define DW_MINORVER Z_MINORVER
+#define DW_PATCHLEVEL Z_PATCHLEVEL
+
+#ifndef IZ_COMPANY_NAME /* might be already defined... */
+# define IZ_COMPANY_NAME "Info-ZIP"
+#endif
+
+#if !defined(WINDLL) && !defined(IZ_VERSION_SYMBOLS_ONLY)
+/* Copyright notice for binary executables--this notice only applies to
+ * those (zip, zipcloak, zipsplit, and zipnote), not to this file
+ * (revision.h).
+ */
+
+#ifndef DEFCPYRT
+/* copyright[] et.al. get defined only once ! */
+/* keep array sizes in sync with number of text */
+/* lines in the array definitions below !! */
+extern ZCONST char *copyright[1];
+extern ZCONST char * far swlicense[50];
+extern ZCONST char * far versinfolines[7];
+extern ZCONST char * far cryptnote[7];
+
+#else /* DEFCPYRT */
+
+ZCONST char *copyright[] = {
+"Copyright (c) 1990-2008 Info-ZIP - Type '%s \"-L\"' for software license."
+/* XXX still necessary ???? */
+#ifdef AZTEC_C
+, /* extremely lame compiler bug workaround */
+#endif
+};
+
+ZCONST char * far versinfolines[] = {
+"This is %s %s (%s), by Info-ZIP.",
+"Currently maintained by E. Gordon. Please send bug reports to",
+"the authors using the web page at www.info-zip.org; see README for details.",
+"",
+"Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip,",
+"as of above date; see http://www.info-zip.org/ for other sites.",
+""
+};
+
+/* new notice - 4 March 2007 */
+ZCONST char * far cryptnote[] = {
+"Encryption notice:",
+"\tThe encryption code of this program is not copyrighted and is",
+"\tput in the public domain. It was originally written in Europe",
+"\tand, to the best of our knowledge, can be freely distributed",
+"\tin both source and object forms from any country, including",
+"\tthe USA under License Exception TSU of the U.S. Export",
+"\tAdministration Regulations (section 740.13(e)) of 6 June 2002."
+};
+
+ZCONST char * far swlicense[] = {
+"Copyright (c) 1990-2008 Info-ZIP. All rights reserved.",
+"",
+"For the purposes of this copyright and license, \"Info-ZIP\" is defined as",
+"the following set of individuals:",
+"",
+" Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,",
+" Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,",
+" Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,",
+" David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,",
+" Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,",
+" Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,",
+" Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,",
+" Rich Wales, Mike White",
+"",
+"This software is provided \"as is,\" without warranty of any kind, express",
+"or implied. In no event shall Info-ZIP or its contributors be held liable",
+"for any direct, indirect, incidental, special or consequential damages",
+"arising out of the use of or inability to use this software.",
+"",
+"Permission is granted to anyone to use this software for any purpose,",
+"including commercial applications, and to alter it and redistribute it",
+"freely, subject to the above disclaimer and the following restrictions:",
+"",
+" 1. Redistributions of source code (in whole or in part) must retain",
+" the above copyright notice, definition, disclaimer, and this list",
+" of conditions.",
+"",
+" 2. Redistributions in binary form (compiled executables and libraries)",
+" must reproduce the above copyright notice, definition, disclaimer,",
+" and this list of conditions in documentation and/or other materials",
+" provided with the distribution. The sole exception to this condition",
+" is redistribution of a standard UnZipSFX binary (including SFXWiz) as",
+" part of a self-extracting archive; that is permitted without inclusion",
+" of this license, as long as the normal SFX banner has not been removed",
+" from the binary or disabled.",
+"",
+" 3. Altered versions--including, but not limited to, ports to new operating",
+" systems, existing ports with new graphical interfaces, versions with",
+" modified or added functionality, and dynamic, shared, or static library",
+" versions not from Info-ZIP--must be plainly marked as such and must not",
+" be misrepresented as being the original source or, if binaries,",
+" compiled from the original source. Such altered versions also must not",
+" be misrepresented as being Info-ZIP releases--including, but not",
+" limited to, labeling of the altered versions with the names \"Info-ZIP\"",
+" (or any variation thereof, including, but not limited to, different",
+" capitalizations), \"Pocket UnZip,\" \"WiZ\" or \"MacZip\" without the",
+" explicit permission of Info-ZIP. Such altered versions are further",
+" prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP",
+" e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP",
+" will provide support for the altered versions.",
+"",
+" 4. Info-ZIP retains the right to use the names \"Info-ZIP,\" \"Zip,\" \"UnZip,\"",
+" \"UnZipSFX,\" \"WiZ,\" \"Pocket UnZip,\" \"Pocket Zip,\" and \"MacZip\" for its",
+" own source and binary releases."
+};
+#endif /* DEFCPYRT */
+#endif /* !WINDLL && !IZ_VERSION_SYMBOLS_ONLY */
+#endif /* !__revision_h */
diff --git a/tailor.h b/tailor.h
new file mode 100644
index 0000000..272f979
--- /dev/null
+++ b/tailor.h
@@ -0,0 +1,887 @@
+/*
+ tailor.h - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* Some compiler distributions for Win32/i386 systems try to emulate
+ * a Unix (POSIX-compatible) environment.
+ */
+#if (defined(WIN32) && defined(UNIX))
+ /* Zip does not support merging both ports in a single executable. */
+# if (defined(FORCE_WIN32_OVER_UNIX) && defined(FORCE_UNIX_OVER_WIN32))
+ /* conflicting choice requests -> we prefer the Win32 environment */
+# undef FORCE_UNIX_OVER_WIN32
+# endif
+# ifdef FORCE_WIN32_OVER_UNIX
+ /* native Win32 support was explicitely requested... */
+# undef UNIX
+# else
+ /* use the POSIX (Unix) emulation features by default... */
+# undef WIN32
+# endif
+#endif
+
+
+/* UNICODE */
+#ifdef NO_UNICODE_SUPPORT
+# ifdef UNICODE_SUPPORT
+# undef UNICODE_SUPPORT
+# endif
+#endif
+
+
+#ifdef AMIGA
+#include "amiga/osdep.h"
+#endif
+
+#ifdef AOSVS
+#include "aosvs/osdep.h"
+#endif
+
+#ifdef ATARI
+#include "atari/osdep.h"
+#endif
+
+#ifdef __ATHEOS__
+#include "atheos/osdep.h"
+#endif
+
+#ifdef __BEOS__
+#include "beos/osdep.h"
+#endif
+
+#ifdef DOS
+#include "msdos/osdep.h"
+#endif
+
+#ifdef __human68k__
+#include "human68k/osdep.h"
+#endif
+
+#if ((defined(__MWERKS__) && defined(macintosh)) || defined(MACOS))
+#include "macos/osdep.h"
+#endif
+
+#ifdef NLM
+#include "novell/osdep.h"
+#endif
+
+#ifdef OS2
+#include "os2/osdep.h"
+#endif
+
+#ifdef __riscos
+#include "acorn/osdep.h"
+#endif
+
+#ifdef QDOS
+#include "qdos/osdep.h"
+#endif
+
+#ifdef __TANDEM
+#include "tandem.h"
+#include "tanzip.h"
+#endif
+
+#ifdef UNIX
+#include "unix/osdep.h"
+#endif
+
+#if defined(__COMPILER_KCC__) || defined(TOPS20)
+#include "tops20/osdep.h"
+#endif
+
+#if defined(VMS) || defined(__VMS)
+#include "vms/osdep.h"
+#endif
+
+#if defined(__VM__) || defined(VM_CMS) || defined(MVS)
+#include "cmsmvs.h"
+#endif
+
+#ifdef WIN32
+#include "win32/osdep.h"
+#endif
+
+#ifdef THEOS
+#include "theos/osdep.h"
+#endif
+
+
+/* generic LARGE_FILE_SUPPORT defines
+ These get used if not defined above.
+ 7/21/2004 EG
+*/
+/* If a port hasn't defined ZOFF_T_FORMAT_SIZE_PREFIX
+ then probably need to define all of these. */
+#ifndef ZOFF_T_FORMAT_SIZE_PREFIX
+
+# ifdef LARGE_FILE_SUPPORT
+ /* Probably passed in from command line instead of in above
+ includes if get here. Assume large file support and hope. 8/14/04 EG */
+
+ /* Set the Large File Summit (LFS) defines to turn on large file support
+ in case it helps. */
+
+# define _LARGEFILE_SOURCE /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */
+# define _LARGE_FILES /* some OSes need this for 64-bit off_t */
+
+ typedef off_t zoff_t;
+ typedef unsigned long long uzoff_t; /* unsigned zoff_t (12/29/04 EG) */
+
+ /* go with common prefix */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+# else
+ /* Default type for offsets and file sizes was ulg but reports
+ of using ulg to create files from 2 GB to 4 GB suggest
+ it doesn't work well. Now just switch to Zip64 or not
+ support over 2 GB. 7/24/04 EG */
+ /* Now use uzoff_t for unsigned things. 12/29/04 EG */
+ typedef long zoff_t;
+ typedef unsigned long uzoff_t;
+
+# define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+
+# endif
+
+ typedef struct stat z_stat;
+
+ /* flag that we are defaulting */
+# define USING_DEFAULT_LARGE_FILE_SUPPORT
+#endif
+
+
+#if (defined(USE_ZLIB) && defined(ASM_CRC))
+# undef ASM_CRC
+#endif
+
+#if (defined(USE_ZLIB) && defined(ASMV))
+# undef ASMV
+#endif
+
+/* When "void" is an alias for "int", prototypes cannot be used. */
+#if (defined(NO_VOID) && !defined(NO_PROTO))
+# define NO_PROTO
+#endif
+
+/* Used to remove arguments in function prototypes for non-ANSI C */
+#ifndef NO_PROTO
+# define OF(a) a
+# define OFT(a) a
+#else /* NO_PROTO */
+# define OF(a) ()
+# define OFT(a)
+#endif /* ?NO_PROTO */
+
+/* If the compiler can't handle const define ZCONST in osdep.h */
+/* Define const itself in case the system include files are bonkers */
+#ifndef ZCONST
+# ifdef NO_CONST
+# define ZCONST
+# define const
+# else
+# define ZCONST const
+# endif
+#endif
+
+/*
+ * Some compiler environments may require additional attributes attached
+ * to declarations of runtime libary functions (e.g. to prepare for
+ * linking against a "shared dll" version of the RTL). Here, we provide
+ * the "empty" default for these attributes.
+ */
+#ifndef IZ_IMP
+# define IZ_IMP
+#endif
+
+/*
+ * case mapping functions. case_map is used to ignore case in comparisons,
+ * to_up is used to force upper case even on Unix (for dosify option).
+ */
+#ifdef USE_CASE_MAP
+# define case_map(c) upper[(c) & 0xff]
+# define to_up(c) upper[(c) & 0xff]
+#else
+# define case_map(c) (c)
+# define to_up(c) ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))
+#endif /* USE_CASE_MAP */
+
+/* Define void, zvoid, and extent (size_t) */
+#include <stdio.h>
+
+#ifndef NO_STDDEF_H
+# include <stddef.h>
+#endif /* !NO_STDDEF_H */
+
+#ifndef NO_STDLIB_H
+# include <stdlib.h>
+#endif /* !NO_STDLIB_H */
+
+#ifndef NO_UNISTD_H
+# include <unistd.h> /* usually defines _POSIX_VERSION */
+#endif /* !NO_UNISTD_H */
+
+#ifndef NO_FCNTL_H
+# include <fcntl.h>
+#endif /* !NO_FNCTL_H */
+
+#ifndef NO_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* NO_STRING_H */
+
+#ifdef NO_VOID
+# define void int
+ typedef char zvoid;
+#else /* !NO_VOID */
+# ifdef NO_TYPEDEF_VOID
+# define zvoid void
+# else
+ typedef void zvoid;
+# endif
+#endif /* ?NO_VOID */
+
+#ifdef NO_STRRCHR
+# define strrchr rindex
+#endif
+
+#ifdef NO_STRCHR
+# define strchr index
+#endif
+
+/*
+ * A couple of forward declarations that are needed on systems that do
+ * not supply C runtime library prototypes.
+ */
+#ifdef NO_PROTO
+IZ_IMP char *strcpy();
+IZ_IMP char *strcat();
+IZ_IMP char *strrchr();
+/* XXX use !defined(ZMEM) && !defined(__hpux__) ? */
+#if !defined(ZMEM) && defined(NO_STRING_H)
+IZ_IMP char *memset();
+IZ_IMP char *memcpy();
+#endif /* !ZMEM && NO_STRING_H */
+
+/* XXX use !defined(__hpux__) ? */
+#ifdef NO_STDLIB_H
+IZ_IMP char *calloc();
+IZ_IMP char *malloc();
+IZ_IMP char *getenv();
+IZ_IMP long atol();
+#endif /* NO_STDLIB_H */
+
+#ifndef NO_MKTEMP
+IZ_IMP char *mktemp();
+#endif /* !NO_MKTEMP */
+
+#endif /* NO_PROTO */
+
+/*
+ * SEEK_* macros, should be defined in stdio.h
+ */
+/* Define fseek() commands */
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif /* !SEEK_SET */
+
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif /* !SEEK_CUR */
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifdef NO_SIZE_T
+ typedef unsigned int extent;
+ /* define size_t 3/17/05 EG */
+ typedef unsigned int size_t;
+#else
+ typedef size_t extent;
+#endif
+
+#ifdef NO_TIME_T
+ typedef long time_t;
+#endif
+
+/* DBCS support for Info-ZIP's zip (mainly for japanese (-: )
+ * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
+ * This code is public domain! Date: 1998/12/20
+ */
+
+/* 2007-07-29 SMS.
+ * Include <locale.h> here if it will be needed later for Unicode.
+ * Otherwise, SETLOCALE may be defined here, and then defined again
+ * (differently) when <locale.h> is read later.
+ */
+#ifdef UNICODE_SUPPORT
+# if defined( UNIX) || defined( VMS)
+# include <locale.h>
+# endif /* defined( UNIX) || defined( VMS) */
+# include <wchar.h>
+# include <wctype.h>
+#endif /* def UNICODE_SUPPORT */
+
+#ifdef _MBCS
+# include <locale.h>
+
+ /* Multi Byte Character Set */
+ extern char *___tmp_ptr;
+ unsigned char *zmbschr OF((ZCONST unsigned char *, unsigned int));
+ unsigned char *zmbsrchr OF((ZCONST unsigned char *, unsigned int));
+# define CLEN(ptr) mblen((ZCONST char *)ptr, MB_CUR_MAX)
+# define PREINCSTR(ptr) (ptr += CLEN(ptr))
+# define POSTINCSTR(ptr) (___tmp_ptr=(char *)ptr,ptr += CLEN(ptr),___tmp_ptr)
+ int lastchar OF((ZCONST char *ptr));
+# define MBSCHR(str,c) (char *)zmbschr((ZCONST unsigned char *)(str), c)
+# define MBSRCHR(str,c) (char *)zmbsrchr((ZCONST unsigned char *)(str), (c))
+# ifndef SETLOCALE
+# define SETLOCALE(category, locale) setlocale(category, locale)
+# endif /* ndef SETLOCALE */
+#else /* !_MBCS */
+# define CLEN(ptr) 1
+# define PREINCSTR(ptr) (++(ptr))
+# define POSTINCSTR(ptr) ((ptr)++)
+# define lastchar(ptr) ((*(ptr)=='\0') ? '\0' : ptr[strlen(ptr)-1])
+# define MBSCHR(str, c) strchr(str, c)
+# define MBSRCHR(str, c) strrchr(str, c)
+# ifndef SETLOCALE
+# define SETLOCALE(category, locale)
+# endif /* ndef SETLOCALE */
+#endif /* ?_MBCS */
+#define INCSTR(ptr) PREINCSTR(ptr)
+
+
+/* System independent replacement for "struct utimbuf", which is missing
+ * in many older OS environments.
+ */
+typedef struct ztimbuf {
+ time_t actime; /* new access time */
+ time_t modtime; /* new modification time */
+} ztimbuf;
+
+/* This macro round a time_t value to the OS specific resolution */
+#ifndef ROUNDED_TIME
+# define ROUNDED_TIME(time) (time)
+#endif
+
+/* Some systems define S_IFLNK but do not support symbolic links */
+#if defined (S_IFLNK) && defined(NO_SYMLINKS)
+# undef S_IFLNK
+#endif
+
+#ifndef Z_UINT4_DEFINED
+# if !defined(NO_LIMITS_H)
+# if (defined(UINT_MAX) && (UINT_MAX == 0xffffffffUL))
+ typedef unsigned int z_uint4;
+# define Z_UINT4_DEFINED
+# else
+# if (defined(ULONG_MAX) && (ULONG_MAX == 0xffffffffUL))
+ typedef unsigned long z_uint4;
+# define Z_UINT4_DEFINED
+# else
+# if (defined(USHRT_MAX) && (USHRT_MAX == 0xffffffffUL))
+ typedef unsigned short z_uint4;
+# define Z_UINT4_DEFINED
+# endif
+# endif
+# endif
+# endif /* !defined(NO_LIMITS_H) */
+#endif /* ndef Z_UINT4_DEFINED */
+#ifndef Z_UINT4_DEFINED
+ typedef ulg z_uint4;
+# define Z_UINT4_DEFINED
+#endif
+
+#ifndef FOPR /* fallback default definitions for FOPR, FOPM, FOPW: */
+# define FOPR "r"
+# define FOPM "r+"
+# define FOPW "w"
+#endif /* fallback definition */
+
+#ifndef FOPW_TMP /* fallback default for opening writable temp files */
+# define FOPW_TMP FOPW
+#endif
+
+/* Open the old zip file in exclusive mode if possible (to avoid adding
+ * zip file to itself).
+ */
+#ifdef OS2
+# define FOPR_EX FOPM
+#else
+# define FOPR_EX FOPR
+#endif
+
+
+/* MSDOS file or directory attributes */
+#define MSDOS_HIDDEN_ATTR 0x02
+#define MSDOS_DIR_ATTR 0x10
+
+
+/* Define this symbol if your target allows access to unaligned data.
+ * This is not mandatory, just a speed optimization. The compressed
+ * output is strictly identical.
+ */
+#if (defined(MSDOS) && !defined(WIN32)) || defined(i386)
+# define UNALIGNED_OK
+#endif
+#if defined(mc68020) || defined(vax)
+# define UNALIGNED_OK
+#endif
+
+#if (defined(SMALL_MEM) && !defined(CBSZ))
+# define CBSZ 2048 /* buffer size for copying files */
+# define ZBSZ 2048 /* buffer size for temporary zip file */
+#endif
+
+#if (defined(MEDIUM_MEM) && !defined(CBSZ))
+# define CBSZ 8192
+# define ZBSZ 8192
+#endif
+
+#ifndef CBSZ
+# define CBSZ 16384
+# define ZBSZ 16384
+#endif
+
+#ifndef SBSZ
+# define SBSZ CBSZ /* copy buf size for STORED entries, see zipup() */
+#endif
+
+#ifndef MEMORY16
+# ifdef __WATCOMC__
+# undef huge
+# undef far
+# undef near
+# endif
+# ifdef THEOS
+# undef far
+# undef near
+# endif
+# if (!defined(__IBMC__) || !defined(OS2))
+# ifndef huge
+# define huge
+# endif
+# ifndef far
+# define far
+# endif
+# ifndef near
+# define near
+# endif
+# endif
+# define nearmalloc malloc
+# define nearfree free
+# define farmalloc malloc
+# define farfree free
+#endif /* !MEMORY16 */
+
+#ifndef Far
+# define Far far
+#endif
+
+/* MMAP and BIG_MEM cannot be used together -> let MMAP take precedence */
+#if (defined(MMAP) && defined(BIG_MEM))
+# undef BIG_MEM
+#endif
+
+#if (defined(BIG_MEM) || defined(MMAP)) && !defined(DYN_ALLOC)
+# define DYN_ALLOC
+#endif
+
+
+/* LARGE_FILE_SUPPORT
+ *
+ * Types are in osdep.h for each port
+ *
+ * LARGE_FILE_SUPPORT and ZIP64_SUPPORT are automatically
+ * set in osdep.h (for some ports) based on the port and compiler.
+ *
+ * Function prototypes are below as OF is defined earlier in this file
+ * but after osdep.h is included. In the future ANSI prototype
+ * support may be required and the OF define may then go away allowing
+ * the function defines to be in the port osdep.h.
+ *
+ * E. Gordon 9/21/2003
+ * Updated 7/24/04 EG
+ */
+#ifdef LARGE_FILE_SUPPORT
+ /* 64-bit Large File Support */
+
+ /* Arguments for all functions are assumed to match the actual
+ arguments of the various port calls. As such only the
+ function names are mapped below. */
+
+/* ---------------------------- */
+# ifdef UNIX
+
+ /* Assume 64-bit file environment is defined. The below should all
+ be set to their 64-bit versions automatically. Neat. 7/20/2004 EG */
+
+ /* 64-bit stat functions */
+# define zstat stat
+# define zfstat fstat
+# define zlstat lstat
+
+# if defined(__alpha) && defined(__osf__) /* support for osf4.0f */
+ /* 64-bit fseek */
+# define zfseeko fseek
+
+ /* 64-bit ftell */
+# define zftello ftell
+
+# else
+ /* 64-bit fseeko */
+# define zfseeko fseeko
+
+ /* 64-bit ftello */
+# define zftello ftello
+# endif /* __alpha && __osf__ */
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif /* UNIX */
+
+/* ---------------------------- */
+# ifdef VMS
+
+ /* 64-bit stat functions */
+# define zstat stat
+# define zfstat fstat
+# define zlstat lstat
+
+ /* 64-bit fseeko */
+# define zfseeko fseeko
+
+ /* 64-bit ftello */
+# define zftello ftello
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif /* def VMS */
+
+/* ---------------------------- */
+# ifdef WIN32
+
+# if defined(__MINGW32__)
+ /* GNU C, linked against "msvcrt.dll" */
+
+ /* 64-bit stat functions */
+# define zstat _stati64
+# ifdef UNICODE_SUPPORT
+# define zwfstat _fstati64
+# define zwstat _wstati64
+# define zw_stat struct _stati64
+# endif
+# define zfstat _fstati64
+# define zlstat lstat
+
+ /* 64-bit fseeko */
+ /* function in win32.c */
+ int zfseeko OF((FILE *, zoff_t, int));
+
+ /* 64-bit ftello */
+ /* function in win32.c */
+ zoff_t zftello OF((FILE *));
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif
+
+# if defined(__CYGWIN__)
+ /* GNU C, CygWin with its own POSIX compatible runtime library */
+
+ /* 64-bit stat functions */
+# define zstat stat
+# define zfstat fstat
+# define zlstat lstat
+
+ /* 64-bit fseeko */
+# define zfseeko fseeko
+
+ /* 64-bit ftello */
+# define zftello ftello
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif
+
+# ifdef __WATCOMC__
+ /* WATCOM C */
+
+ /* 64-bit stat functions */
+# define zstat _stati64
+# ifdef UNICODE_SUPPORT
+# define zwfstat _fstati64
+# define zwstat _wstati64
+# define zw_stat struct _stati64
+# endif
+# define zfstat _fstati64
+# define zlstat lstat
+
+ /* 64-bit fseeko */
+ /* function in win32.c */
+ int zfseeko OF((FILE *, zoff_t, int));
+
+ /* 64-bit ftello */
+ /* function in win32.c */
+ zoff_t zftello OF((FILE *));
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif
+
+# ifdef _MSC_VER
+ /* MS C and VC */
+
+ /* 64-bit stat functions */
+# define zstat _stati64
+# ifdef UNICODE_SUPPORT
+# define zwfstat _fstati64
+# define zwstat _wstati64
+# define zw_stat struct _stati64
+# endif
+# define zfstat _fstati64
+# define zlstat lstat
+
+ /* 64-bit fseeko */
+ /* function in win32.c */
+ int zfseeko OF((FILE *, zoff_t, int));
+
+ /* 64-bit ftello */
+ /* function in win32.c */
+ zoff_t zftello OF((FILE *));
+
+ /* 64-bit fopen */
+# define zfopen fopen
+# define zfdopen fdopen
+
+# endif
+
+# ifdef __IBMC__
+ /* IBM C */
+
+ /* 64-bit stat functions */
+
+ /* 64-bit fseeko */
+ /* function in win32.c */
+ int zfseeko OF((FILE *, zoff_t, int));
+
+ /* 64-bit ftello */
+ /* function in win32.c */
+ zoff_t zftello OF((FILE *));
+
+ /* 64-bit fopen */
+
+# endif
+
+# endif /* WIN32 */
+
+#else
+ /* No Large File Support or default for 64-bit environment */
+
+# define zstat stat
+# define zfstat fstat
+# define zlstat lstat
+# define zfseeko fseek
+# define zftello ftell
+# define zfopen fopen
+# define zfdopen fdopen
+# ifdef UNICODE_SUPPORT
+# define zwfstat _fstat
+# define zwstat _wstat
+# define zw_stat struct _stat
+# endif
+
+#endif
+
+#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/2003 */
+
+# ifndef SSTAT
+# define SSTAT zstat
+# ifdef UNICODE_SUPPORT
+# define SSTATW zwstat
+# endif
+# endif
+# ifdef S_IFLNK
+# define LSTAT zlstat
+# define LSSTAT(n, s) (linkput ? zlstat((n), (s)) : SSTAT((n), (s)))
+# else
+# define LSTAT SSTAT
+# define LSSTAT SSTAT
+# ifdef UNICODE_SUPPORT
+# define LSSTATW SSTATW
+# endif
+# endif
+
+#else /* no LARGE_FILE_SUPPORT */
+
+# ifndef SSTAT
+# define SSTAT stat
+# endif
+# ifdef S_IFLNK
+# define LSTAT lstat
+# define LSSTAT(n, s) (linkput ? lstat((n), (s)) : SSTAT((n), (s)))
+# else
+# define LSTAT SSTAT
+# define LSSTAT SSTAT
+# ifdef UNICODE_SUPPORT
+# define LSSTATW SSTATW
+# endif
+# endif
+
+#endif
+
+
+/*---------------------------------------------------------------------*/
+
+
+/* 2004-12-01 SMS.
+ * Added fancy zofft() macros, et c.
+ */
+
+/* Default fzofft() format selection.
+ * Modified 2004-12-27 EG
+ */
+
+#ifndef FZOFFT_FMT
+# define FZOFFT_FMT ZOFF_T_FORMAT_SIZE_PREFIX /* printf for zoff_t values */
+
+# ifdef LARGE_FILE_SUPPORT
+# define FZOFFT_HEX_WID_VALUE "16" /* width of 64-bit hex values */
+# else
+# define FZOFFT_HEX_WID_VALUE "8" /* digits in 32-bit hex values */
+# endif
+
+#endif /* ndef FZOFFT_FMT */
+
+#define FZOFFT_HEX_WID ((char *) -1)
+#define FZOFFT_HEX_DOT_WID ((char *) -2)
+
+
+
+
+/* The following default definition of the second input for the crypthead()
+ * random seed computation can be used on most systems (all those that
+ * supply a UNIX compatible getpid() function).
+ */
+#ifdef ZCRYPT_INTERNAL
+# ifndef ZCR_SEED2
+# define ZCR_SEED2 (unsigned) getpid() /* use PID as seed pattern */
+# endif
+#endif /* ZCRYPT_INTERNAL */
+
+/* The following OS codes are defined in pkzip appnote.txt */
+#ifdef AMIGA
+# define OS_CODE 0x100
+#endif
+#ifdef VMS
+# define OS_CODE 0x200
+#endif
+/* unix 3 */
+#ifdef VM_CMS
+# define OS_CODE 0x400
+#endif
+#ifdef ATARI
+# define OS_CODE 0x500
+#endif
+#ifdef OS2
+# define OS_CODE 0x600
+#endif
+#ifdef MACOS
+# define OS_CODE 0x700
+#endif
+/* z system 8 */
+/* cp/m 9 */
+#ifdef TOPS20
+# define OS_CODE 0xa00
+#endif
+#ifdef WIN32
+# define OS_CODE 0xb00
+#endif
+#ifdef QDOS
+# define OS_CODE 0xc00
+#endif
+#ifdef RISCOS
+# define OS_CODE 0xd00
+#endif
+#ifdef VFAT
+# define OS_CODE 0xe00
+#endif
+#ifdef MVS
+# define OS_CODE 0xf00
+#endif
+#ifdef __BEOS__
+# define OS_CODE 0x1000
+#endif
+#ifdef TANDEM
+# define OS_CODE 0x1100
+#endif
+#ifdef THEOS
+# define OS_CODE 0x1200
+#endif
+/* Yes, there is a gap here. */
+#ifdef __ATHEOS__
+# define OS_CODE 0x1E00
+#endif
+
+#define NUM_HOSTS 31
+/* Number of operating systems. Should be updated when new ports are made */
+
+#if defined(DOS) && !defined(OS_CODE)
+# define OS_CODE 0x000
+#endif
+
+#ifndef OS_CODE
+# define OS_CODE 0x300 /* assume Unix */
+#endif
+
+/* can't use "return 0" from main() on VMS */
+#ifndef EXIT
+# define EXIT exit
+#endif
+#ifndef RETURN
+# define RETURN return
+#endif
+
+#ifndef ZIPERR
+# define ZIPERR ziperr
+#endif
+
+#if (defined(USE_ZLIB) && defined(MY_ZCALLOC))
+ /* special zcalloc function is not needed when linked against zlib */
+# undef MY_ZCALLOC
+#endif
+
+#if (!defined(USE_ZLIB) && !defined(MY_ZCALLOC))
+ /* Any system without a special calloc function */
+# define zcalloc(items,size) \
+ (zvoid far *)calloc((unsigned)(items), (unsigned)(size))
+# define zcfree free
+#endif /* !USE_ZLIB && !MY_ZCALLOC */
+
+/* end of tailor.h */
diff --git a/tandem/HISTORY b/tandem/HISTORY
new file mode 100644
index 0000000..59d3429
--- /dev/null
+++ b/tandem/HISTORY
@@ -0,0 +1,97 @@
+Tandem Port History
+===================
+
+Hi, I'm Dave Smith and I work at BP Oil UK, looking after their European card
+processing system since 1992. We need to send lots of files via FTP to other
+BP machines (Novell, NT, Sun...). Sending large files was frowned upon, so the
+search for a zip product was on.
+
+We tried the GZIP product from Twinsoft Netherlands but it was complicated to
+use and it was not widely known by other arts of BP.
+
+What we really wanted was a PKZIP compatible product, as this is a widely known
+product. By chance when surfing the web I discovered the Info-ZIP web site.
+This claimed PKZIP 2.04g compatibility and had a number of ports, was free, and
+even had source code, but unfortunately no Tandem version :-(
+
+Thus in the autumn 1996 I bit the bullet and took on the job of porting the
+code to Tandem NSK (Guardian). This meant dusting off my circa 1985 'C'
+programming skills and firing up the Tandem 'C' compiler - not known for its
+ease of use, especially debugging 8-; This was all on D30 by the way.
+
+To start this off I had to choose an existing port to base te Tandem one on.
+Nearest (?) was the VM-CMS/MVS port by George Petrov. The main similarity
+being that these machines are record based, and have a similarish filing system
+to Guardian.
+
+First to be tackled was ZIP. By the end of 1996 I had a version which compiled
+and ran (giving the program banner) - which seemed like a major acheivement at
+the time.
+
+In December 1996 I forwarded a version of ZIP to Info-ZIP which wor
+ked only on Edit files, and had no concept of directories. Became ZIP 2.1
+
+By March 1997 I had improved ZIP so that it could cope with Unstructured files
+as well (Became ZIP 2.2). I also had ported a version of UNZIP which could
+create Unstructured files (not Edit) - UNZIP 5.20
+
+At the start of September 1997 I sent UNZIP with Edit file support to Info-ZIP
+(incorporated into 5.32)
+
+In March 1998 I submitted file I/O improvements (SBB) for ZIP (2.3a)
+
+In August 1998 I added Tandem DEFINE processing for ZIP (2.3e). This was a
+feature required by BP to allow them to store files with a different internal
+name than the physical file being zipped (without renaming it).
+Also added storing of proper UTC timestamps which allow for DST & timezone.
+
+Also in August I added the same file I/O improvements for UNZIP (5.33f)
+
+I then added the ability to update the unzipped files last modified and last
+open timestamps - this required help from TNSC to allow me access to the
+priviliged procedure call. Also can give the files back to the original user
+by use of the '-X' flag.
+
+At the end of 1998 I was given the go ahead to add the zipping of Enscribe
+files. This first version stores all Enscribe file attributes EXCEPT SQL, alt
+key and partition information.
+
+ZIP now uses its own Guardian I/O (rather than the 'C'library) for the reading
+of files to be zipped.
+
+Unstructured files use Large Transfer mode and READ (56K or 30K reads)
+Edit files use IOEdit routines
+Enscribe files use READ and SBB and add LF to the end of each record.
+
+UNZIP has the ability to update the filecode of files restored to ther original
+value (Unstructured only)
+
+
+To Do ZIP
+===========
+1. Change I/O to use NSK/Large Transfer mode in fwrite of ZIP file itself- this
+ will dramaticaly speed up updating an existing zipfile. When updating an
+ existing zipfile it copies it to a temporary file currently using only SBB.
+2. Add raw binary mode to allow storing of raw data in zip file - e.g. only to
+ be unzipped on Tandem ! This is simplest/fastest way to provide full
+ Enscribe support for Tandem platform - with no cross-platform support.
+3. Add SQL support !!
+
+To Do UNZIP
+===========
+1. Re-write the I/O routines to use NSK to recreate the original Enscribe file
+ structure.
+2. Use NSK Large Transfer mode I/O for reading/writing of ZIP file
+3. Add raw binary mode to allow restoration of Tandem file from previous raw
+ data ZIP (see above)
+4. Add SQL support !!
+
+
+
+Current Versions on Website
+===========================
+
+ZIP 2.3
+UNZIP 5.5
+
+As of February 17th 2002
diff --git a/tandem/README b/tandem/README
new file mode 100644
index 0000000..f877aeb
--- /dev/null
+++ b/tandem/README
@@ -0,0 +1,95 @@
+Tandem Port of Info ZIP (zip)
+=======================
+
+History:
+1. Tidy up COMMACS/MACROS/MAKE
+2. Changes for version 5.32d affected files:
+- TANDEMC (changes to stat() for UNZIP)
+- ZIPUPC (changes to use REVISIOH rather than REVISEH)
+- ZIPFILEC (don't add ".zip" to ZIP name)
+- FILEIOC (cosmetic missing "*/")
+3. Fix to allow zipping of files called ZIP (e.g. DAVES.ZIP)
+03/08/98 2.3e Process Tandem DEFINE names - use define name as internal name
+ Remove BITSO from build of ZIPLIB
+ New DOIT macro for extracting files from archive
+17/08/98 2.3e Set USE_EF_UT_TIME to allow for timezone changes
+18/08/98 2.3e Use define LICENSED to build object able to update timestamps
+30/11/98 2.3h Updated mapname/chmod/in2ex, include licensing in MAKE
+21/12/98 2.3i Add simple Enscribe file handling, consisting of:
+ - storing Enscribe files as LF delimited text files
+ - adding Tandem Extra Field, holding Enscribe file attributes
+ Create ZIP file with Tandem File Code 1001
+ Rationalised TANDEMH and TANDEMC wth UNZIP 5.40d
+12/01/99 2.3i Correct bug stopping setting of last open timestamp
+25/01/99 2.3k Add '-B' flag to zip Enscribe files with no record delimiters
+26/01/99 2.3k Make CRLF the default delimiter for Structured and Text files
+01/02/99 2.3k Use maximum size large transfer read (57344) as default, allow
+ smaller value as option
+01/02/99 2.3k Redefine -B flag for Edit/Enscribe files as in table below.
+ Default (-B or -B0 or no flag) is add CR/LF
+
+ -B<number> options at present are:
+ Bit 0 - Don't add delimiter (Edit/Enscribe)
+ Bit 1 - Use LF rather than CR/LF as delimiter (Edit/Enscribe)
+ Bit 2 - Space fill record to max record length (Enscribe)
+ Bit 3 - Trim trailing space (Edit/Enscribe)
+
+ Bit 8 - Force 30K (Expand) large read for Unstructured files
+
+06/02/99 2.3k Attempt to catch Large Transfer mode failure (err 21) when
+ attempting 56K reads, add substitute 30K reads (Expand files)
+24/03/99 2.3m Split TANDEMC into TANDEMC/TANZIPC/TANUNZC
+24/03/99 2.3m Added TANNSKH to allow for declarations which require
+ structures defined in ZIPH after call to TANDEMH
+11/05/99 2.3m Change zopen in TANZIPC to allow opening of files with
+ missing alt keys (err 4)
+ Assume not DST if can't resolve time (no DST table available)
+27/09/99 2.3o Fixed bug in -B0 option causing files to be stored rather than
+ deflated. Created TANZIPH
+29/04/02 2.4g Fixed contention on temporary file when multiple ZIPs run
+
+A few notes about the files on this subvol
+
+COMMACS - used by MAKE (compiler)
+DOIT - macro to extract required Tandem files from archive and rename
+MACROS - used by MAKE (bind)
+MAKE - recompile ZIP code, attempts to only recompile changed code
+README - this file
+ZIPLIB - library of ZIP compiled routines, used by ZIP/ZIPNOTE etc
+ZIPL - ZIP object (bound using LARGE memory model)
+ZIPNOTE - ZIPNOTE object (bound using LARGE memory model)
+
+*C - Source file
+*H - Header files
+*O - Individual object files (when compiled by MAKE)
+
+Install Notes:
+==============
+Stage 1 - get ZIP object onto Tandem
+- download Tandem Zip executables archive from Web
+- using PC unzip program (e.g. pkunzip/WinZip) extract ZIP
+- copy ZIP from PC to Tandem in Binary mode s(FTP/IXF)
+- alter file code to 100
+- optionally place in $SYSTEM.SYSTEM to allow easy access from command line
+
+Stage 2 - (optional) compile source code (requires UNZIP on Tandem)
+- download ZIP source archive fwom web - contains all supported platforms
+- copy archive onto Tandem as Binary
+- extract Tandem DOIT macro ( UNZIP -j <archive> tandem/DOIT )
+- update DOIT macro to point at archive file
+- restore relevant files by running DOIT
+- NOTE that revision.h must be restored as REVISIOH
+- replace references to $T with a collector on your system
+- replace references to SUPER.DAVES with whatever user id you use
+- to compile run MAKE (compiles, accelerates, licences)
+- NOTE: Always run the accelerated object on TNS/R systems, otherwise
+ it runs extremely slow.
+
+
+Additional Notes - LICENSE the object:
+======================================
+If you wish to be able to update the last modified time of the zip file
+(-o option) you need to add the line "#define LICENSED" to the TANDEMH file.
+If you set this option then you MUST FUP LICENSE the file as SUPER.SUPER.
+This is a Tandem restriction since we have to call a PRIV procedure to update
+the file label. For ZIP the define is setup (default) in tandem.h
diff --git a/tandem/commacs b/tandem/commacs
new file mode 100644
index 0000000..31e91a1
--- /dev/null
+++ b/tandem/commacs
@@ -0,0 +1,94 @@
+?section CC ROUTINE
+#FRAME
+[#PUSH file stem src obj htime file prev time stime otime
+ comp out options sup buf col locn group
+]
+
+[#IF [#ARGUMENT /VALUE file/ WORD /SPACE/ END]]
+[#IF [#EMPTYV file] |THEN|
+ #OUTPUT Syntax: CC <file> <collector> <comp-options>
+ #RESET FRAMES
+ #RETURN
+]
+
+[#IF NOT [#FILEINFO /EXISTENCE/ [file]]
+|THEN|
+ #OUTPUT [file] does not exist !
+ #RESET FRAMES
+ #RETURN
+]
+
+#PUSH #DEFAULTS vol subvol
+#SETMANY vol subvol src, [#FILEINFO /VOLUME, SUBVOL, FILE/ [file]]
+VOLUME [vol].[subvol]
+
+#SETV stem file
+#CHARDEL stem [#CHARCOUNT stem]
+#SET obj [stem]O
+#SETV stem src
+#CHARDEL stem [#CHARCOUNT stem]
+
+[#IF [#ARGUMENT /VALUE out/ DEVICE END]]
+[#IF [#EMPTYV out] |THEN| #SET out $T.#C]
+
+#SETMANY col group, [#FILEINFO /VOLUME, SUBVOL/ [out]]
+#SET locn [group].[stem]
+#SET sup [#LOOKUPPROCESS /ANCESTOR/ [col]]
+
+#SET options [#REST]
+
+== Find newest Header file
+#SET htime 0
+#SET file [#FILENAMES /MAXIMUM 1/ *H]
+[#LOOP |WHILE| NOT [#EMPTYV file]
+|DO|
+ #SET time [#FILEINFO /MODIFICATION/ [file]]
+ [#IF time > htime |THEN| #SETV htime time]
+
+ #SETV prev file
+ #SET file [#FILENAMES /MAXIMUM 1, PREVIOUS [prev]/ *H]
+]
+
+#SET stime [#FILEINFO /MODIFICATION/ [src]]
+#SET otime [#FILEINFO /MODIFICATION/ [obj]]
+
+#SET comp 0
+
+[#IF otime < htime
+|THEN|
+ #OUTPUT Header file(s) changed since object [obj] compiled
+ #SET comp -1
+]
+
+[#IF otime < stime
+|THEN|
+ #OUTPUT Source file [src] changed since object [obj] compiled
+ #SET comp -1
+]
+
+[#IF comp
+|THEN|
+ SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS,DELETE !
+ #SET buf
+ #OUTPUT Compiling [src]... [options]
+ C /IN [src], OUT [out].[stem]/[obj];SYMBOLS,HIGHPIN [options]
+ [#CASE [tacl^completioncode]
+ | 0 |
+ #OUTPUT Compiled OK: [src]
+ SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS,DELETE !
+ #SET _completion:completioncode 0
+ | 1 |
+ #OUTPUT [src]: Compile Warnings
+ SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS
+ #OUTPUTV buf
+ |OTHERWISE|
+ #OUTPUT [src]: Compile FAILED !
+ SPOOLCOM /OUTV buf/ OPEN [sup];JOB (OWNER, LOC [locn]),STATUS
+ #OUTPUTV buf
+ ]
+|ELSE|
+ #OUTPUT Object file [obj] is up to date
+ #SET _completion:completioncode 0
+]
+
+#UNFRAME
diff --git a/tandem/doit b/tandem/doit
new file mode 100644
index 0000000..1388730
--- /dev/null
+++ b/tandem/doit
@@ -0,0 +1,21 @@
+?tacl macro
+#frame
+#push zipfile
+#SET zipfile [#FILEINFO /SUBVOL/ A]
+
+unzip -a [zipfile] *.c -x */*
+== Following not required
+RENAME apic apicz
+RENAME timezonc timezonz
+
+unzip -a [zipfile] *.h -x */*
+== Following not required
+RENAME apih apizh
+
+unzip -aj [zipfile] tandem/*.h
+
+unzip -aj [zipfile] tandem/*.c
+
+unzip -aj [zipfile] tandem/* -x tandem/*.*
+
+#unframe
diff --git a/tandem/macros b/tandem/macros
new file mode 100644
index 0000000..ab1505b
--- /dev/null
+++ b/tandem/macros
@@ -0,0 +1,571 @@
+?section ADD^LIST routine
+[#IF [#ARGUMENT /VALUE item/ WORD/SPACE/]]
+#APPEND bin ADD * FROM [item]
+#SET itime [#FILEINFO /MODIFICATION/ [item]]
+[#IF itime > ntime |THEN| #SETV ntime itime]
+
+?section BBZIPLIB MACRO
+#FRAME
+#push bin item ntime itime libtime
+#SET ntime 0
+
+#OUTPUT Building [lib]
+#APPEND bin CLEAR
+add^list CRC32O
+add^list CRYPTO
+add^list DEFLATEO
+add^list FILEIOO
+add^list GLOBALSO
+add^list TANDEMO
+add^list TANZIPO
+add^list TREESO
+add^list TTYIOO
+add^list UTILO
+add^list ZIPFILEO
+add^list ZIPUPO
+#APPEND bin INFO UNRESOLVED *
+#APPEND bin BUILD [lib] ! , LIST * OFF
+
+#SET libtime [#FILEINFO /MODIFICATION/ [lib]]
+[#IF libtime < ntime
+|THEN|
+ #OUTPUT [lib] needs re-building
+ BIND /NAME,INV BIN/
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Bound [lib] OK
+ | 1 | #OUTPUT [lib]: BIND Failed with Warnings
+ | OTHERWISE | #OUTPUT [lib]: BIND Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT [lib] is up to date
+]
+
+#UNFRAME
+
+?section BBZIP MACRO
+#FRAME
+#push bin ziptime build
+#SET build 0
+#OUTPUT Building %1% with %2% memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM ZIPO
+#APPEND bin select search ($system.system.c%2%, [lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1% !
+
+#SET ziptime [#FILEINFO /MODIFICATION/ %1%]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ ZIPO] |THEN|
+ #OUTPUT %1% is older than ZIPO
+ #SET build -1
+]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+ #OUTPUT %1% is older than [lib]
+ #SET build -1
+]
+[#IF build
+|THEN|
+ #OUTPUT %1% is out of date, re-building
+ BIND /NAME,INV BIN/
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Bound %1% OK
+ | 1 | #OUTPUT %1%: BIND Failed with Warnings
+ | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+?section BBANY MACRO
+#FRAME
+#push bin memory anytime build
+#SET build 0
+#SETMANY memory, %2% LARGE
+#OUTPUT Building %1% with [memory] memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM %1%O
+#APPEND bin select search ($system.system.c[memory],[lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1% !
+
+#SET anytime [#FILEINFO /MODIFICATION/ %1%]
+[#IF anytime < [#FILEINFO /MODIFICATION/ %1%O] |THEN|
+ #OUTPUT %1% is older than %1%O
+ #SET build -1
+]
+[#IF anytime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+ #OUTPUT %1% is older than [lib]
+ #SET build -1
+]
+[#IF build
+|THEN|
+ #OUTPUT %1% is out of date, re-building
+ BIND /NAME,INV BIN/
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Bound %1% OK
+ | 1 | #OUTPUT %1%: BIND Failed with Warnings
+ | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+
+?section BBUNZIPLIB MACRO
+#FRAME
+#push bin item ntime itime libtime
+#SET ntime 0
+
+#OUTPUT Building [lib]
+#APPEND bin CLEAR
+add^list CRC32O
+add^list CRYPTO
+add^list ENVARGSO
+add^list EXPLODEO
+add^list EXTRACTO
+add^list FILEIOO
+add^list GLOBALSO
+add^list INFLATEO
+add^list LISTO
+add^list MATCHO
+add^list PROCESSO
+add^list TANDEMO
+add^list TANUNZO
+add^list TTYIOO
+add^list UNSHRINO
+add^list ZIPINFOO
+#APPEND bin INFO UNRESOLVED *
+#APPEND bin BUILD [lib] ! , LIST * OFF
+
+#SET libtime [#FILEINFO /MODIFICATION/ [lib]]
+[#IF libtime < ntime
+|THEN|
+ #OUTPUT [lib] needs re-building
+ BIND /NAME,INV BIN/
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Bound [lib] OK
+ | 1 | #OUTPUT [lib]: BIND Failed with Warnings
+ | OTHERWISE | #OUTPUT [lib]: BIND Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT [lib] is up to date
+]
+
+#UNFRAME
+
+?section BBUNZIP MACRO
+#FRAME
+#push bin ziptime build
+#SET build 0
+#OUTPUT Building %1% with %2% memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM UNZIPO
+#APPEND bin select search ($system.system.c%2%,[lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1% !
+
+#SET ziptime [#FILEINFO /MODIFICATION/ %1%]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ UNZIPO] |THEN|
+ #OUTPUT %1% is older than UNZIPO
+ #SET build -1
+]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+ #OUTPUT %1% is older than [lib]
+ #SET build -1
+]
+[#IF build
+|THEN|
+ #OUTPUT %1% is out of date, re-building
+ BIND /NAME,INV BIN/
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Bound %1% OK
+ | 1 | #OUTPUT %1%: BIND Failed with Warnings
+ | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+?section BBSFXLIB MACRO
+#FRAME
+#push bin item ntime itime libtime
+#SET ntime 0
+
+#OUTPUT Building [lib]
+#APPEND bin CLEAR
+add^list CRC32O
+add^list EXTRACTX
+add^list FILEIOX
+add^list GLOBALSX
+add^list INFLATEX
+add^list MATCHX
+add^list PROCESSX
+add^list TANDEMX
+add^list TANUNZX
+add^list TTYIOX
+#APPEND bin INFO UNRESOLVED *
+#APPEND bin BUILD [lib] ! , LIST * OFF
+
+#SET libtime [#FILEINFO /MODIFICATION/ [lib]]
+[#IF libtime < ntime
+|THEN|
+ #OUTPUT [lib] needs re-building
+ BIND /NAME,INV BIN/
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Bound [lib] OK
+ | 1 | #OUTPUT [lib]: BIND Failed with Warnings
+ | OTHERWISE | #OUTPUT [lib]: BIND Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT [lib] is up to date
+]
+
+#UNFRAME
+
+?section BBSFX MACRO
+#FRAME
+#push bin ziptime build
+#SET build 0
+#OUTPUT Building %1% with %2% memory model
+#APPEND bin CLEAR
+#APPEND bin ADD * FROM UNZIPX
+#APPEND bin select search ($system.system.c%2%,[lib])
+#APPEND bin select runnable object on
+#APPEND bin select list * off
+#APPEND bin set heap 20 pages
+#APPEND bin set symbols on
+#APPEND bin set saveabend on
+#APPEND bin set inspect on
+#APPEND bin info unresolved *
+#APPEND bin BUILD %1% !
+
+#SET ziptime [#FILEINFO /MODIFICATION/ %1%]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ UNZIPX] |THEN|
+ #OUTPUT %1% is older than UNZIPX
+ #SET build -1
+]
+[#IF ziptime < [#FILEINFO /MODIFICATION/ [lib]] |THEN|
+ #OUTPUT %1% is older than [lib]
+ #SET build -1
+]
+[#IF build
+|THEN|
+ #OUTPUT %1% is out of date, re-building
+ BIND /NAME,INV BIN/
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Bound %1% OK
+ | 1 | #OUTPUT %1%: BIND Failed with Warnings
+ | OTHERWISE | #OUTPUT %1%: BIND Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT %1% is up to date, no re-build required
+]
+
+#UNFRAME
+
+?section accel^file MACRO
+#FRAME
+#PUSH buf
+[#IF [#FILEINFO /MODIFICATION/ %1%]
+ > [#FILEINFO /MODIFICATION/ %2%]
+|THEN|
+ #OUTPUT %2% is older than %1%
+ #OUTPUT Accelerating %1% to %2%
+ AXCEL /OUTV buf/ %1%,%2%
+ #OUTPUTV buf
+ [#CASE [tacl^completioncode]
+ | 0 | #OUTPUT Accelerated %2% OK
+ | 1 | #OUTPUT %2%: AXCEL Failed with Warnings
+ | OTHERWISE | #OUTPUT %2%: AXCEL Failed with ERRORS !
+ ]
+|ELSE|
+ #OUTPUT %2% is up to date
+]
+
+#UNFRAME
+
+?section fup^license ROUTINE
+#FRAME
+#PUSH #DEFAULTS filename old^user current^user
+
+[#IF [#ARGUMENT /VALUE filename/ FILENAME]]
+
+#SET old^user [#USERNAME [#PROCESSINFO /PAID/]]
+#SETV current^user old^user
+[#LOOP |WHILE| current^user '<>' "SUPER.SUPER"
+ AND NOT [#INPUTEOF]
+|DO|
+ #OUTPUT Please log on as SUPER.SUPER (CTRL-Y aborts)
+ logon SUPER.SUPER
+ #SET current^user [#USERNAME [#PROCESSINFO /PAID/]]
+ #OUTPUT
+]
+
+[#IF current^user '=' "SUPER.SUPER" |THEN|
+ #OUTPUT Licensing [filename]
+ $SYSTEM.SYSTEM.FUP LICENSE [filename]
+]
+
+[#LOOP |WHILE| current^user '<>' old^user
+ AND NOT [#INPUTEOF]
+|DO|
+ #OUTPUT Please log on as [old^user] (CTRL-Y aborts)
+ logon [old^user]
+ #SET current^user [#USERNAME [#PROCESSINFO /PAID/]]
+ #OUTPUT
+]
+
+#UNFRAME
+
+
+?section CODE routine
+#FRAME
+#PUSH delta arg
+
+#SET /TYPE delta/ DELTA
+
+[#LOOP |WHILE| [#COMPUTE [#ARGUMENT /VALUE arg/ NUMBER END] = 1 ]
+|DO|
+ #APPEND DELTA [arg]I
+]
+
+#RESULT [#DELTA /COMMANDS DELTA/]
+
+#UNFRAME
+
+
+?section TACL^COMPLETIONCODE routine
+#RESULT [_completion:completioncode]
+
+?SECTION INCREMENT routine
+#FRAME
+#PUSH increment_variable increment_value
+
+[#IF [#ARGUMENT /VALUE increment_variable/ VARIABLE]]
+[#IF [#EMPTYV [increment_variable]]|THEN|#SET [increment_variable] 0]
+[#IF [#MORE]
+ |THEN|
+ [#IF [#ARGUMENT /VALUE increment_value/ NUMBER]]
+ |ELSE|
+ #SET increment_value 1
+]
+[#IF [#ARGUMENT END]]
+
+#SET [increment_variable] [#COMPUTE [increment_variable] + [increment_value]]
+
+#UNFRAME
+
+?section ERROR^IN^FUP^OUTPUT routine
+#FRAME
+#PUSH err output last line type
+
+#SETMANY err output, 0 0
+
+[#LOOP |WHILE| NOT [#EMPTYV fup^out]
+|DO|
+ #EXTRACTV fup^out line
+ [#SETMANY type, [#CHARGET line 1 TO 7] .]
+ [#CASE [type]
+ | ERROR | #SETMANY output err, -1 -1
+ | WARNING | #SET output -1
+ | OTHERWISE |
+ ]
+ [#IF output |THEN|
+ #OUTPUTV last
+ #OUTPUTV line
+ #SET output 0
+ #EXTRACTV fup^out line
+ ]
+ #SETV last line
+]
+
+#RESULT [err]
+
+#UNFRAME
+
+?section SECURE^FILE routine
+#FRAME
+
+[#DEF fup^out TEXT |BODY|]
+[#DEF fup^buf TEXT |BODY|]
+
+[#DEF fup^cmd MACRO |BODY|
+ FUP /OUTV fup^out/ %*%
+ #SETV fup^buf fup^out
+ [#IF [error^in^fup^output]
+ |THEN|
+ #OUTPUT Error detected in FUP output, ABORTING !!
+ #OUTPUT ..............................................................
+ #OUTPUTV fup^buf
+ #OUTPUT ..............................................................
+ #RAISE _BREAK
+ ]
+]
+
+[#DEF display^action MACRO |BODY|
+ [#IF NOT action |THEN|
+ #OUTPUT /HOLD/ Updating [file] ...
+ #SET action -1
+ #SET count 0
+ ]
+ #OUTPUT /COLUMN 3/ ... %*%
+]
+
+[#DEF display^noaction MACRO |BODY|
+ [#IF count
+ |THEN|
+ increment count
+ |ELSE|
+ #OUTPUT
+ #SET count 1
+ ]
+ [#IF count |THEN|
+ #OUTPUT /COLUMN [count]/ [code 27]A.
+ [#IF count > 75
+ |THEN|
+ #SET count 0
+ ]
+ ]
+]
+
+[#DEF process^file TEXT |BODY|
+ #SET action 0
+ #SETMANY cur^owner cur^security cur^license cur^progid, &
+ [#FILEINFO /OWNER, SECURITY, LICENSED, PROGID/ [file]]
+
+ #SET cur^owner [#USERNAME [cur^owner]]
+
+ [#IF NOT [#EMPTYV owner]
+ |THEN|
+ [#IF owner '<>' cur^owner
+ |THEN|
+ display^action giving to [owner] (was [cur^owner])
+ fup^cmd GIVE [file], [owner]
+ [#IF cur^progid
+ |THEN|
+ #OUTPUT /COLUMN 3/... WARNING! Loss of PROGID flag
+ #SET cur^progid 0
+ ]
+ ]
+ ]
+ [#IF NOT [#EMPTYV security]
+ |THEN|
+ [#IF security '<>' cur^security
+ |THEN|
+ display^action securing to [security] (was [cur^security])
+ fup^cmd SECURE [file], [security]
+ ]
+ ]
+ [#IF license |THEN|
+ [#IF NOT cur^license
+ |THEN|
+ display^action licensed
+ fup^cmd LICENSE [file]
+ ]
+ ]
+ [#IF progid |THEN|
+ [#IF NOT cur^progid
+ |THEN|
+ display^action PROGID flag set
+ fup^cmd SECURE [file],, PROGID
+ ]
+ ]
+ [#IF action
+ |THEN|
+ fup^cmd INFO [file]
+ |ELSE|
+ [#IF tflag
+ |THEN|
+ display^noaction
+ |ELSE|
+ #OUTPUT /HOLD/ Unchanged : [file]
+ [#IF cur^progid |THEN| #OUTPUT /COLUMN 39,HOLD/ P]
+ [#IF cur^license |THEN| #OUTPUT /COLUMN 40,HOLD/ L]
+ #OUTPUTV /COLUMN 43,HOLD/ cur^security
+ #OUTPUTV /COLUMN 50,HOLD/ cur^owner
+ #OUTPUT
+ ]
+ ]
+]
+
+#PUSH arg template file security owner progid license prev action count tflag
+#PUSH cur^security cur^owner cur^license cur^progid
+
+#SETMANY license progid, 0 0
+#SET count 0
+#SET tflag 0
+
+[#LOOP |WHILE| [#MORE]
+|DO|
+ [#CASE [#ARGUMENT /VALUE arg/ FILENAME
+ USER /USERNAME/
+ USER
+ SECURITY
+ KEYWORD /WORDLIST LICENSE/
+ KEYWORD /WORDLIST PROGID/
+ TEMPLATE
+ ]
+ | 1 | #SETV file arg
+ | 2 | #SETV owner arg
+ | 3 | #SET owner [#USERNAME [arg]]
+ | 4 | #SETV security arg
+ | 5 | #SET license -1
+ | 6 | #SET progid -1
+ | 7 | #SETV template arg
+ ]
+]
+[#IF [#ARGUMENT END]]
+
+
+[#IF [#EMPTYV template]
+|THEN|
+ #SETV template file
+|ELSE|
+ #SET tflag -1
+ #OUTPUT /HOLD/ Template : [template]
+ [#IF progid |THEN| #OUTPUT /COLUMN 39,HOLD/ P]
+ [#IF license |THEN| #OUTPUT /COLUMN 40,HOLD/ L]
+ [#IF NOT [#EMPTYV security] |THEN| #OUTPUTV /HOLD/ " "[security]""]
+ [#IF NOT [#EMPTYV owner] |THEN| #OUTPUTV /HOLD/ " [owner]"]
+ #OUTPUT
+]
+
+[#IF [#EMPTYV template]
+|THEN|
+ #OUTPUT ERROR! No filename specified
+ #RESET FRAMES
+ #RETURN
+|ELSE|
+ #SET file [#FILENAMES /MAXIMUM 1/ [template]]
+ [#LOOP |WHILE| NOT [#EMPTYV file]
+ |DO|
+ process^file
+ #SETV prev file
+ #SET file [#FILENAMES /MAXIMUM 1, PREVIOUS [prev]/ [template]]
+ ]
+]
+
+#UNFRAME
diff --git a/tandem/make b/tandem/make
new file mode 100644
index 0000000..84efb4d
--- /dev/null
+++ b/tandem/make
@@ -0,0 +1,130 @@
+?tacl routine
+#FRAME
+SINK [#LOAD /keep 1/ commacs]
+SINK [#LOAD /keep 1/ macros]
+
+[#PUSH file prev memory clib OK model zip lib accel unlicensed licensed
+ options fileset nocrypt crypt
+]
+#PUSH #DEFAULTS
+
+#SET OK -1
+
+[#IF [#ARGUMENT /VALUE memory/ KEYWORD /WORDLIST LARGE SMALL/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE model/ KEYWORD /WORDLIST NOWIDE WIDE/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE unlicensed/ KEYWORD /WORDLIST UNLICENSED/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE nocrypt/ KEYWORD /WORDLIST NOCRYPT/ OTHERWISE ]]
+[#IF [#ARGUMENT /VALUE fileset/ TEMPLATE FILENAME OTHERWISE ]]
+
+[#IF [#EMPTYV memory] |THEN| #SET memory LARGE]
+[#IF [#EMPTYV model] |THEN| #SET model NOWIDE]
+
+[#IF model '=' "WIDE"
+ |THEN| #SETV clib model
+ |ELSE| #SETV clib memory
+]
+
+[#IF model '=' "WIDE"
+|THEN|
+ #SET zip ZIPW
+|ELSE|
+ #SET zip ZIPL
+]
+#SET lib [zip]B
+#SET accel ZIP
+#SET options [options], [model]
+
+[#IF unlicensed '=' "UNLICENSED"
+|THEN|
+ #SET zip [zip]U
+ #SET accel [accel]U
+ #SET lib [lib]U
+|ELSE|
+ #SET licensed LICENSED
+ #SET options [options], define [licensed]
+]
+
+[#IF nocrypt '=' "NOCRYPT"
+|THEN|
+|ELSE|
+ #SET crypt USE_CRYPT
+ #SET options [options], define [crypt]
+]
+
+[#IF [#EMPTYV fileset] |THEN| #SET fileset *C]
+
+#OUTPUT Files to compile: [fileset]
+#OUTPUT Pointer Model : [model]
+#OUTPUT Memory Model : [memory]
+#OUTPUT C Library : [clib]
+#OUTPUT Axcel Object : [accel]
+#OUTPUT Run Object : [zip]
+#OUTPUT Library Object : [lib]
+#OUTPUT Compile Options : [options]
+#OUTPUT
+
+#SET file [#FILENAMES /MAXIMUM 1/ [fileset]]
+[#loop |while| NOT [#EMPTYV file]
+|do|
+ #SETV prev file
+ CC [file] $T.#ZIP [options]
+ [#IF [tacl^completioncode] > 1 |THEN| #set OK 0 ]
+ #SET file [#FILENAMES /MAXIMUM 1, PREVIOUS [prev]/ [fileset]]
+]
+
+[#IF OK |THEN|
+ BBZIPLIB
+ [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+#PUSH #PROCESSFILESECURITY
+VOLUME ,"NUNU"
+
+[#IF OK |THEN|
+ BBZIP [zip] [clib]
+ [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+[#IF OK |THEN|
+ secure^file [accel] "UUUU" SUPER.DAVES
+ accel^file [zip] [accel]
+ [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+[#IF OK
+ |THEN| #OUTPUT Successfully produced Accelerated Object [accel]
+ secure^file [accel] "UUUU" SUPER.DAVES
+ [#IF [#INTERACTIVE] |THEN|
+ [#IF licensed '=' "LICENSED" |THEN|
+ #OUTPUT [accel] will not run without being LICENSED
+ [#IF [#FILEINFO /LICENSED/ [accel]]
+ |THEN|
+ #OUTPUT [accel] already LICENSED
+ |ELSE|
+ [#IF [#MATCH Y* [#INPUT [accel] License [accel] ?]] |THEN|
+ fup^license [accel]
+ ]
+ ]
+ ]
+ ]
+ |ELSE| #OUTPUT Failed to produce Accelerated Object [accel]
+]
+
+#OUTPUT Finished
+
+#OUTPUT Setting up additonal utilities
+== ZIPNOTE
+CC ZIPNOTEC $T.#ZIP [options]
+#SET zip ZIPNOTE
+#SET accel ZIPNOTE
+[#IF OK |THEN|
+ BBANY [zip] [clib]
+ [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+[#IF OK |THEN|
+ secure^file [accel] "UUUU" SUPER.DAVES
+ accel^file [zip] [accel]
+ [#IF [tacl^completioncode] > 0 |THEN| #SET OK 0]
+]
+
+#UNFRAME
diff --git a/tandem/tandem.c b/tandem/tandem.c
new file mode 100644
index 0000000..0aa1e06
--- /dev/null
+++ b/tandem/tandem.c
@@ -0,0 +1,889 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * routines common to TANDEM (ZIP and UNZIP)
+ */
+
+#include "zip.h" /* This sets up ZIP / UNZIP define */
+
+#include <tal.h>
+#include "$system.zsysdefs.zsysc" nolist
+#include <cextdecs> nolist
+#include "tannsk.h"
+
+static time_t gmt_to_time_t (long long *);
+
+int isatty (fnum)
+int fnum;
+{
+ return 1;
+}
+
+/********************/
+/* Function in2ex() */
+/********************/
+
+#ifdef UNZIP
+char *in2ex(__G__ n)
+ __GDEF
+#else
+char *in2ex(n)
+#endif
+ char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name buffer */
+ char *y; /* pointer to external buffer */
+ char *max; /* pointer to max end of next file part */
+ char *t; /* pointer to internal - start of substring */
+ char *p; /* pointer to internal - TANDEM delimiter */
+ char *e; /* pointer to internal - DOS extension delimiter */
+ char *z; /* pointer to internal - end of substring */
+ int len; /* length of substring to copy to external name */
+ int allow_dollar; /* $ symbol allowed as next character */
+
+ if ((x = malloc(strlen(n) + 4)) == NULL) /* + 4 for safety */
+ return NULL;
+
+ *x = '\0';
+
+ /* Junk pathname as requested */
+#ifdef UNZIP
+ if (uO.jflag && (t = strrchr(n, INTERNAL_DELIMITER)) != NULL)
+ ++t;
+ else
+ t = n;
+#endif /* UNZIP */
+#ifdef ZIP
+ if (!pathput)
+ t = last(n, INTERNAL_DELIMITER);
+ else
+ t = n;
+#endif /* ZIP */
+
+ allow_dollar = TRUE;
+
+ while (*t != '\0') { /* File part could be sys, vol, subvol or file */
+ if (*t == INTERNAL_DELIMITER) { /* System, Volume or Subvol Name */
+ t++;
+ if (*t == INTERNAL_DELIMITER) { /* System */
+ strcat(x, TANDEM_NODE_STR);
+ t++;
+ }
+ else {
+ strcat(x, TANDEM_DELIMITER_STR);
+ allow_dollar = FALSE;
+ }
+ }
+ /* Work out where end of current external string is */
+ y = x + strlen(x);
+
+ /* Work out substring to copy and externalise */
+ p = strchr(t, INTERNAL_DELIMITER);
+ e = strchr(t, DOS_EXTENSION);
+ if (p != NULL) {
+ if (e > p)
+ e = NULL;
+ }
+
+ z = e;
+ if (z == NULL)
+ z = p;
+ if (z == NULL)
+ z = t + strlen(t);
+
+ /* can't have Tandem name longer than 8 characters */
+ max = y + MAXFILEPARTLEN;
+
+ /* Allow $ symbol as first character in some cases */
+ if (*t == '$') {
+ if (allow_dollar)
+ *y++ = *t++;
+ else;
+ *t++;
+ }
+
+ /* Make sure first real character is alpha */
+ if (! isalpha(*t) )
+ *y++ = 'A';
+
+ /* Characters left to process */
+ len = z - t;
+
+ while ( len > 0 ) {
+ if ( isalnum(*t) ) {
+ *y++ = toupper(*t++);
+ if (y >= max)
+ break;
+ }
+ else
+ t++;
+ len--;
+ }
+ *y = '\0';
+ t = p;
+
+ if (p == NULL) {
+ /* Last part of filename, store pseudo extension if available */
+ if (e != NULL) {
+ strcat(x, TANDEM_EXTENSION_STR);
+ y = x + strlen(x);
+
+ /* no restriction on extension length as its virtual */
+ z = e + 1;
+ while ( *z != '\0' ) {
+ *y++ = toupper(*z++);
+ }
+ *y = '\0';
+ }
+ break;
+ }
+ }
+
+ return x;
+}
+
+void zexit(status)
+ int status;
+{
+ /* Exit(>0) creates saveabend files */
+ terminate_program (0,0,(short)status,,,);
+}
+
+/************************/
+/* Function zputc() */
+/************************/
+
+#ifdef putc
+# undef putc
+#endif
+
+int zputc(ch, fptr)
+ int ch;
+ FILE *fptr;
+{
+ int err;
+ err = putc(ch,fptr);
+ fflush(fptr);
+ return err;
+}
+#define putc zputc
+
+#ifdef LICENSED
+_tal _priv short FILE_CHANGELABEL_ (
+ short, /* IN */
+ short, /* IN */
+ const short _far * /* IN */
+ );
+
+_c _callable int changelabel OF((short, const short *, const short *));
+
+_c _callable int changelabel(fnum, modtime, actime)
+ short fnum;
+ const short *modtime;
+ const short *actime;
+{
+ int err;
+
+ err = FILE_CHANGELABEL_(fnum, 16, modtime);
+ if (!err)
+ err = FILE_CHANGELABEL_(fnum, 17, actime);
+ return err;
+}
+
+int islicensed(void)
+{
+ #define plist_items 1
+ #define plist_size 10
+
+ short myphandle[ZSYS_VAL_PHANDLE_WLEN];
+ short licensetag[plist_items] = {37};
+ short licensed[plist_size];
+ short maxlen = plist_size;
+ short items = plist_items;
+ short resultlen[1], err;
+
+ err = PROCESSHANDLE_NULLIT_(myphandle);
+
+ if (!err)
+ err = PROCESS_GETINFO_(myphandle);
+
+ if (!err)
+ err = PROCESS_GETINFOLIST_(/*cpu*/,
+ /*pin*/,
+ /*nodename*/,
+ /*nodenamelen*/,
+ myphandle,
+ licensetag,
+ items,
+ licensed,
+ maxlen,
+ resultlen
+ );
+
+ if (err != 0)
+ return 0;
+ else
+ return licensed[0];
+}
+#endif /* LICENSED */
+
+int utime(file, time)
+ const char *file;
+ const ztimbuf *time;
+{
+#ifdef LICENSED
+ int result, err;
+ union timestamp_ov {
+ long long fulltime;
+ short wordtime[4];
+ };
+ union timestamp_ov lasttime, opentime;
+ struct tm *modt, *opent;
+ short datetime[8], errormask[1];
+ short len, fnum, access, exclus, options;
+ char fname[FILENAME_MAX + 1];
+ short extension;
+ char ext[EXTENSION_MAX + 1];
+
+ if (islicensed() ) {
+ /* Attempt to update file label */
+ modt = gmtime( &time->modtime );
+
+ datetime[0] = modt->tm_year + 1900;
+ datetime[1] = modt->tm_mon + 1;
+ datetime[2] = modt->tm_mday;
+ datetime[3] = modt->tm_hour;
+ datetime[4] = modt->tm_min;
+ datetime[5] = modt->tm_sec;
+ datetime[6] = datetime[7] = 0;
+ errormask[0] = 0;
+ lasttime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
+
+ opent = gmtime( &time->actime );
+
+ datetime[0] = opent->tm_year + 1900;
+ datetime[1] = opent->tm_mon + 1;
+ datetime[2] = opent->tm_mday;
+ datetime[3] = opent->tm_hour;
+ datetime[4] = opent->tm_min;
+ datetime[5] = opent->tm_sec;
+ datetime[6] = datetime[7] = 0;
+ errormask[0] = 0;
+ opentime.fulltime = COMPUTETIMESTAMP (datetime, errormask);
+
+ /* Remove any (pseudo) file extension */
+ extension = parsename (file,fname,ext);
+ len = strlen(fname);
+
+ access = NSK_WRONLY;
+ exclus = NSK_SHARED;
+ options = NSK_NOUPDATEOPENTIME;
+
+ extension = parsename (file,fname,ext);
+ len = strlen(fname);
+
+ err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
+ result = changelabel(fnum,lasttime.wordtime,opentime.wordtime);
+ err = FILE_CLOSE_(fnum);
+ return result;
+ }
+ return -1;
+#else /* !LICENSED */
+ return 0; /* "no error", to suppress annoying failure messages */
+#endif /* ?LICENSED */
+}
+
+/* TANDEM version of chmod() function */
+
+int chmod(file, unix_sec)
+ const char *file;
+ mode_t unix_sec;
+{
+ FILE *stream;
+ struct nsk_sec_type {
+ unsigned progid : 1;
+ unsigned clear : 1;
+ unsigned null : 2;
+ unsigned read : 3;
+ unsigned write : 3;
+ unsigned execute: 3;
+ unsigned purge : 3;
+ };
+ union nsk_sec_ov {
+ struct nsk_sec_type bit_ov;
+ short int_ov;
+ };
+ union nsk_sec_ov nsk_sec;
+ short fnum, err, nsk_sec_int;
+ short len, access, exclus, extension, options;
+ char fname[FILENAME_MAX + 1];
+ char ext[EXTENSION_MAX + 1];
+
+ nsk_sec.bit_ov.progid = 0;
+ nsk_sec.bit_ov.clear = 0;
+ nsk_sec.bit_ov.null = 0;
+
+ /* 4="N", 5="C", 6="U", 7="-" */
+
+ if (unix_sec & S_IROTH) nsk_sec.bit_ov.read = 4;
+ else if (unix_sec & S_IRGRP) nsk_sec.bit_ov.read = 5;
+ else if (unix_sec & S_IRUSR) nsk_sec.bit_ov.read = 6;
+ else nsk_sec.bit_ov.read = 7;
+
+ if (unix_sec & S_IWOTH) nsk_sec.bit_ov.write = 4;
+ else if (unix_sec & S_IWGRP) nsk_sec.bit_ov.write = 5;
+ else if (unix_sec & S_IWUSR) nsk_sec.bit_ov.write = 6;
+ else nsk_sec.bit_ov.write = 7;
+
+ if (unix_sec & S_IXOTH) nsk_sec.bit_ov.execute = 4;
+ else if (unix_sec & S_IXGRP) nsk_sec.bit_ov.execute = 5;
+ else if (unix_sec & S_IXUSR) nsk_sec.bit_ov.execute = 6;
+ else nsk_sec.bit_ov.execute = 7;
+
+ nsk_sec.bit_ov.purge = nsk_sec.bit_ov.write;
+
+ nsk_sec_int = nsk_sec.int_ov;
+
+ access = NSK_RDONLY;
+ exclus = NSK_SHARED;
+ options = NSK_NOUPDATEOPENTIME;
+
+ extension = parsename (file,fname,ext);
+ len = strlen(fname);
+
+ err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
+ err = (SETMODE(fnum, SET_FILE_SECURITY, nsk_sec_int) != CCE);
+ err = FILE_CLOSE_(fnum);
+
+ return (err != 0 ? -1 : 0);
+}
+
+/* TANDEM version of chown() function */
+
+int chown(file, uid, gid)
+ const char *file;
+ uid_t uid;
+ gid_t gid;
+{
+ FILE *stream;
+ struct nsk_own_type {
+ unsigned group : 8;
+ unsigned user : 8;
+ };
+ union nsk_own_ov {
+ struct nsk_own_type bit_ov;
+ short int_ov;
+ };
+ union nsk_own_ov nsk_own;
+ short fnum, err, nsk_own_int;
+ short len, access, exclus, extension, options;
+ char fname[FILENAME_MAX + 1];
+ char ext[EXTENSION_MAX + 1];
+
+ nsk_own.bit_ov.group = gid;
+ nsk_own.bit_ov.user = uid;
+
+ nsk_own_int = nsk_own.int_ov;
+
+ access = NSK_RDONLY;
+ exclus = NSK_SHARED;
+ options = NSK_NOUPDATEOPENTIME;
+
+ extension = parsename (file,fname,ext);
+ len = strlen(fname);
+
+ err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,,,options,,,);
+ err = (SETMODE(fnum, SET_FILE_OWNER, nsk_own_int) != CCE);
+ err = FILE_CLOSE_(fnum);
+ return (err != 0 ? -1 : 0);
+}
+
+/* TANDEM version of getch() - non-echo character reading */
+int zgetch(void)
+{
+ char ch;
+ short f, err, count, fnum, rlen;
+
+ rlen = 1;
+ f = (short)fileno(stdin);
+ fnum = fdtogfn (f);
+ #define ECHO_MODE 20
+ err = (SETMODE(fnum, ECHO_MODE, 0) != CCE);
+ err = (READX(fnum, &ch, rlen, (short *) &count) != CCE);
+ err = (SETMODE(fnum, ECHO_MODE, 1) != CCE);
+
+ if (err)
+ if (err != 1)
+ return EOF;
+ else
+ ch = 'q';
+ else
+ if (count == 0)
+ ch = '\r';
+
+ return (int)ch;
+}
+
+short parsename(srce, fname, ext)
+ const char *srce;
+ char *fname;
+ char *ext;
+{
+ /* As a way of supporting DOS extensions from Tandem we look for a space
+ separated extension string after the Guardian filename
+ e.g. ZIP ZIPFILE "$DATA4.TESTING.INVOICE TXT"
+ */
+
+ char *fstart;
+ char *fptr;
+ short extension = 0;
+
+ *fname = *ext = '\0'; /* set to null string */
+
+ fstart = (char *) srce;
+
+ if ((fptr = strrchr(fstart, TANDEM_EXTENSION)) != NULL) {
+ extension = 1;
+
+ fptr++;
+ strncat(ext, fptr, _min(EXTENSION_MAX, strlen(fptr)));
+
+ fptr = strchr(fstart, TANDEM_EXTENSION); /* End of filename */
+ strncat(fname, fstart, _min(FILENAME_MAX, (fptr - fstart)));
+ }
+ else {
+ /* just copy string */
+ strncat(fname, srce, _min(FILENAME_MAX, strlen(srce)));
+ }
+
+ return extension;
+}
+
+static time_t gmt_to_time_t (gmt)
+ long long *gmt;
+{
+ #define GMT_TO_LCT 0
+ #define GMT_TO_LST 1
+
+ struct tm temp_tm;
+ short date_time[8];
+ long julian_dayno;
+ long long lct, lst, itime;
+ short err[1], type;
+
+ type = GMT_TO_LCT;
+ lct = CONVERTTIMESTAMP(*gmt, type,, err);
+
+ if (!err[0]) {
+ type = GMT_TO_LST;
+ lst = CONVERTTIMESTAMP(*gmt, type,, err);
+ }
+
+ itime = (err[0] ? *gmt : lct);
+ /* If we have no DST in force then make sure we give it a value,
+ else mktime screws up if we set the isdst flag to -1 */
+ temp_tm.tm_isdst = (err[0] ? 0 : ((lct == lst) ? 0 : 1));
+
+ julian_dayno = INTERPRETTIMESTAMP(itime, date_time);
+
+ temp_tm.tm_sec = date_time[5];
+ temp_tm.tm_min = date_time[4];
+ temp_tm.tm_hour = date_time[3];
+ temp_tm.tm_mday = date_time[2];
+ temp_tm.tm_mon = date_time[1] - 1; /* C's so sad */
+ temp_tm.tm_year = date_time[0] - 1900; /* it's almost funny */
+
+ return (mktime(&temp_tm));
+}
+
+/* TANDEM version of stat() function */
+int stat(n, s)
+ const char *n;
+ struct stat *s;
+{
+ #define ilist_items 26
+ #define klist_items 4
+ #define slist_items 3
+ #define ulist_items 1
+ #define flist_size 100
+
+ short err, i, extension;
+ char fname[FILENAME_MAX + 1];
+ short fnamelen;
+ char ext[EXTENSION_MAX + 1];
+
+ /* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
+ short ilist[ilist_items]={56,144, 54,142, 58, 62, 60, 41, 42, 44,
+ 50, 51, 52, 61, 63, 66, 67, 70, 72, 73,
+ 74, 75, 76, 77, 78, 79 };
+ short ilen[ilist_items] ={ 4, 4, 4, 2, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1 };
+ short ioff[ilist_items];
+
+ /* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
+ short klist[klist_items]={45, 46, 68, 69 };
+ short klen[klist_items] ={ 1, 1, 1, 1 };
+ short koff[klist_items];
+
+ /* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
+ short slist[slist_items]={43, 80, 90 };
+ short slen[slist_items] ={ 1, 1, 1 };
+ short soff[slist_items];
+
+ /* #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 */
+ short ulist[ulist_items]={65 };
+ short ulen[ulist_items] ={ 1 };
+ short uoff[ulist_items];
+
+ short flist[flist_size];
+ short extra[2];
+ short *rlen=&extra[0];
+ short *err_item=&extra[1];
+ unsigned short *fowner;
+ unsigned short *fprogid;
+ char *fsec;
+
+ nsk_stat_ov *nsk_ov;
+ nsk_file_attrs *nsk_attr;
+
+ short end, count, kind, level, options, searchid;
+ short info[5];
+
+ /* Initialise stat structure */
+ s->st_dev = _S_GUARDIANOBJECT;
+ s->st_ino = 0;
+ s->st_nlink = 0;
+ s->st_rdev = 0;
+ s->st_uid = s->st_gid = 0;
+ s->st_size = 0;
+ s->st_atime = s->st_ctime = s->st_mtime = 0;
+ s->st_reserved[0] = 0;
+ s->st_reserved[1] = 0;
+ s->st_reserved[2] = 0;
+ nsk_ov = (nsk_stat_ov *)&s->st_reserved[0];
+ nsk_attr = (nsk_file_attrs *)&nsk_ov->ov.nsk_ef_region;
+
+ /* Check to see if name contains a (pseudo) file extension */
+ extension = parsename (n,fname,ext);
+
+ fnamelen = strlen(fname);
+
+ options = 3; /* Allow Subvols and Templates */
+ err = FILENAME_SCAN_( fname,
+ fnamelen,
+ &count,
+ &kind,
+ &level,
+ options
+ );
+
+ /* allow kind == 2 (DEFINE names) */
+ if (err != 0) return -1;
+
+ if (kind == 1 || (kind == 0 && level < 2)) {
+ /* Pattern, Subvol Name or One part Filename - lets see if it exists */
+ err = FILENAME_FINDSTART_ ( &searchid,
+ fname,
+ fnamelen,
+ ,
+ DISK_DEVICE
+ );
+
+ if (err != 0) {
+ end = FILENAME_FINDFINISH_ ( searchid );
+ return -1;
+ }
+
+ err = FILENAME_FINDNEXT_ ( searchid,
+ fname,
+ FILENAME_MAX,
+ &fnamelen,
+ info
+ );
+ end = FILENAME_FINDFINISH_ ( searchid );
+
+ if (err != 0)
+ return -1; /* Non existing template, subvol or file */
+
+ if (kind == 1 || info[2] == -1) {
+ s->st_mode = S_IFDIR; /* Its an existing template or directory */
+ return 0;
+ }
+
+ /* Must be a real file so drop to code below to get info on it */
+ }
+
+ err = FILE_GETINFOLISTBYNAME_( fname,
+ fnamelen,
+ ilist,
+ ilist_items,
+ flist,
+ flist_size,
+ rlen,
+ err_item
+ );
+ if (err != 0) return -1;
+
+ ioff[0] = 0;
+
+ /* Build up table of offets into result list */
+ for (i=1; i < ilist_items; i++)
+ ioff[i] = ioff[i-1] + ilen[i-1];
+
+ /* Set up main stat fields */
+
+ /* Setup timestamps */
+ s->st_atime = gmt_to_time_t ((long long *)&flist[ioff[0]]);
+ s->st_mtime = s->st_ctime = gmt_to_time_t ((long long *)&flist[ioff[1]]);
+ nsk_ov->ov.creation_time = gmt_to_time_t ((long long *)&flist[ioff[2]]);
+
+ s->st_size = *(off_t *)&flist[ioff[3]];
+
+ fowner = (unsigned short *)&flist[ioff[4]];
+ s->st_uid = *fowner & 0x00ff;
+ s->st_gid = *fowner >> 8;
+
+ /* Note that Purge security (fsec[3]) in NSK has no relevance to stat() */
+ fsec = (char *)&flist[ioff[5]];
+ fprogid = (unsigned short *)&flist[ioff[6]];
+
+ s->st_mode = S_IFREG | /* Regular File */
+ /* Parse Read Flag */
+ ((fsec[0] & 0x03) == 0x00 ? S_IROTH : 0) |
+ ((fsec[0] & 0x02) == 0x00 ? S_IRGRP : 0) |
+ ((fsec[0] & 0x03) != 0x03 ? S_IRUSR : 0) |
+ /* Parse Write Flag */
+ ((fsec[1] & 0x03) == 0x00 ? S_IWOTH : 0) |
+ ((fsec[1] & 0x02) == 0x00 ? S_IWGRP : 0) |
+ ((fsec[1] & 0x03) != 0x03 ? S_IWUSR : 0) |
+ /* Parse Execute Flag */
+ ((fsec[2] & 0x03) == 0x00 ? S_IXOTH : 0) |
+ ((fsec[2] & 0x02) == 0x00 ? S_IXGRP : 0) |
+ ((fsec[2] & 0x03) != 0x03 ? S_IXUSR : 0) |
+ /* Parse Progid */
+ (*fprogid == 1 ? (S_ISUID | S_ISGID) : 0) ;
+
+ /* Set up NSK additional stat fields */
+ nsk_attr->progid = (unsigned) flist[ioff[6]];
+ nsk_attr->filetype = (unsigned) flist[ioff[7]];
+ nsk_attr->filecode = (unsigned) flist[ioff[8]];
+ nsk_attr->block = (unsigned short) flist[ioff[9]];
+ nsk_attr->priext = (unsigned short) flist[ioff[10]];
+ nsk_attr->secext = (unsigned short) flist[ioff[11]];
+ nsk_attr->maxext = (unsigned short) flist[ioff[12]];
+ nsk_attr->flags.clearonpurge = (unsigned) flist[ioff[13]];
+ nsk_attr->licensed = (unsigned) flist[ioff[14]];
+ nsk_attr->flags.audited = (unsigned) flist[ioff[15]];
+ nsk_attr->flags.acompress = (unsigned) flist[ioff[16]];
+ nsk_attr->flags.refresheof = (unsigned) flist[ioff[17]];
+ nsk_attr->flags.buffered = (unsigned) (flist[ioff[18]] == 0 ? 1 : 0);
+ nsk_attr->flags.verified = (unsigned) flist[ioff[19]];
+ nsk_attr->flags.serial = (unsigned) flist[ioff[20]];
+ nsk_attr->flags.crashopen = (unsigned) flist[ioff[22]];
+ nsk_attr->flags.rollforward = (unsigned) flist[ioff[23]];
+ nsk_attr->flags.broken = (unsigned) flist[ioff[24]];
+ nsk_attr->flags.corrupt = (unsigned) flist[ioff[25]];
+ nsk_attr->fileopen = (unsigned) flist[ioff[21]];
+
+
+ if (nsk_attr->filetype == NSK_UNSTRUCTURED) {
+ /* extra info for Unstructured files */
+ err = FILE_GETINFOLISTBYNAME_( fname,
+ fnamelen,
+ ulist,
+ ulist_items,
+ flist,
+ flist_size,
+ rlen,
+ err_item
+ );
+ if (err != 0) return -1;
+
+ uoff[0] = 0;
+
+ /* Build up table of offets into result list */
+ for (i=1; i < ulist_items; i++)
+ uoff[i] = uoff[i-1] + ulen[i-1];
+ }
+ else {
+ /* extra info for Structured files */
+ err = FILE_GETINFOLISTBYNAME_( fname,
+ fnamelen,
+ slist,
+ slist_items,
+ flist,
+ flist_size,
+ rlen,
+ err_item
+ );
+ if (err != 0) return -1;
+
+ soff[0] = 0;
+
+ /* Build up table of offets into result list */
+ for (i=1; i < slist_items; i++)
+ soff[i] = soff[i-1] + slen[i-1];
+
+ nsk_attr->reclen = (unsigned) flist[soff[0]];
+ nsk_attr->flags.secpart = (unsigned) flist[soff[1]];
+ nsk_attr->flags.primpart = (unsigned)
+ ( (flist[soff[2]] > 0 && nsk_attr->flags.secpart == 0) ? 1 : 0 );
+
+ if (nsk_attr->filetype == NSK_KEYSEQUENCED) {
+ /* extra info for Key Sequenced files */
+ err = FILE_GETINFOLISTBYNAME_( fname,
+ fnamelen,
+ klist,
+ klist_items,
+ flist,
+ flist_size,
+ rlen,
+ err_item
+ );
+ if (err != 0) return -1;
+
+ koff[0] = 0;
+
+ /* Build up table of offets into result list */
+ for (i=1; i < klist_items; i++)
+ koff[i] = koff[i-1] + klen[i-1];
+
+ nsk_attr->keyoff = (unsigned) flist[koff[0]];
+ nsk_attr->keylen = (unsigned) flist[koff[1]];
+ nsk_attr->flags.dcompress = (unsigned) flist[koff[2]];
+ nsk_attr->flags.icompress = (unsigned) flist[koff[3]];
+ }
+ }
+
+ return 0;
+}
+
+#ifndef SFX
+/* TANDEM Directory processing */
+
+DIR *opendir(const char *dirname)
+{
+ short i, resolve;
+ char sname[FILENAME_MAX + 1];
+ short snamelen;
+ char fname[FILENAME_MAX + 1];
+ short fnamelen;
+ char *p;
+ short searchid, err, end;
+ struct dirent *entry;
+ DIR *dirp;
+ char ext[EXTENSION_MAX + 1];
+ short extension;
+
+ extension = parsename(dirname, sname, ext);
+ snamelen = strlen(sname);
+
+ /* First we work out how detailed the template is...
+ * e.g. If the template is DAVES*.* we want the search result
+ * in the same format
+ */
+
+ p = sname;
+ i = 0;
+ while ((p = strchr(p, TANDEM_DELIMITER)) != NULL){
+ i++;
+ p++;
+ };
+ resolve = 2 - i;
+
+ /* Attempt to start a filename template */
+ err = FILENAME_FINDSTART_ ( &searchid,
+ sname,
+ snamelen,
+ resolve,
+ DISK_DEVICE
+ );
+ if (err != 0) {
+ end = FILENAME_FINDFINISH_(searchid);
+ return NULL;
+ }
+
+ /* Create DIR structure */
+ if ((dirp = malloc(sizeof(DIR))) == NULL ) {
+ end = FILENAME_FINDFINISH_(searchid);
+ return NULL;
+ }
+ dirp->D_list = dirp->D_curpos = NULL;
+ strcpy(dirp->D_path, dirname);
+
+ while ((err = FILENAME_FINDNEXT_(searchid,
+ fname,
+ FILENAME_MAX,
+ &fnamelen
+ )
+ ) == 0 ){
+ /* Create space for entry */
+ if ((entry = malloc (sizeof(struct dirent))) == NULL) {
+ end = FILENAME_FINDFINISH_(searchid);
+ return NULL;
+ }
+
+ /* Link to last entry */
+ if (dirp->D_curpos == NULL)
+ dirp->D_list = dirp->D_curpos = entry; /* First name */
+ else {
+ dirp->D_curpos->d_next = entry; /* Link */
+ dirp->D_curpos = entry;
+ };
+ /* Add directory entry */
+ *dirp->D_curpos->d_name = '\0';
+ strncat(dirp->D_curpos->d_name,fname,fnamelen);
+ if (extension) {
+ strcat(dirp->D_curpos->d_name,TANDEM_EXTENSION_STR);
+ strcat(dirp->D_curpos->d_name,ext);
+ };
+ dirp->D_curpos->d_next = NULL;
+ };
+
+ end = FILENAME_FINDFINISH_(searchid);
+
+ if (err == 1) { /* Should return EOF at end of search */
+ dirp->D_curpos = dirp->D_list; /* Set current pos to start */
+ return dirp;
+ }
+ else
+ return NULL;
+}
+
+struct dirent *readdir(DIR *dirp)
+{
+ struct dirent *cur;
+
+ cur = dirp->D_curpos;
+ dirp->D_curpos = dirp->D_curpos->d_next;
+ return cur;
+}
+
+void rewinddir(DIR *dirp)
+{
+ dirp->D_curpos = dirp->D_list;
+}
+
+int closedir(DIR *dirp)
+{
+ struct dirent *node;
+
+ while (dirp->D_list != NULL) {
+ node = dirp->D_list;
+ dirp->D_list = dirp->D_list->d_next;
+ free( node );
+ }
+ free( dirp );
+ return 0;
+}
+
+#endif /* !SFX */
diff --git a/tandem/tandem.h b/tandem/tandem.h
new file mode 100644
index 0000000..7296d26
--- /dev/null
+++ b/tandem/tandem.h
@@ -0,0 +1,236 @@
+/*
+ Copyright (c) 1990-2006 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __tandem_h /* prevent multiple inclusions */
+#define __tandem_h
+
+#ifndef TANDEM
+# define TANDEM /* better than __TANDEM */
+#endif
+
+/* LICENSED define now supplied by compile time option (MAKE) */
+
+#define NO_UNISTD_H
+#define NO_RMDIR
+#define NO_MKTEMP
+
+/* TANDEM supplies proper UTC vs. local time conversion, so enable Info-ZIP's
+ UT e.f. support unless explicitly suppressed by a compilation option. */
+#if (!defined(USE_EF_UT_TIME) && !defined(NO_EF_UT_TIME))
+# define USE_EF_UT_TIME
+#endif
+#if (defined(NO_EF_UT_TIME) && defined(USE_EF_UT_TIME))
+# undef USE_EF_UT_TIME
+#endif
+
+/* Include file for TANDEM */
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#include <time.h> /* the usual non-BSD time functions */
+#include <stdio.h>
+#include <sysstat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define PASSWD_FROM_STDIN
+ /* Kludge until we know how to open a non-echo tty channel */
+
+#define NSK_UNSTRUCTURED 0
+#define NSK_RELATIVE 1
+#define NSK_ENTRYSEQUENCED 2
+#define NSK_KEYSEQUENCED 3
+#define NSK_OBJECTFILECODE 100
+#define NSK_EDITFILECODE 101
+#define NSK_ZIPFILECODE 1001
+#define TANDEM_BLOCKSIZE 4096
+#define MAX_NORMAL_READ 4096
+#define MAX_EDIT_READ 255
+#define MAX_LARGE_READ 57344
+#define MAX_LARGE_READ_EXPAND 30720
+
+#define MAXFILEPARTLEN 8
+#define MAXPATHLEN 128
+#define EXTENSION_MAX 3
+/* FILENAME_MAX is defined in stdio.h */
+
+#define EXIT zexit /* To stop creation of Abend files */
+#define RETURN zexit /* To stop creation of Abend files */
+#define putc zputc /* To allow us to auto flush */
+
+
+#define FOPR "rb"
+#define FOPM "r+"
+#define FOPW "wb"
+#define FOPWT "w"
+
+#define NAMELEN FILENAME_MAX+1+EXTENSION_MAX /* allow for space extension */
+
+struct dirent {
+ struct dirent *d_next;
+ char d_name[NAMELEN+1];
+};
+
+typedef struct _DIR {
+ struct dirent *D_list;
+ struct dirent *D_curpos;
+ char D_path[NAMELEN+1];
+} DIR;
+
+DIR * opendir(const char *dirname);
+struct dirent *readdir(DIR *dirp);
+void rewinddir(DIR *dirp);
+int closedir(DIR *dirp);
+char * readd(DIR *dirp);
+
+#define DISK_DEVICE 3
+
+/* SETMODE Literals */
+#define SET_FILE_SECURITY 1
+#define SET_FILE_OWNER 2
+#define SET_FILE_BUFFERED 90
+#define SET_FILE_MAXEXTENTS 92
+#define SET_FILE_BUFFERSIZE 93
+#define SET_LARGE_TRANSFERS 141
+
+/* FILE_OPEN_ Literals */
+#define NSK_RDWR 0
+#define NSK_RDONLY 1
+#define NSK_WRONLY 2
+#define NSK_APPEND 3
+#define NSK_SHARED 0
+#define NSK_EXCLUSIVE 1
+#define NSK_PROCESSEXCLUSIVE 2
+#define NSK_PROTECTED 3
+#define NSK_UNSTRUCTUREDACCESS 0x8000
+#define NSK_NOUPDATEOPENTIME 0x2000
+
+#define NSK_NO_DELIMITER 0x0001
+#define NSK_USE_FF_DELIMITER 0x0002
+#define NSK_SPACE_FILL 0x0004
+#define NSK_TRIM_TRAILING_SPACE 0x0008
+#define NSK_LARGE_READ_EXPAND 0x0100 /* use smaller value for Expand */
+
+#define DOS_EXTENSION '.'
+#define TANDEM_EXTENSION ' '
+#define TANDEM_DELIMITER '.'
+#define TANDEM_NODE '\\'
+#define INTERNAL_DELIMITER '/'
+#define INTERNAL_NODE '//'
+#define TANDEM_WILD_1 '*'
+#define TANDEM_WILD_2 '?'
+
+#define DOS_EXTENSION_STR "."
+#define TANDEM_EXTENSION_STR " "
+#define TANDEM_DELIMITER_STR "."
+#define TANDEM_NODE_STR "\\"
+#define INTERNAL_DELIMITER_STR "/"
+#define INTERNAL_NODE_STR "//"
+
+/* Use 'spare' area at end of stat structure to hold additional Tandem/NSK
+ file details. Initially used to hold Creation time, now also holds most
+ Enscribe details */
+
+struct nsk_stat_reserved
+{
+ int64_t spare[3];
+};
+
+#pragma FIELDALIGN SHARED8 nsk_owner
+struct nsk_owner
+{
+ unsigned group : 8;
+ unsigned user : 8;
+};
+
+#pragma FIELDALIGN SHARED8 nsk_file_flags
+struct nsk_file_flags
+{
+ unsigned buffered : 1;
+ unsigned audited : 1;
+ unsigned acompress : 1;
+ unsigned icompress : 1;
+ unsigned dcompress : 1;
+ unsigned oddunstr : 1;
+ unsigned verified : 1;
+ unsigned serial : 1;
+ unsigned refresheof : 1;
+ unsigned broken : 1;
+ unsigned corrupt : 1;
+ unsigned primpart : 1;
+ unsigned secpart : 1;
+ unsigned crashopen : 1;
+ unsigned rollforward : 1;
+ unsigned clearonpurge: 1;
+};
+
+#pragma FIELDALIGN SHARED8 nsk_file_attrs_def
+struct nsk_file_attrs_def
+{
+ unsigned short filecode; /* 16 */
+ unsigned short block; /* 16 */ /* Allow of block > 4096 one day ! */
+ struct nsk_file_flags flags; /* 16 */
+ struct nsk_owner owner; /* 16 */
+ unsigned short priext; /* 16 */
+ unsigned short secext; /* 16 */
+ unsigned maxext : 10;
+ unsigned read : 3;
+ unsigned write : 3;
+ unsigned execute : 3;
+ unsigned delete : 3;
+ unsigned licensed : 1;
+ unsigned progid : 1;
+ unsigned keylen : 8;
+ unsigned : 5;
+ unsigned keyoff : 11;
+ unsigned : 1;
+ unsigned filetype : 2;
+ unsigned fileopen : 1;
+ unsigned reclen : 12;
+};
+typedef struct nsk_file_attrs_def nsk_file_attrs;
+
+#pragma FIELDALIGN SHARED8 nsk_stat_overlay
+struct nsk_stat_overlay
+{
+ time_t creation_time; /* 32 bits */
+ nsk_file_attrs nsk_ef_region;
+ /* char nsk_ef_region[20]; *//* EF region */
+};
+
+typedef union
+{
+ struct nsk_stat_reserved reserved;
+ struct nsk_stat_overlay ov;
+} nsk_stat_ov;
+
+/* Prototype function declarations */
+
+void zexit (int);
+
+int zputc(
+ int,
+ FILE *
+);
+
+int zgetch (void);
+
+short parsename(
+ const char *,
+ char *,
+ char *
+);
+
+int islicensed (void);
+
+/* End of prototype function declarations */
+
+#endif /* !__tandem_h */
diff --git a/tandem/tannsk.h b/tandem/tannsk.h
new file mode 100644
index 0000000..34ad49c
--- /dev/null
+++ b/tandem/tannsk.h
@@ -0,0 +1,19 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * Header declaration(s) which are forced to go after earlier includes
+ */
+
+#ifndef __tannsk_h /* prevent multiple inclusions */
+#define __tannsk_h
+
+/* ztimbuf is declared in zip\tailor.h after include of tandem.h */
+int utime (const char *, const ztimbuf *);
+
+#endif /* !__tannsk_h */
diff --git a/tandem/tanzip.c b/tandem/tanzip.c
new file mode 100644
index 0000000..5985b33
--- /dev/null
+++ b/tandem/tanzip.c
@@ -0,0 +1,723 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * routines only used by TANDEM ZIP
+ */
+
+#include "zip.h"
+#include "crypt.h"
+#include <tal.h>
+#include "$system.zsysdefs.zsysc" nolist
+#include <cextdecs> nolist
+#include "tannsk.h"
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if 0
+ char buf[40];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+ "C ", "T9255D44 - (16OCT98)",
+#endif
+
+ "NonStop ", "(Tandem/NSK)",
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
+
+
+/************************/
+/* Function nskopen() */
+/************************/
+
+#ifdef fopen
+# undef fopen
+#endif
+
+FILE *nskopen(fname, opt)
+const char *fname;
+const char *opt;
+{
+ int fdesc;
+ short fnum, err, len;
+ int priext, secext;
+ short maxext, filecode, blocksize;
+
+ #define alist_items 1
+ #define vlist_bytes 2
+ short alist[alist_items]={42};
+ unsigned short vlist[alist_items];
+ short extra, *err_item=&extra;
+
+ char nsk_work[FILENAME_MAX + 1], *nsk_fname=&nsk_work[0];
+
+ /* See if we want to create a new file */
+ if ((strcmp(opt,FOPW) == 0) || (strcmp(opt,FOPWT) == 0)) {
+ blocksize = TANDEM_BLOCKSIZE;
+ priext = 100;
+ secext = 500;
+ maxext = 978;
+ filecode = NSK_ZIPFILECODE;
+
+ if ((fdesc = creat(fname,,priext,secext)) != -1){
+ fnum = fdtogfn ((short)fdesc);
+ err = (SETMODE (fnum, SET_FILE_BUFFERSIZE, blocksize) != CCE);
+ err = (SETMODE (fnum, SET_FILE_BUFFERED, 0, 0) != CCE);
+ err = (SETMODE (fnum, SET_FILE_BUFFERED, 0, 1) != CCE);
+ err = (SETMODE (fnum, SET_FILE_MAXEXTENTS, maxext) != CCE);
+ err = close(fdesc);
+
+ vlist[0] = filecode;
+
+ /* Note that FILE_ALTERLIST_ expects uppercase names */
+ /* Need to call strlen and upshift */
+ len = strlen(fname);
+ err = STRING_UPSHIFT_((char *)fname,
+ len,
+ nsk_fname,
+ len);
+
+ err = FILE_ALTERLIST_(nsk_fname,
+ len,
+ alist,
+ alist_items,
+ vlist,
+ vlist_bytes,
+ ,
+ err_item);
+ };
+ };
+
+ return fopen(fname,opt);
+}
+#define fopen nskopen
+
+
+ int Bflag = 0; /* Special formatting options for Tandem */
+ /* Bit 0 = Add delimiter (0 = Yes, 1 = No) */
+ /* Bit 1 = Delimiter Type (0 = CR/LF, 1 = LF) */
+ /* Bit 2 = Space Fill records (0 = No, 1 = Yes) */
+ /* Bit 3 = Trim trailing space(0 = No, 1 = Yes) */
+ /* Thus, default is to add CR/LF, no padding */
+ /* Bit 8 = Use 'safe' large read size (Expand) */
+ char nsk_delim[2] = {'\r', '\n'}; /* CR/LF */
+ int nsk_delim_len = 2;
+ int nsk_space_fill = 0; /* 0 = No, 1 = Yes */
+ int nsk_trim_space = 0; /* 0 = No, 1 = Yes */
+ unsigned short nsk_large_read = MAX_LARGE_READ;
+
+ /* Following holds details of file currently used by zopen & zread */
+ struct stat znsk_stat;
+ nsk_stat_ov *znsk_ov = (nsk_stat_ov *)&znsk_stat.st_reserved[0];
+ nsk_file_attrs *znsk_attr = (nsk_file_attrs *)
+ ( (char *)(&znsk_stat.st_reserved[0]) +
+ offsetof (struct nsk_stat_overlay, nsk_ef_region) );
+
+ /* Following items used by zread to avoid overwriting window */
+ char zreadbuf[MAX_LARGE_READ]; /* Buffer as large as biggest read */
+ char *zreadptr = (char *) zreadbuf; /* pointer to start of buffer */
+ char *zread_ovptr = NULL; /* pointer to left overs */
+ long zread_ovlen = 0; /* size of remaining left overs */
+
+ int zopen (filename, opt)
+ const char *filename;
+ int opt;
+ {
+ /* Currently ignore opt. Choose method of I/O based on NSK file type */
+ short err, len, fnum, access, exclus, bufferlen, options;
+ long recnum;
+ char fname[FILENAME_MAX + 1];
+ short extension;
+ char ext[EXTENSION_MAX + 1];
+
+ /* Remove any (pseudo) file extension */
+ extension = parsename (filename,fname,ext);
+ len = strlen(fname);
+
+ fnum = 0;
+ access = NSK_RDONLY;
+ exclus = NSK_SHARED;
+
+ err = stat(fname, &znsk_stat); /* Setup global struct, used by zread */
+
+ if (znsk_attr->filetype == NSK_UNSTRUCTURED)
+ if (znsk_attr->filecode == NSK_EDITFILECODE) {
+ /* Edit File */
+ fnum = -1; /* Ask OPENEDIT_ to open the file for us */
+ err = OPENEDIT_ ((char *)fname, len, &fnum, access, exclus);
+ if (!err) {
+ recnum = -1; /* Position to first line */
+ err = POSITIONEDIT (fnum, recnum);
+ }
+ }
+ else {
+ /* Unstructured File */
+ options = NSK_UNSTRUCTUREDACCESS;
+ err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,
+ ,,options,,,);
+ if (!err)
+ /* Ask for large transfer mode */
+ err = (SETMODE (fnum, SET_LARGE_TRANSFERS, 1) != CCE);
+ }
+ else {
+ /* Structured File */
+ bufferlen = 4096; /* request SBB */
+ err = FILE_OPEN_((char *)fname, len, &fnum, access, exclus,
+ ,,,, bufferlen ,);
+ if (err == 4)
+ err = 0; /* Allow saving of files that have missing altkeys */
+ }
+
+ return (err == 0 ? (int)fnum : -1);
+ }
+
+ unsigned zread (fnum, buf, len)
+ int fnum;
+ char *buf;
+ unsigned len;
+ {
+ short err, trail;
+ long total, movelen;
+ unsigned short countread;
+ unsigned readlen; /* typed to match incoming arg */
+ char *bufptr, *readptr;
+
+ total = err = 0;
+ bufptr = buf;
+
+ /* We use a separate buffer to read in data as it can be larger than
+ WSIZE, and hence would overwrite memory */
+
+ /* We always attempt to give the user the exact requested size
+ Hence we make use of an overfow buffer for previously truncated data */
+
+ /* see if we have some left over characters from last time */
+ if (zread_ovlen) {
+ movelen = _min(len,zread_ovlen);
+ memcpy(bufptr, zread_ovptr, movelen);
+ bufptr += movelen;
+ total += movelen;
+ zread_ovptr += movelen;
+ zread_ovlen -= movelen;
+ }
+
+ while (!err && (total < len)) {
+ readptr = zreadptr;
+
+ if (znsk_attr->filetype == NSK_UNSTRUCTURED)
+ if (znsk_attr->filecode == NSK_EDITFILECODE){
+ /* Edit File */
+ trail = 1;
+ readlen = MAX_EDIT_READ; /* guarantee it fits in buffer */
+
+ /* get line and preserve any trailing space characters */
+ err = READEDIT (fnum,, zreadptr, (short) readlen,
+ (short *) &countread,,, trail);
+ /* if countread is ever negative then we will skip a line */
+
+ if (!err) {
+ readptr = zreadptr + countread;
+ /* Note it is possible for Edit files to hold trailing space */
+ if (nsk_trim_space)
+ while (*(readptr-1) == ' ') {
+ readptr--;
+ countread--;
+ }
+
+ if (nsk_delim_len) {
+ memcpy(readptr, nsk_delim, nsk_delim_len);
+ readptr += nsk_delim_len;
+ countread += nsk_delim_len;
+ }
+ }
+ }
+ else {
+ /* Unstructured File */
+
+ /* Using large transfer mode so we have to use 2K multiples
+ Use largest size possible and put remains in overflow */
+
+ readlen = nsk_large_read; /* use largest read, overflow into buffer*/
+
+ err = (READX(fnum, zreadptr, readlen, (short *)&countread) != CCE);
+ if (err && (errno == EINVAL)) {
+ /* Read too big so scale back to smaller value */
+ readlen = nsk_large_read = MAX_LARGE_READ_EXPAND;
+ err = (READX(fnum, zreadptr, readlen, (short *)&countread) != CCE);
+ }
+ if (!err)
+ readptr = zreadptr + countread;
+ }
+ else {
+ /* Structured File */
+ readlen = znsk_attr->reclen;
+
+ err = (READX(fnum, zreadptr, readlen, (short *)&countread)!= CCE);
+
+ if (!err) {
+ readptr = zreadptr + countread;
+ if (nsk_space_fill)
+ while (countread < readlen) {
+ *readptr++ = ' ';
+ countread++;
+ }
+ else
+ if (nsk_trim_space)
+ while (*(readptr-1) == ' ') {
+ readptr--;
+ countread--;
+ }
+
+ if (nsk_delim_len) {
+ memcpy(readptr, nsk_delim, nsk_delim_len);
+ readptr += nsk_delim_len;
+ countread += nsk_delim_len;
+ }
+ }
+ }
+ if (!err) {
+ movelen = _min((len-total), countread);
+ memcpy(bufptr, zreadptr, movelen);
+ bufptr += movelen;
+ total += movelen;
+ if (movelen < countread) { /* still stuff in Read buffer */
+ zread_ovptr = zreadptr + movelen; /* pointer to whats left */
+ zread_ovlen = countread - movelen; /* how much is left */
+ }
+ }
+ }
+
+ return ((unsigned)total);
+ }
+
+ int zclose (fnum)
+ int fnum;
+ {
+ short err;
+
+ if ((znsk_attr->filetype == NSK_UNSTRUCTURED)
+ && (znsk_attr->filecode == NSK_EDITFILECODE))
+ err = CLOSEEDIT_(fnum);
+ else
+ err = FILE_CLOSE_(fnum);
+
+ return (err != 0);
+ }
+
+/* modified to work with get_option which returns
+ a string with the number value without leading option */
+void nskformatopt(p)
+char *p;
+{
+ /* set up formatting options for ZIP */
+
+ Bflag = 0; /* default option */
+
+ Bflag = strtoul(p, NULL, 10);
+
+ if (Bflag & NSK_SPACE_FILL)
+ nsk_space_fill = 1;
+ else
+ nsk_space_fill = 0;
+
+ if (Bflag & NSK_TRIM_TRAILING_SPACE)
+ nsk_trim_space = 1;
+ else
+ nsk_trim_space = 0;
+
+ if (Bflag & NSK_NO_DELIMITER)
+ nsk_delim_len = 0;
+ else {
+ if (Bflag & NSK_USE_FF_DELIMITER) {
+ nsk_delim[0] = '\n';
+ nsk_delim_len = 1;
+ }
+ else { /* CR/LF */
+ nsk_delim[0] = '\r';
+ nsk_delim[1] = '\n';
+ nsk_delim_len = 2;
+ }
+ }
+
+ if (Bflag & NSK_LARGE_READ_EXPAND)
+ nsk_large_read = MAX_LARGE_READ_EXPAND;
+ else
+ nsk_large_read = MAX_LARGE_READ;
+
+}
+
+
+ int deletedir(d)
+ char *d; /* directory to delete */
+ /* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+ {
+ return rmdir(d);
+ }
+
+ local char *readd(d)
+ DIR *d; /* directory stream to read from */
+ /* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+ {
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+ }
+
+ int procname(n, caseflag)
+ char *n; /* name to process */
+ int caseflag; /* true to force case-sensitive match */
+ /* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+ {
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (stat(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->zname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ if ((p = malloc(strlen(n)+4)) == NULL)
+ return ZE_MEM;
+
+ strcpy(p, n);
+
+ /* No concept of directories on Tandem - so do not store them ...*/
+ /* code removed from which attempted to save dir name if dirnames set */
+
+ /* Test for recurse being set removed, since Tandem has no dir concept*/
+ /* recurse into template */
+ if ((d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if ((m = procname(e, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", e);
+ else
+ ziperr(m, e);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+ }
+
+ char *ex2in(x, isdir, pdosflag)
+ char *x; /* external file name */
+ int isdir; /* input: x is a directory */
+ int *pdosflag; /* output: force MSDOS file attributes? */
+ /* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+ {
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+ char *p; /* pointer to temp area */
+ char fname[FILENAME_MAX + 1]= ""; /* file name */
+ char ext[EXTENSION_MAX + 1] = ""; /* extension name */
+ short extension; /* does the filename contain an extension */
+
+ dosflag = dosify; /* default for non-DOS non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ if (*x == '=')
+ t = x + 1; /* store DEFINE names without the '=' */
+ else
+ t = x;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+
+ if (!pathput)
+ t = last(t, TANDEM_DELIMITER);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 4)) == NULL) /* + 4 for safety */
+ return NULL;
+
+ extension = parsename(t,fname,ext);
+ t = fname;
+
+ *n= '\0';
+
+ while (*t != '\0') { /* File part could be sys,vol,subvol or file */
+ if (*t == TANDEM_NODE) { /* System Name */
+ strcat(n, INTERNAL_NODE_STR);
+ t++;
+ }
+ else if (*t == TANDEM_DELIMITER) { /* Volume or Subvol */
+ strcat(n, INTERNAL_DELIMITER_STR);
+ t++;
+ };
+ p = strchr(t,TANDEM_DELIMITER);
+ if (p == NULL) break;
+ strncat(n,t,(p - t));
+ t = p;
+ }
+
+ strcat(n,t); /* mop up any left over characters */
+
+ if (extension) {
+ strcat(n,DOS_EXTENSION_STR);
+ strcat(n,ext);
+ };
+
+ if (isdir == 42) return n; /* avoid warning on unused variable */
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+
+ return n;
+ }
+
+ void stamp(f, d)
+ char *f; /* name of file to change */
+ ulg d; /* dos-style time to change it to */
+ /* Set last updated and accessed time of file f to the DOS time d. */
+ {
+ ztimbuf u; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u.actime and u.modtime */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ utime(f, &u);
+ }
+
+ ulg filetime(f, a, n, t)
+ char *f; /* name of file to get info on */
+ ulg *a; /* return value: file attributes */
+ long *n; /* return value: file size */
+ iztimes *t; /* return value: access and modification time */
+ {
+ struct stat s;
+ nsk_stat_ov *nsk_ov;
+
+ if (strcmp(f, "-") == 0) { /* if compressing stdin */
+ if (n != NULL) {
+ *n = -1L;
+ }
+ }
+
+ if (stat(f, &s) != 0) return 0;
+
+ if (a!= NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWUSR);
+ if ((s.st_mode & S_IFMT) == S_IFDIR) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+
+ if (n!= NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ nsk_ov = (nsk_stat_ov *)&s.st_reserved[0];
+ t->ctime = nsk_ov->ov.creation_time;
+ }
+
+ return unix2dostime(&s.st_mtime);
+ }
+
+ int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+ /* store full data in local header but just modification time stamp info
+ in central header */
+ {
+ struct stat s;
+ nsk_stat_ov *nsk_ov = (nsk_stat_ov *)&s.st_reserved[0];
+ nsk_file_attrs *nsk_attr = (nsk_file_attrs *)&nsk_ov->ov.nsk_ef_region;
+ char *ext, *cext;
+ int lsize, csize;
+#ifdef USE_EF_UT_TIME
+ char *UTptr, *Uxptr;
+#endif /* USE_EF_UT_TIME */
+
+ /* For the Tandem and UT local field including the UID/GID fields, we
+ have to stat the file again. */
+ if (LSSTAT(z->name, &s))
+ return ZE_OPEN;
+
+ z->ext = z->cext = 0;
+
+ #define EB_TANDEM_SIZE 20
+ #define EF_TANDEM_SIZE (EB_HEADSIZE + EB_TANDEM_SIZE)
+
+ /* allocate size of buffers to allow Tandem field */
+ lsize = EF_TANDEM_SIZE;
+ csize = EF_TANDEM_SIZE;
+
+#ifdef USE_EF_UT_TIME
+
+ #define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3))
+ #define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+ #define EB_L_UX2_SIZE (EB_HEADSIZE + EB_UX2_MINLEN)
+ #define EB_C_UX2_SIZE EB_HEADSIZE
+ #define EF_L_UNIX_SIZE (EB_L_UT_SIZE + EB_L_UX2_SIZE)
+ #define EF_C_UNIX_SIZE (EB_C_UT_SIZE + EB_C_UX2_SIZE)
+
+ /* resize to allow for UT fields */
+ lsize += EF_L_UNIX_SIZE;
+ csize += EF_C_UNIX_SIZE;
+
+#endif /* USE_EF_UT_TIME */
+
+ if ((z->extra = (char *)malloc(lsize)) == NULL)
+ return ZE_MEM;
+ ext = z->extra;
+
+ if ((z->cextra = (char *)malloc(csize)) == NULL)
+ return ZE_MEM;
+ cext = z->cextra;
+
+ /* Place Tandem field first so its on an even boundary */
+ *ext++ = *cext++ = 'T';
+ *ext++ = *cext++ = 'A';
+ *ext++ = *cext++ = (char)EB_TANDEM_SIZE; /*length of data part of e.f.*/
+ *ext++ = *cext++ = 0;
+
+ /* Copy Tandem specific file information */
+ memcpy(ext, (char *)nsk_attr, EB_TANDEM_SIZE);
+ ext += EB_TANDEM_SIZE;
+ z->ext += EF_TANDEM_SIZE;
+
+ /* Copy same data to central field */
+ memcpy(cext, (char *)nsk_attr, EB_TANDEM_SIZE);
+ cext += EB_TANDEM_SIZE;
+ z->cext += EF_TANDEM_SIZE;
+
+#ifdef USE_EF_UT_TIME
+ UTptr = ext;
+ *ext++ = 'U';
+ *ext++ = 'T';
+ *ext++ = (char)EB_UT_LEN(3); /* length of data part of local e.f. */
+ *ext++ = 0;
+ *ext++ = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+ *ext++ = (char)(s.st_mtime);
+ *ext++ = (char)(s.st_mtime >> 8);
+ *ext++ = (char)(s.st_mtime >> 16);
+ *ext++ = (char)(s.st_mtime >> 24);
+ *ext++ = (char)(s.st_atime);
+ *ext++ = (char)(s.st_atime >> 8);
+ *ext++ = (char)(s.st_atime >> 16);
+ *ext++ = (char)(s.st_atime >> 24);
+
+ *ext++ = (char)(nsk_ov->ov.creation_time);
+ *ext++ = (char)(nsk_ov->ov.creation_time >> 8);
+ *ext++ = (char)(nsk_ov->ov.creation_time >> 16);
+ *ext++ = (char)(nsk_ov->ov.creation_time >> 24);
+
+ Uxptr = ext;
+ *ext++ = 'U';
+ *ext++ = 'x';
+ *ext++ = (char)EB_UX2_MINLEN; /* length of data part of local e.f. */
+ *ext++ = 0;
+ *ext++ = (char)(s.st_uid);
+ *ext++ = (char)(s.st_uid >> 8);
+ *ext++ = (char)(s.st_gid);
+ *ext++ = (char)(s.st_gid >> 8);
+
+ z->ext += EF_L_UNIX_SIZE;
+
+ memcpy(cext, UTptr, EB_C_UT_SIZE);
+ cext[EB_LEN] = (char)EB_UT_LEN(1);
+ memcpy(cext+EB_C_UT_SIZE, Uxptr, EB_C_UX2_SIZE);
+ cext[EB_LEN+EB_C_UT_SIZE] = 0;
+
+ z->cext += EF_C_UNIX_SIZE;
+ cext += EF_C_UNIX_SIZE;
+
+#endif /* USE_EF_UT_TIME */
+
+ return ZE_OK;
+ }
+
+#if CRYPT
+ /* getpid() only available on OSS so make up dummy version using NSK PID */
+ unsigned zgetpid (void)
+ {
+ short myphandle[ZSYS_VAL_PHANDLE_WLEN];
+ short err;
+ unsigned retval;
+
+ err = PROCESSHANDLE_NULLIT_(myphandle);
+
+ if (!err)
+ err = PROCESS_GETINFO_(myphandle);
+
+ if (!err)
+ retval = (unsigned) myphandle[ZSYS_VAL_PHANDLE_WLEN - 3];
+ else
+#ifndef __INT32
+ retval = (unsigned) 31415;
+#else
+ retval = (unsigned) 3141592654L;
+#endif /* __INT32 */
+
+ return retval;
+ }
+#endif /* CRYPT */
diff --git a/tandem/tanzip.h b/tandem/tanzip.h
new file mode 100644
index 0000000..528337d
--- /dev/null
+++ b/tandem/tanzip.h
@@ -0,0 +1,43 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __tanzip_h /* prevent multiple inclusions */
+#define __tanzip_h
+
+# define fopen nskopen /* To allow us to set extent sizes */
+
+# define USE_CASE_MAP
+
+ FILE *nskopen(const char *, const char *);
+ int zopen (const char *, int);
+ int zclose (int);
+ unsigned zread (int, char *, unsigned);
+ void nskformatopt(char *);
+
+ #define getpid zgetpid
+ unsigned zgetpid (void);
+
+#define CBSZ 0x10000 /* Was used for both fcopy and file_read. */
+ /* Created separate define (SBSZ) for file_read */
+ /* fcopy param is type size_t (unsigned long) */
+ /* For Guardian we choose a multiple of 4K */
+
+#define ZBSZ 0x10000 /* This is used in call to setvbuf, 64K seems to work */
+ /* in all memory models. Again it is an unsigned long */
+ /* For Guardian we choose a multiple of 4K */
+
+#ifndef __INT32
+#define SBSZ 0x0e000 /* Maximum of size unsigned (int). Only used in STORE */
+ /* method. We can use up to 56K bytes thanks to large */
+ /* transfer mode. Note WSIZE is limited to 32K, which */
+ /* limits the DEFLATE read size to same value. */
+#else
+#define SBSZ 0x10000 /* WIDE model so we can use 64K */
+#endif /* __INT32 */
+
+#endif /* !__tanzip_h */
diff --git a/tandem/zipup.h b/tandem/zipup.h
new file mode 100644
index 0000000..19d92ad
--- /dev/null
+++ b/tandem/zipup.h
@@ -0,0 +1,26 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+
+/* Now we create Guardian versions of zopen, zread, zclose instead
+ moved prototypes to tanzip.h as they are now coded in tanzip.c
+ #define zopen(n,p) open(n,p)
+ #define zread(f,b,n) read(f,b,n)
+ #define zclose(f) close(f)
+*/
+
+
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
+
diff --git a/theos/Makefile b/theos/Makefile
new file mode 100644
index 0000000..acdbb12
--- /dev/null
+++ b/theos/Makefile
@@ -0,0 +1,138 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# THEOS ANSI C
+# To use, do "make -f theos/makefile"
+# This make file uses cl, a C compiler and linker driver written by
+# Jean-Michel Dubois. Send a mail to jmdubois@ibcfrance.fr to get it for free.
+# MAINWA_BUG Workaround argument expansion failure
+# LOCATE_BUG Workaround stat, fopen and open failure on relative paths to
+# root dir.
+
+CC=cl
+CFLAGS=-Zi -W3 -DDYN_ALLOC -DCRYPT -DMAINWA_BUG -DLOCATE_BUG
+LD=cl -o
+LDFLAGS=-m -Zi
+AS=cc
+ASFLAGS=
+
+UTILFLAGS=-DUTIL $(CFLAGS) -Fo
+
+# variables
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+ theos.o crc32.o _fprintf.o _stat.o _chmod.o _isatty.o \
+ _setargv.o _rename.o
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o theos_.o _rename.o _stat.o \
+ _chmod.o _fprintf.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+OSDEP_H = theos/osdep.h
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+ZIPS = zip.command zipnote.command zipsplit.command zipcloak.command
+
+zips: $(ZIPS)
+
+zip.o: zip.c $(ZIP_H) crc32.h crypt.h ttyio.h revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.o: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.o: zipup.c $(ZIP_H) revision.h crc32.h crypt.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.o: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.o: util.c $(ZIP_H) theos/charconv.h
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.o: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.o: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.o: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.o: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.o: crypt.c $(ZIP_H) crc32.h crypt.h
+ $(CC) -c $(CFLAGS) $*.c
+
+theos.o: theos/theos.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) -Fo$@ theos/theos.c
+
+_fprintf.o: theos/_fprintf.c
+ $(CC) -c $(CFLAGS) -Fo$@ theos/_fprintf.c
+
+_stat.o: theos/_stat.c
+ $(CC) -c $(CFLAGS) -Fo$@ theos/_stat.c
+
+_chmod.o: theos/_chmod.c
+ $(CC) -c $(CFLAGS) -Fo$@ theos/_chmod.c
+
+_isatty.o: theos/_isatty.c
+ $(CC) -c $(CFLAGS) -Fo$@ theos/_isatty.c
+
+_rename.o: theos/_rename.c
+ $(CC) -c $(CFLAGS) -Fo$@ theos/_rename.c
+
+_setargv.o: theos/_setargv.c
+ $(CC) -c $(CFLAGS) -Fo$@ theos/_setargv.c
+
+ttyio.o: $(ZIP_H) ttyio.h ttyio.c
+ $(CC) -c $(CFLAGS) $*.c
+
+zipcloak.o: zipcloak.c $(ZIP_H) crc32.h crypt.h ttyio.h revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.o: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.o: $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.o: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$@ zipfile.c
+
+fileio_.o: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$@ fileio.c
+
+theos_.o: theos/theos.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$@ theos/theos.c
+
+util_.o: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$@ util.c
+
+crc32_.o: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$@ $*.c
+
+crypt_.o: crypt.c $(ZIP_H) crc32.h crypt.h
+ $(CC) -c $(UTILFLAGS)$@ crypt.c
+
+zip.command: $(OBJZ) $(OBJI)
+ $(LD) $@ $(OBJZ) $(OBJI) $(LDFLAGS)
+
+zipcloak.command: $(OBJC)
+ $(LD) $@ $(OBJC) $(LDFLAGS)
+
+zipnote.command: $(OBJN)
+ $(LD) $@ $(OBJN) $(LDFLAGS)
+
+zipsplit.command: $(OBJS)
+ $(LD) $@ $(OBJS) $(LDFLAGS)
+
+install: $(ZIPS)
+ copy *.command /system.cmd32.=(rep noq not
+
+clean:
+ erase *.o(noq not
+ erase *.command(noq not
diff --git a/theos/README b/theos/README
new file mode 100644
index 0000000..1ec99d3
--- /dev/null
+++ b/theos/README
@@ -0,0 +1,34 @@
+This Theos port supports all the unusual features of Theos filesystem.
+
+Under Theos filesystem files are typed. Types include :
+- stream
+- relative
+- keyed
+- indexed (ISAM)
+- program (86 real mode, 16 bits protected mode, 32 bits protected mode)
+- directory
+- library (contains files of any other types librry and directory excepted).
+
+Most of the information on the type and on the structure of a file are not
+contained in the file itself but its in directory entry. For all types of
+files, directory and stream files excepted, this information is vital. If it
+is lost, the file can no longer be usable.
+
+In zip files the information is stored in an extra block with type "Th".
+
+A few years ago I ported ZIP for internal use and spreaded it a little around
+me. It was using a non portable extra block structure. Its type was "TH".
+For backward compatibility it is supported by UNZIP 5.4.0 port to Theos.
+ZIP archives created with ZIP 2.3 port MUST be unzipped with 5.4.0 or a later
+version.
+
+Also disk search sequence is supported. The disk name is not stored into
+the zip archive.
+
+Thanks to Bob Baker from Stockboy Services who spent his time to check this
+port under other conditions than mines.
+
+Jean-Michel Dubois
+IBC France / THEOS France
+jmdubois@ibcfrance.fr
+jean-michel-dubois@wanadoo.fr
diff --git a/theos/_chmod.c b/theos/_chmod.c
new file mode 100644
index 0000000..0937b45
--- /dev/null
+++ b/theos/_chmod.c
@@ -0,0 +1,21 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/* Change UNIX modes */
+
+#pragma library
+
+#include <sc.h>
+
+int _chmod(const char *fname, short mask)
+{
+ extern char _um2tm_(short);
+
+ return _filechange(fname,'p',(size_t) _um2tm_(mask)|0x80);
+}
+
diff --git a/theos/_fprintf.c b/theos/_fprintf.c
new file mode 100644
index 0000000..36a21a6
--- /dev/null
+++ b/theos/_fprintf.c
@@ -0,0 +1,26 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include <stdio.h>
+#include <stdarg.h>
+
+/* for Info and similar macroes. fprintf is already a macro and fprintf x
+ * fools the preprocessor
+ */
+
+int _fprintf(FILE* fp, const char* fmt, ...)
+{
+ va_list ap;
+ long n;
+
+ va_start(ap, fmt);
+ n = vfprintf(fp, fmt, (long*) ap);
+ va_end(ap);
+ return n;
+}
+
diff --git a/theos/_isatty.c b/theos/_isatty.c
new file mode 100644
index 0000000..3283e90
--- /dev/null
+++ b/theos/_isatty.c
@@ -0,0 +1,26 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* replace standard library function who needs a FILE* */
+
+#pragma library
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sc.h>
+#include <lub.h>
+
+short _isatty(int fd)
+{
+ register short lub;
+
+ lub = (int) _fcntl(&stdin[fd], 5, (size_t) 0);
+ return (lub >= CONIN && lub <= CONOUT)
+ || (lub >= COM1 && lub <= COM4)
+ || (lub >= COM5 && lub <= COM16);
+}
diff --git a/theos/_rename.c b/theos/_rename.c
new file mode 100644
index 0000000..04eb204
--- /dev/null
+++ b/theos/_rename.c
@@ -0,0 +1,83 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define EXDEV 590
+
+#define _sys_rename() _sc_140()
+extern unsigned short _sys_rename(const char _far *oldfn, char *newfn);
+
+/* rename a file. Report an error on cross disk renames */
+
+static void _n_(const char* fn, char* bfn)
+{
+ if (*fn != '.' && *fn != '/')
+ strcpy(bfn, "./");
+ else
+ *bfn = '\0';
+ strcat(bfn, fn);
+}
+
+int _rename(const char* old, const char* new)
+{
+ char* p;
+ char* q;
+ char* r;
+ char olddrv, newdrv;
+ char dir[FILENAME_MAX];
+ short status;
+ char bold[FILENAME_MAX], bnew[FILENAME_MAX];
+
+ p = strrchr(old, ':');
+ q = strrchr(new, ':');
+
+ /* if at least one path includes a disk name, check for equality */
+ if (p != NULL || q != NULL) {
+ /* getcwd return a NULL pointer for /:S */
+ getcwd(dir, FILENAME_MAX);
+ r = strrchr(dir, ':');
+
+ if (p == NULL)
+ p = r;
+ olddrv = p ? p[1] : 'S';
+
+ if (q == NULL)
+ q = r;
+ newdrv = q ? q[1] : 'S';
+
+ /* return an error if uppercased disk names are not the same */
+ if ((old & ~0x20) != (new & ~0x20)) {
+ _errarg = NULL;
+ return errno = _errnum = EXDEV;
+ }
+ }
+ /* prepend ./ if there is no path to force rename to work on files
+ * in the current directory instead of default library
+ */
+ _n_(old, bold);
+ _n_(new, bnew);
+
+ status = _sys_rename(bold, bnew);
+ /* can be :
+ * 0 no error
+ * 19 "old" file not found
+ * 44 "new" file already exist
+ * 45 "new" filename missing
+ * 46 "old" file name missing
+ */
+ if (status) {
+ errno = _errnum = status;
+ _errarg = (status == 44 || status == 45) ? new : old;
+ }
+
+ return status;
+}
diff --git a/theos/_setargv.c b/theos/_setargv.c
new file mode 100644
index 0000000..d76f955
--- /dev/null
+++ b/theos/_setargv.c
@@ -0,0 +1,140 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * __setargv.c - command argument expander
+ *
+ * Author : Jean-Michel Dubois
+ * Date : 09/26/92
+ *
+ * Function: Expands the command line arguments by replacing any filename
+ * including wilcards by the sorted list of matching files name.
+ * Strings beginning by a dash are considered as options and left
+ * unchanged.
+ *
+ * Syntax : void _setargv(int *argc, char ***argv);
+ *
+ * Returns : new argc. Caller's argc and argv are updated.
+ * If a insufficient memory condition occurs, return 0 and errno
+ * is set to ENOMEM.
+ *
+ * Example :
+ * main(int argc, char **argv)
+ * {
+ * if (_setargv(&argc, &argv)) {
+ * ...
+ */
+#pragma library
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <scr.h>
+#include <peek.h>
+
+/* Allocate argv array in 16 entries chunks */
+
+static int allocarg(int n, int l, char ***nargv, char *s)
+{
+ if ((n+1) > l) { /* If array full */
+ l += 16; /* increase size and reallocate */
+ if (!(*nargv = (char **) realloc(*nargv,l * sizeof (void *)))) {
+ errno = _errnum = ENOMEM; /* Not enough memory */
+ return 0;
+ }
+ }
+ (*nargv)[n] = strdup(s); /* Save argument */
+ return l; /* Return new maxsize */
+}
+
+/* Comparison function for qsort */
+
+static int sortcmp(char **p, char **q)
+{
+ return stricmp(*p,*q);
+}
+
+/* Main body of the function */
+
+int _setargv(int *argc, char ***argv)
+{
+ register int nargc; /* New arguments counter */
+ char **nargv; /* New arguments pointers */
+ register int i, l, base;
+ char *p, *q, *r;
+ char path[FILENAME_MAX];
+
+ _errnum = 0;
+ nargc = 0; /* Initialise counter, size counter */
+ l = *argc; /* and new argument vector to the */
+ /* current argv array size */
+
+ if ((nargv = (char **) calloc((size_t) *argc, sizeof (void *))) != NULL) {
+ /* For each initial argument */
+ for (i = 0; i < *argc; i++) {
+ q = (*argv)[i];
+ if (q[0] == '-' || ! testwild(q)) {
+ /* if it begins with a dash or doesnt include
+ * wildcard simply add it to the new array
+ */
+ if (! (l = allocarg(nargc, l, &nargv, q)))
+ return 0; /* Not enough memory */
+ nargc++;
+ } else {
+ /* else keep current counter for qsort */
+ base = nargc;
+ /* open directory with argument */
+ diropen(q);
+ while ((r = dirread()) != NULL) {
+ /* reduce path to given one */
+ if ((p = strrchr(q, '/')) != NULL) {
+ strncpy(path, q, p-q+1);
+ path[p-q+1] = '\0';
+ } else
+ path[0] = '\0';
+
+ if ((p = strrchr(r, '/')) != NULL)
+ strcat(path, p+1);
+ else
+ strcat(path, r);
+
+ if (peekscr(&SCR->searchseq[1]) == 255
+ && strchr(q, ':') == NULL) {
+ *strchr(path, ':') = '\0';
+ }
+ /* and add each matching filename. */
+ if (! (l = allocarg(nargc,l,&nargv,path)))
+ return 0;/* Not enough memory */
+ nargc++;
+ }
+ if (nargc == base) {
+ /* if no match found include wild card name */
+ if (! (l = allocarg(nargc, l, &nargv, q)))
+ return 0; /* Not enough memory */
+ nargc++;
+ } else if ((nargc - base) > 1)
+ /* If more than one file name matchs */
+ /* sort arguments. */
+ qsort(&(nargv[base]),(size_t)nargc-base,
+ sizeof(void *),sortcmp);
+ dirclose();
+ }
+ }
+ /* Update caller's parameters */
+ *argc = nargc;
+ *argv = nargv;
+ /* and sign on success */
+ return nargc;
+ }
+
+ /* If it is not possible to allocate initial array, sign on error */
+ _errnum = ENOMEM;
+ return 0;
+}
diff --git a/theos/_stat.c b/theos/_stat.c
new file mode 100644
index 0000000..6855d28
--- /dev/null
+++ b/theos/_stat.c
@@ -0,0 +1,461 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#pragma library
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sc.h>
+#include <peek.h>
+#include <lub.h>
+#include <fdb.h>
+#include <fsa.h>
+#include "theos/stat.h"
+
+/* replacement for standard library functions stat and fstat */
+
+int _stat_(struct stat* st, struct fdb* fdb);
+int _dstat_(struct stat* st);
+
+#define peekucb() peeknuc()
+
+/* map THEOS protection code to Unix modes */
+
+unsigned short _tm2um_(char protect)
+{
+ unsigned short umask = 0;
+
+ if (!(protect & _FDB_READ_PROTECT))
+ umask = S_IRUSR|S_IRGRP;
+
+ if (!(protect & _FDB_WRITE_PROTECT))
+ umask |= S_IWUSR|S_IWGRP;
+
+ if (!(protect & _FDB_EXECUTE_PROTECT))
+ umask |= S_IXUSR|S_IXGRP;
+
+ if (!(protect & _FDB_ERASE_PROTECT))
+ umask |= S_IEUSR|S_IEGRP;
+
+ if (!(protect & _FDB_SHARED_READ_PROTECT)) {
+ if (_osmajor > 3)
+ umask |= S_IROTH|S_IXOTH;
+ else
+ umask |= S_IROTH;
+ }
+
+ if (!(protect & _FDB_SHARED_WRITE_PROTECT))
+ umask |= S_IWOTH;
+
+ if (!(protect & _FDB_MODIFIED)) {
+ if (_osmajor > 3)
+ umask |= S_IMODF;
+ else
+ umask |= S_IXOTH;
+ }
+
+ if (protect & _FDB_NOT_HIDDEN)
+ umask |= S_INHID;
+
+ return umask;
+}
+
+/* map Unix modes to THEOS protections */
+
+char _um2tm_(unsigned short mask)
+{
+ char protect = 0;
+
+ if (!(mask & (S_IRUSR|S_IRGRP)))
+ protect |= _FDB_READ_PROTECT;
+
+ if (!(mask & (S_IWUSR|S_IWGRP)))
+ protect |= _FDB_WRITE_PROTECT;
+
+ if (!(mask & (S_IXUSR|S_IXGRP)))
+ protect |= _FDB_EXECUTE_PROTECT;
+
+ if (!(mask & (S_IEUSR|S_IEGRP)))
+ protect |= _FDB_ERASE_PROTECT;
+
+ if (_osmajor < 4) {
+ if (!(mask & S_IROTH))
+ protect |= _FDB_SHARED_READ_PROTECT;
+ } else {
+ if (!(mask & (S_IROTH|S_IXOTH)))
+ protect |= _FDB_SHARED_READ_PROTECT;
+ }
+
+ if (!(mask & S_IWOTH))
+ protect |= _FDB_SHARED_WRITE_PROTECT;
+
+ if (mask & S_IMODF && _osmajor > 3)
+ protect |= _FDB_MODIFIED;
+
+ if (mask & S_INHID && _osmajor > 3)
+ protect |= _FDB_NOT_HIDDEN;
+
+ return protect;
+}
+
+/* root directory stat */
+
+static int rdirstat(const char* fn, struct stat *st)
+{
+ register char* p = strchr(fn, ':');
+ char drive;
+
+ drive = p ? p[1] : 'S';
+
+ if (drive >= 'a' && drive <= 'Z')
+ drive -= 0x40;
+
+ memset(st, 0, sizeof(struct stat));
+
+ if (getlub(drive - 'A') != 255) {
+ st->st_org = _FDB_STAT_DIRECTORY;
+ st->st_mode = S_IFDIR|S_IRUSR|S_IWUSR|S_IROTH|S_IWOTH;
+ st->st_nlink = 1;
+ st->st_dev = st->st_rdev = drive - 'A';
+ st->st_uid = st->st_gid = getuid();
+ st->st_protect = _FDB_ERASE_PROTECT;
+ return 0;
+ }
+ errno = _errnum = ENOENT;
+ _errarg = fn;
+ return -1;
+}
+
+#ifdef LOCATE_BUG
+
+/* locate fails when stating a file in root dir from a directory with a
+ * relative path. Workaround by setting directory to root dir
+ * getting the file directory block, then restoring the current directory.
+ */
+
+struct fdb* __locate(const char* fn, char* buf, short* drv)
+{
+ struct fdb* fdb;
+ char buf2[FILENAME_MAX];
+ char cwd[FILENAME_MAX];
+ char drive[3];
+ char* p;
+ char* q;
+
+ /* return if file found */
+ if (fdb = _locate(fn, buf, drv))
+ return fdb;
+
+ /* if file name does not contain a path delimiter it really does not exist.
+ */
+ strcpy(buf2, fn);
+
+ if ((p = strrchr(buf2, '/')) == NULL)
+ return NULL;
+
+ /* get drive name from file path */
+ q = strrchr(buf2, ':');
+
+ /* cat drive name if any to directory path */
+ if (q) {
+ strncpy(drive, q, 2);
+ drive[2] = '\0';
+ strcpy(p, q);
+ } else
+ *p = '\0';
+ /* save current directory */
+ getcwd(cwd, FILENAME_MAX);
+ /* chdir to directory path */
+ chdir(buf2);
+ /* get File Directory Block */
+ p = strrchr(fn, '/');
+ fdb = _locate(p + 1, buf, drv);
+ /* restore current directory */
+ chdir(cwd);
+ return fdb;
+}
+
+#undef _locate
+#define _locate() __locate()
+
+/* same cause, same consequence for fopen and open.
+*/
+
+FILE* _fopen(const char* fn, const char* mode)
+{
+ FILE* fp;
+ char buf[FILENAME_MAX];
+ short drv;
+
+ /* prepend a path to current dir to avoid use of default library */
+ if (*fn != '.' && *fn != '/') {
+ strcpy(buf, "./");
+ strcat(buf, fn);
+ return fopen(buf, mode);
+ }
+
+ if (fp = fopen(fn, mode))
+ return fp;
+
+ /* see comment for _locate */
+ if (_locate(fn, buf, &drv)) {
+ fn = strrchr(fn, '/');
+ return fopen(fn, mode);
+ }
+ return NULL;
+}
+
+#undef open
+int open(const char*, int, ...);
+
+int __open(const char* fn, int mode)
+{
+ int fd;
+ char buf[FILENAME_MAX];
+ short drv;
+
+ /* prepend a path to current dir to avoid use of default library */
+ if (*fn != '.' && *fn != '/') {
+ strcpy(buf, "./");
+ strcat(buf, fn);
+ return open(buf, mode);
+ }
+
+ if ((fd = open(fn, mode)) != EOF)
+ return fd;
+
+ /* see comment for _locate */
+ if (_locate(fn, buf, &drv)) {
+ fn = strrchr(fn, '/');
+ if (fn)
+ return open(fn, mode);
+ }
+ return EOF;
+}
+#endif
+
+/* replacement for standard file stat */
+
+int _stat(const char *_fn, struct stat *st)
+{
+ char buf[FILENAME_MAX], buf2[FILENAME_MAX], buf3[FILENAME_MAX];
+ register struct fdb* fdb;
+ register char* p;
+ register char* fn;
+
+ fn = strcpy(buf3, _fn);
+
+ if (p = strrchr(fn, ':'))
+ *p = 0;
+
+ /* on current drive ./:d and .:m point to current dir
+ * on another drive to root directory, workaround to avoid it */
+
+ if (! strcmp(fn, "/") || ! strcmp(fn, ".") || ! strcmp(fn, "./")) {
+ if (p == NULL) {
+ /* current dir on current drive */
+ fn = getcwd(buf2, FILENAME_MAX);
+ /* getcwd returns NULL on root dir on drive S */
+ if (fn == NULL)
+ fn = strcpy(buf2, "/:S");
+ /* getcwd returns /:d on root dir on any other drive */
+ if (fn[1] == ':')
+ return rdirstat(fn, st);
+ } else {
+ *p = ':';
+ return rdirstat(fn, st);
+ }
+ if (p)
+ *p = ':';
+ } else {
+ if (p)
+ *p = ':';
+ if (*fn != '.' && *fn != '/') {
+ strcpy(buf2, "./");
+ fn = strcat(buf2, fn);
+ }
+ }
+
+ if (buf2 != fn)
+ strcpy(buf2, fn);
+ /* remove trailing slash before optional disk name */
+ if (p = strrchr(buf2, '/')) {
+ if (p[1] == ':') {
+ *p = p[1];
+ p[1] = p[2];
+ p[2] = p[3];
+ } else if (p[1] == '\0')
+ *p = '\0';
+ }
+ /* if fn is a file get file directory block structure and device */
+ if (fdb = _locate(buf2, buf, &st->st_dev)) {
+ /* is it a file from another user... */
+ if (strchr(buf2, '\\')
+ /* a public system file... */
+ || fdb->fileowner == 0
+ /* or a file from the current user account ? */
+ || fdb->fileowner == getuid())
+ /* yes, return stat */
+ return _stat_(st, fdb);
+ else {
+ /* no, say file doesn't exist */
+ errno = _errnum = ENOENT;
+ _errarg = fn;
+ return -1;
+ }
+ }
+ /* else should be a device, get device number from device name */
+ st->st_rdev = st->st_dev = _lub_name(*fn == ':' ? fn+1 : fn);
+ /* if it is really a device return device status */
+ if (st->st_dev != -1 && getlub(st->st_dev) != 255)
+ return _dstat_(st);
+ /* neither an existing file or a device name, return EOF */
+ st->st_rdev = st->st_dev = 0;
+ errno = _errnum = ENOENT;
+ _errarg = fn;
+ return -1;
+}
+
+/* replacement for fstat */
+
+int _fstat(int fd, struct stat *st)
+{
+ unsigned short fsanum;
+ struct fsa fsa;
+ register FILE *fp;
+ int status;
+ register int i;
+ register char *p;
+
+ if (fd < FOPEN_MAX) {
+ fp = &stdin[fd];
+ /* get File Save Area number */
+ if (_fcntl(fp,1,0) & 0x80) {
+ fsanum = (unsigned short) _fcntl(fp,83,0);
+ st->st_dev = (unsigned short) _fcntl(fp,5,0);
+
+ if (st->st_dev >= A_DISK && st->st_dev <= Z_DISK) {
+ /* if opened file is a disk file */
+ /* copy far fsa in protected segment to local fsa */
+ for (i = 0, fsanum *= sizeof(fsa), p = (char *) &fsa;
+ i < (sizeof(fsa));
+ i++, fsanum++, p++)
+ *p = _peekfsa((char *) fsanum);
+ /* build stat structure from fsa */
+ status = _stat_(st, (struct fdb*) &fsa);
+ /* get blocksize */
+ if ((st->st_blksize = _fcntl(fp,817,0)) == 0)
+ st->st_blksize = BUFSIZ;
+ return status;
+ }
+ /* return device status */
+ return _dstat_(st);
+ }
+ }
+ errno = _errnum = EBADF;
+ return -1;
+}
+
+static int _isprt(int dev)
+{
+ return IS_PRT_LUB(dev);
+}
+
+/* device stat */
+
+int _dstat_(st)
+register struct stat* st;
+{
+ register struct ucb* ucb;
+
+ ucb = getucb(st->st_dev);
+ st->st_ino = 0;
+ if (st->st_dev <= Z_DISK
+ || (st->st_dev >= TAPE1 && st->st_dev <= TAPE4)) {
+ st->st_mode = S_IFBLK | S_IWUSR | S_IRUSR;
+ if (peekucb(&ucb->devowner) == 255)
+ st->st_mode |= S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH;
+ } else {
+ st->st_mode = S_IFCHR | S_IWUSR;
+ if (_isprt(st->st_dev))
+ st->st_mode |= S_IRUSR;
+ if (peekucb(&ucb->devowner) == 255) {
+ st->st_mode |= S_IWGRP | S_IWOTH;
+ if (_isprt(st->st_dev))
+ st->st_mode |= S_IRGRP | S_IROTH;
+ }
+ }
+ st->st_nlink = 1;
+ st->st_uid = st->st_gid = getuid();
+ st->st_size = 0;
+ st->st_atime = st->st_mtime = st->st_ctime = 0;
+ st->st_rlen = 0;
+ st->st_klen = 0;
+ st->st_grow = 0;
+ st->st_blksize = 0;
+ return 0;
+}
+
+/* regular file stat */
+
+int _stat_(st, fdb)
+register struct stat* st;
+register struct fdb* fdb;
+{
+ st->st_rdev = st->st_dev;
+ st->st_ino = 0;
+ st->st_org = fdb->filestat;
+
+ /* map fdb file status to stat mode */
+ switch (fdb->filestat) {
+ case _FDB_STAT_LIBRARY: st->st_mode = S_IFLIB; break;
+ case _FDB_STAT_DIRECTORY: st->st_mode = S_IFDIR; break;
+ case _FDB_STAT_STREAM: st->st_mode = S_IFREG; break;
+ case _FDB_STAT_RELATIVE: st->st_mode = S_IFREL; break;
+ case _FDB_STAT_KEYED: st->st_mode = S_IFKEY; break;
+ case _FDB_STAT_INDEXED: st->st_mode = S_IFIND; break;
+ case _FDB_STAT_RANDOM: st->st_mode = S_IFRND; break;
+ case _FDB_STAT_PROGRAM: st->st_mode = S_IFR16; break;
+ case _FDB_STAT_16_BIT_PROGRAM: st->st_mode = S_IFP16; break;
+ case _FDB_STAT_32_BIT_PROGRAM: st->st_mode = S_IFP32; break;
+ }
+
+ /* map theos file protection codes to stat mode */
+ st->st_mode |= _tm2um_(st->st_protect = fdb->protect);
+ st->st_nlink = 1;
+ st->st_uid = st->st_gid = fdb->fileowner;
+ st->st_size = fdb->filesize;
+ st->st_atime = st->st_mtime = st->st_ctime = getfiledate(fdb);
+ st->st_blksize = 0;
+ /* specific theos information */
+ st->st_rlen = fdb->reclen;
+ st->st_klen = fdb->keylen;
+ st->st_grow = fdb->filegrow;
+ return 0;
+}
+
+#include <direct.h>
+
+/* standard diropen fails on path endung with a '/', workaround */
+
+struct dirent* _opendir(const char* dirpath)
+{
+ int l;
+ char dirp[FILENAME_MAX];
+ struct dirent* dir;
+
+ if (dirpath && (l = strlen(dirpath))) {
+ if (dirpath[l - 1] == '/') {
+ strcpy(dirp, dirpath);
+ dirp[l - 1] = '\0';
+ return opendir(dirp);
+ }
+ }
+ return opendir(dirpath);
+}
diff --git a/theos/charconv.h b/theos/charconv.h
new file mode 100644
index 0000000..3189170
--- /dev/null
+++ b/theos/charconv.h
@@ -0,0 +1,93 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#ifdef IZ_THS2ISO_ARRAY
+ZCONST uch Far ths2iso[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 80 - 87 */
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 88 - 8F */
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 90 - 97 */
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 98 - 9F */
+ 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, /* A0 - A7 */
+ 0x2B, 0x2D, 0x7C, 0x2B, 0x2B, 0x2B, 0x2B, 0x23, /* A8 - AF */
+ 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, /* B0 - B7 */
+ 0x3D, 0x23, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, /* B8 - BF */
+ 0xC4, 0xE4, 0xE2, 0xE0, 0xE1, 0xC9, 0xEB, 0xEA, /* C0 - C7 */
+ 0xE8, 0xE9, 0xEF, 0xEE, 0xEC, 0xED, 0xD6, 0xF6, /* C8 - CF */
+ 0xF4, 0xF2, 0xF3, 0xDC, 0xFC, 0xFB, 0xF9, 0xFA, /* D0 - D7 */
+ 0xC7, 0xE7, 0xD1, 0xF1, 0xC6, 0xE6, 0xC5, 0xE5, /* D8 - DF */
+ 0xDF, 0xBF, 0xA1, 0xA2, 0xA3, 0xA5, 0xB5, 0xA4, /* E0 - E7 */
+ 0xBC, 0xBD, 0xFF, 0xA7, 0xB0, 0xB2, 0x20, 0x20, /* E8 - EF */
+ 0x20, 0xB1, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* F0 - F7 */
+ 0x20, 0x20, 0xB7, 0x20, 0x20, 0x20, 0x20, 0x20 /* F8 - FF */
+};
+#endif /* IZ_THS2ISO_ARRAY */
+
+#ifdef IZ_THS2OEM_ARRAY
+ZCONST uch Far ths2oem[] = {
+ 254,254,254,254, 254,254,134,135, /* 80 - 87 */
+ 136,137,138,139, 140,141,142,143, /* 88 - 8F */
+ 144,145,146,147, 148,149,150,151, /* 90 - 97 */
+ 152,153,154,155, 156,157,158,159, /* 98 - 9F */
+ 218,191,217,192, 197,195,180,194, /* A0 - A7 */
+ 193,196,179,218, 191,217,192,201, /* A8 - AF */
+ 183,188,200,206, 199,182,203,202, /* B0 - B7 */
+ 205,186,186,187, 188,189,190,191, /* B8 - BF */
+ 142,132,131,133, 160,144,137,136, /* C0 - C7 */
+ 138,130,139,140, 141,161,153,148, /* C8 - CF */
+ 147,149,162,154, 129,150,151,163, /* D0 - D7 */
+ 128,135,165,164, 146,145,143,134, /* D8 - DF */
+ 225,168,173,155, 156,157,158, 31, /* E0 - E7 */
+ 172,171,152, 21, 248,253,238,239, /* E8 - EF */
+ 240,241,242,243, 244,245,246,247, /* F0 - F7 */
+ 248,249,250,251, 252,253,254,255 /* F8 - FF */
+};
+#endif /* IZ_THS2OEM_ARRAY */
+
+#ifdef IZ_ISO2THS_ARRAY
+ZCONST uch Far iso2ths[] = {
+ 0x3F, 0x3F, 0x27, 0x3F, 0x22, 0x2E, 0xA4, 0xB3, /* 80 - 87 */
+ 0x5E, 0x25, 0x53, 0x3C, 0x4F, 0x3F, 0x3F, 0x3F, /* 88 - 8F */
+ 0x3F, 0x27, 0x27, 0x22, 0x22, 0x07, 0x2D, 0x2D, /* 90 - 97 */
+ 0x7E, 0x54, 0x73, 0x3E, 0x6F, 0x3F, 0x3F, 0x59, /* 98 - 9F */
+ 0x20, 0xE2, 0xE3, 0xE4, 0xE7, 0xE5, 0x7C, 0xEB, /* A0 - A7 */
+ 0x20, 0x20, 0x20, 0x22, 0x20, 0x2D, 0x20, 0x2D, /* A8 - AF */
+ 0xEC, 0xF1, 0xED, 0x20, 0x20, 0xE6, 0x20, 0xFA, /* B0 - B7 */
+ 0x20, 0x20, 0x20, 0x22, 0xE8, 0xE9, 0x20, 0xE1, /* B8 - BF */
+ 0xC3, 0xC4, 0xC2, 0x41, 0xC0, 0xDE, 0xDC, 0xD8, /* C0 - C7 */
+ 0xC8, 0xC5, 0xC7, 0xC6, 0xCC, 0xCD, 0xCB, 0xCA, /* C8 - CF */
+ 0x44, 0xDA, 0xD1, 0xD2, 0xD0, 0x4F, 0xCE, 0x78, /* D0 - D7 */
+ 0x4F, 0xD6, 0xD7, 0xD5, 0xD3, 0x59, 0x20, 0xE0, /* D8 - DF */
+ 0xC3, 0xC4, 0xC2, 0x61, 0xC1, 0xDF, 0xDD, 0xD9, /* E0 - E7 */
+ 0xC8, 0xC9, 0xC7, 0xC6, 0xCC, 0xCD, 0xCB, 0xCA, /* E8 - EF */
+ 0x64, 0xDB, 0xD1, 0xD2, 0xD0, 0x4F, 0xCF, 0xF1, /* F0 - F7 */
+ 0x6F, 0xD6, 0xD7, 0xD5, 0xD4, 0x79, 0x20, 0xEA /* F8 - FF */
+};
+#endif /* IZ_ISO2THS_ARRAY */
+
+#ifdef IZ_OEM2THS_ARRAY
+ZCONST uch Far oem2ths[] = {
+ 216,212,201,194, 193,195,223,217, /* 80 - 87 */
+ 199,198,200,202, 203,204,192,222, /* 88 - 8F */
+ 197,221,220,208, 207,209,213,214, /* 90 - 97 */
+ 234,206,211,227, 228,229,230,159, /* 98 - 9F */
+ 196,205,210,215, 219,218,254,254, /* A0 - A7 */
+ 225,254,254,233, 232,226, 34, 34, /* A8 - AF */
+ 254,254,254,170, 166,166,181,176, /* B0 - B7 */
+ 161,181,185,176, 177,177,162,161, /* B8 - BF */
+ 163,168,167,165, 169,164,165,180, /* C0 - C7 */
+ 178,175,183,182, 180,184,179,168, /* C8 - CF */
+ 183,167,182,178, 163,160,175,179, /* D0 - D7 */
+ 164,162,160,254, 254,254,254,254, /* D8 - DF */
+ 254,224,254,254, 254,254,254, 31, /* E0 - E7 */
+ 254,254,254, 21, 254,254,238,239, /* E8 - EF */
+ 240,241,242,243, 244,245,246,247, /* F0 - F7 */
+ 236,249,250,251, 252,237,254,255 /* F8 - FF */
+};
+#endif /* IZ_OEM2THS_ARRAY */
+
diff --git a/theos/osdep.h b/theos/osdep.h
new file mode 100644
index 0000000..4f4857e
--- /dev/null
+++ b/theos/osdep.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * XXX this should somehow depend on the stuff in revision.h
+ */
+#pragma prog 2.3,0,0,0
+
+/* use argument expansion */
+#if !defined(UTIL) && !defined(MAINWA_BUG)
+# pragma wild argv
+#endif
+
+#include <stdio.h>
+#include <malloc.h>
+#include <handle.h>
+#include <conio.h>>
+#include <locale.h>
+#include <sys/types.h>
+#include "theos/stat.h" /* use JMD's extended stat function */
+
+#define isatty() _isatty() /* THEOS isatty uses a FILE* instead of a fd */
+int _isatty(int fd);
+
+#define deletedir(d) rmdir(d)
+
+/* will come later */
+#if 0
+#define USE_EF_UT_TIME /* Enable use of "UT" extra field time info */
+#endif
+
+#if DEBUG
+int _fprintf(FILE* fp, const char* fmt, ...);
+#endif
+
+/* for rename() replacement. Standard function is bugged */
+
+int _rename(const char* old, const char* new);
+#define rename(a,b) _rename(a,b)
+
+#ifdef LOCATE_BUG
+/* for fopen replacement. Standard function fails on relative path pointing
+ * to root directory.
+ */
+#undef _fopen
+#undef open
+#define fopen() _fopen()
+FILE* _fopen(const char*, const char*);
+#define open() __open()
+FILE* __open(const char*, int);
+#endif
+
+#define EXDEV 10000
diff --git a/theos/stat.h b/theos/stat.h
new file mode 100644
index 0000000..ffcec0f
--- /dev/null
+++ b/theos/stat.h
@@ -0,0 +1,106 @@
+#ifndef __theos_stat_h
+#define __theos_stat_h
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* extended stat structure for stat, fstat, chmod */
+/* Written by Jean-Michel Dubois */
+
+#pragma field word
+struct stat {
+ unsigned short st_mode; /* file attributes */
+ #define S_IFMT 0xf000 /* file type mask */
+ #define S_IFIFO 0x1000 /* pipe */
+ #define S_IFCHR 0x2000 /* char device */
+ #define S_IFSOCK 0x3000 /* socket */
+ #define S_IFDIR 0x4000 /* directory */
+ #define S_IFLIB 0x5000 /* library */
+ #define S_IFBLK 0x6000 /* block device */
+ #define S_IFREG 0x8000 /* regular file */
+ #define S_IFREL 0x9000 /* relative (direct) */
+ #define S_IFKEY 0xA000 /* keyed */
+ #define S_IFIND 0xB000 /* indexed */
+ #define S_IFRND 0xC000 /* ???? */
+ #define S_IFR16 0xD000 /* 16 bit real mode program */
+ #define S_IFP16 0xE000 /* 16 bit protected mode prog */
+ #define S_IFP32 0xF000 /* 32 bit protected mode prog */
+
+ #define S_ISUID 0x0800 /* meaningless */
+ #define S_ISGID 0x0400 /* meaningless */
+ #define S_ISVTX 0x0200 /* meaningless */
+
+ #define S_IMODF 0x0800 /* modified */
+ #define S_INHID 0x0400 /* not hidden */
+
+ #define S_IRWXU 0x03c0 /* read,write,execute: owner */
+ #define S_IEUSR 0x0200 /* erase permission: owner */
+ #define S_IRUSR 0x0100 /* read permission: owner */
+ #define S_IWUSR 0x0080 /* write permission: owner */
+ #define S_IXUSR 0x0040 /* execute permission: owner */
+ /* group permissions */
+ #define S_IRWXG 0x0238
+ #define S_IEGRP 0x0200
+ #define S_IRGRP 0x0020
+ #define S_IWGRP 0x0010
+ #define S_IXGRP 0x0008
+ /* other never has erase permission */
+ #define S_IRWXO 0x0207 /* read,write,execute: other */
+ #define S_IROTH 0x0004 /* read permission: other */
+ #define S_IWOTH 0x0002 /* write permission: other */
+ #define S_IXOTH 0x0001 /* execute permission: other */
+
+ #define S_IREAD 0x0100 /* read permission, owner */
+ #define S_IEXEC 0x0040 /* execute permission, owner */
+ #define S_IWRITE 0x0080 /* write permission, owner */
+ short st_ino; /* not used */
+ short st_dev; /* not used */
+ short st_rdev; /* not used */
+ short st_nlink; /* not used */
+ short st_uid; /* owner id */
+ short st_gid; /* not used */
+ unsigned long st_size; /* size of file */
+ unsigned long st_atime; /* not used */
+ unsigned long st_mtime; /* date & time last modified */
+ unsigned long st_ctime; /* not used */
+ unsigned long st_blksize; /* buffer size */
+ unsigned short st_org; /* organization */
+ unsigned short st_rlen; /* record size */
+ unsigned short st_klen; /* key size */
+ char st_grow; /* growing factor */
+ char st_protect; /* native protections */
+};
+#pragma field
+
+#define S_ISREG(m) (((m) & S_IFMT) >= S_IFREG)
+#define S_ISLIB(m) (((m) & S_IFMT) == S_IFLIB)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+
+#define S_ISSEQ(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISREL(m) (((m) & S_IFMT) == S_IFREL)
+#define S_ISKEY(m) (((m) & S_IFMT) == S_IFKEY)
+#define S_ISIND(m) (((m) & S_IFMT) == S_IFIND)
+#define S_ISPRG(m) (((m) & S_IFMT) >= S_IFP16)
+#define S_ISLNK(m) 0
+
+/* avoid conflict with original THEOS functions */
+
+#define stat(a,b) _stat(a,b)
+#define fstat(a,b) _fstat(a,b)
+#define chmod(a,b) _chmod(a,b)
+
+extern int _stat(const char *file, struct stat *statptr);
+extern int _fstat(int fd, struct stat *statptr);
+extern int _chmod(const char *file, short mask);
+
+#define _chstat(a,b) ((int) _sc_168(a,'p',(size_t)(b)))
+extern unsigned short _sc_168(const char _far *fn, int cmd, size_t value);
+
+#endif /* !__theos_stat_h */
diff --git a/theos/theos.c b/theos/theos.c
new file mode 100644
index 0000000..5da3f8b
--- /dev/null
+++ b/theos/theos.c
@@ -0,0 +1,556 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ theos.c (zip)
+
+ Contribution by Jean-Michel Dubois. 20-Jun-1995, 20-Dec-98
+
+ THEOS specific extra informations
+
+ ---------------------------------------------------------------------------*/
+
+
+#include <stdio.h>
+
+#ifndef UTIL
+
+#include "zip.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include <sc.h>
+#include <direct.h>
+#include <sys/utime.h>
+
+#define opendir(a) _opendir(a)
+extern struct dirent* _opendir(char* fname);
+
+#define PAD 0
+
+#define RET_ERROR 1
+#define RET_SUCCESS 0
+#define RET_EOF 0
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* match from Phase One Systems */
+
+int match(char *s, char *p) /*S Returns non-zero if string matches
+ the literal mask */
+{
+ int matched, k;
+
+ if (!(*p))
+ return 1;
+ for(;;) {
+ if ( (!(*s)) && (!(*p)) )
+ return(1);
+ else if ( !(*p) )
+ return(0);
+ else if (*p == '*') {
+ if (!*(p+1))
+ return(1);
+ k=0;
+ do {
+ matched = match(s+k,p+1);
+ k++;
+ } while ( (!matched) && *(s+k));
+ return(matched);
+ } else if (*p == '@') {
+ if (!((*s >= 'a' && *s <= 'z')
+ ||(*s >= 'A' && *s <= 'Z')))
+ return(0);
+ } else if (*p == '#') {
+ if (*s < '0' || *s > '9')
+ return(0);
+ } else if (*p != '?') {
+ if (tolower(*s) != tolower(*p))
+ return(0);
+ }
+ s++; p++;
+ }
+}
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+/* check if file is a member of a library */
+
+int ismember(char* path)
+{
+ char* p;
+
+ if ((p = strrchr(path, '/')) == NULL)
+ p = path;
+ return ((p = strchr(p, '.')) && (p = strchr(p + 1, '.')));
+}
+
+/* extract library name from a file name */
+
+char* libname(char* path)
+{
+ char* p;
+ static char lib[FILENAME_MAX];
+ char drive[3];
+
+ strcpy(lib, path);
+ if (p = strrchr(lib, ':')) {
+ strncpy(drive, p, 2);
+ drive[2] = '\0';
+ *p = '\0' ;
+ } else
+ drive[0] = '\0';
+
+ if ((p = strrchr(lib, '/')) == NULL)
+ p = lib;
+
+ p = strchr(p, '.');
+ p = strchr(p + 1, '.');
+ *p = 0;
+ strcat(lib, drive);
+ return lib;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist *z; /* steps through zfiles list */
+ struct flist *f; /* steps through files list */
+ char* path; /* full name */
+ char drive[3]; /* drive name */
+ int recursion; /* save recurse flag */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s)) {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (match(z->iname, p))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory or library */
+ if (S_ISREG(s.st_mode)) {
+ if ((path = malloc(strlen(n) + 2)) == NULL)
+ return ZE_MEM;
+
+ strcpy(path, n);
+
+ /* if member name, include library name before any member name */
+ if (ismember(path)) {
+ strcpy(path, libname(path));
+ /* mask recursion flag to avoid endless loop recursion
+ * if -r is used with member names
+ */
+ recursion = recurse;
+ recurse = FALSE;
+ if ((m = procname(path, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", path);
+ else
+ ziperr(m, a);
+ }
+ /* restore recursion flag */
+ recurse = recursion;
+ }
+
+ strcpy(path, n);
+
+ if ((p = strchr(path, ':')) != NULL) {
+ p[2] = '\0';
+ strcpy(drive, p);
+ } else
+ drive[0] = '\0';
+
+ /* remove trailing dot in flat file name */
+ p = strend(path) - 1;
+ if (*p == '.')
+ *p = '\0';
+
+ strcat(path, drive);
+ /* add or remove name of file */
+ if ((m = newname(path, 0, caseflag)) != ZE_OK) {
+ free(path);
+ return m;
+ }
+ free(path);
+ } else if (S_ISLIB(s.st_mode)) {
+ if ((path = malloc(strlen(n) + 2)) == NULL)
+ return ZE_MEM;
+
+ strcpy(path, n);
+
+ if ((p = strchr(path, ':')) != NULL) {
+ p[2] = '\0';
+ strcpy(drive, p);
+ } else
+ drive[0] = '\0';
+
+ /* add a trailing dot in flat file name... */
+ p = strend(path) - 1;
+ if (*p != '/')
+ strcat(path, "/");
+ p = strend(path);
+ /* ... then add drive name */
+ strcpy(p, drive);
+
+ /* don't include the library name twice... or more */
+ for (f = found; f != NULL; f = f->nxt) {
+ if (! stricmp(path, f->name)) {
+ free(path);
+ return ZE_OK;
+ }
+ }
+ /* add or remove name of library */
+ if ((m = newname(path, 0, caseflag)) != ZE_OK) {
+ free(path);
+ return m;
+ }
+ /* recurse into library if required */
+ strcpy(p - 1, ".*");
+ strcat(p, drive);
+ if (recurse && diropen(path) == 0)
+ {
+ while ((e = dirread()) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if (*drive == '\0')
+ *strchr(e, ':') = '\0';
+ if ((a = malloc(strlen(e) + 1)) == NULL)
+ {
+ dirclose();
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcpy(a, e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ dirclose();
+ }
+ free(path);
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ }
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ char *p;
+ int dosflag;
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ for (t = x; *t == '/'; t++)
+ ;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ t = last(t, '/');
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+
+ strcpy(n, t);
+ if (p = strchr(n, ':'))
+ *p = '\0';
+ for (p = n; *p = tolower(*p); p++);
+
+ if (isdir == 42) return n; /* avoid warning on unused variable */
+
+ if (dosify)
+ msname(n);
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+ return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ struct utimbuf u; /* argument for utime() const ?? */
+
+ /* Convert DOS time to time_t format in u */
+ u.actime = u.modtime = dos2unixtime(d);
+ utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. Bits 8 to 15 contains native THEOS protection
+ code. If n is not NULL, store the file size there. If t is not NULL,
+ the file's access, modification and creation times are stored there as
+ UNIX time_t values. If f is "-", use standard input as the file. If f is
+ a device, return a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* from FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+
+ if (name[len - 1] == '/' || name[len - 1] == '.')
+ name[len - 1] = '\0';
+
+ /* not all systems allow stat'ing a file with / appended */
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFMT) == S_IFDIR
+ || (s.st_mode & S_IFMT) == S_IFLIB) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ /* Map Theos' hidden attribute to DOS's hidden attribute */
+ if (!(st.st_protect & 0x80))
+ *a |= MSDOS_HIDDEN_ATTR;
+ *a |= ((ulg) s.st_protect) << 8;
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = t->mtime; /* best guess, (s.st_ctime: last status change!!) */
+ }
+ return unix2dostime(&s.st_mtime);
+}
+/*
+ * Get file THEOS attributes and store them into extent fields.
+ * On error leave z intact.
+ */
+
+/*
+* Extra record format
+* ===================
+* signature (2 bytes) = 'T','h'
+* size (2 bytes)
+* flags (1 byte)
+* filesize (4 bytes)
+* keylen (2 bytes)
+* reclen (2 bytes)
+* filegrow (1 byte)
+* reserved (4 bytes)
+*/
+
+#define EB_L_THSIZE 4
+#define EB_L_TH_SIZE 14
+
+int set_extra_field(z, z_utim)
+ struct zlist *z;
+ iztimes *z_utim;
+ /* store full data in local header but just modification time stamp info
+ in central header */
+{
+ char *extra = NULL;
+ char *p;
+ char c;
+ struct stat st;
+ int status;
+
+ if (status = stat(z->name, &st)) {
+ p = &z->name[strlen(z->name) - 1];
+ if (*p == '/' || *p == '.') {
+ c = *p;
+ *p = '\0';
+ status = stat(z->name, &st);
+ *p = c;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "set_extra_field: stat for file %s:\n status = %d\n",
+ z->name, status);
+#endif
+ if (status)
+ return RET_ERROR;
+ }
+
+ if ((extra = malloc(EB_L_TH_SIZE)) == NULL ) {
+ fprintf(stderr, "set_extra_field: Insufficient memory.\n" );
+ return RET_ERROR;
+ }
+
+
+ extra[0] = 'T';
+ extra[1] = 'h';
+ extra[2] = EB_L_TH_SIZE;
+ extra[3] = EB_L_TH_SIZE >> 8;
+ extra[4] = 0;
+ extra[5] = st.st_size;
+ extra[6] = st.st_size >> 8;
+ extra[7] = st.st_size >> 16;
+ extra[8] = st.st_size >> 24;
+ extra[9] = st.st_org;
+ extra[10] = st.st_rlen;
+ extra[11] = st.st_rlen >> 8;
+ extra[12] = st.st_klen;
+ extra[13] = st.st_klen >> 8;
+ extra[14] = st.st_grow;
+ extra[15] = st.st_protect;
+ extra[16] = 0;
+ extra[17] = 0;
+ z->ext = z->cext = EB_L_TH_SIZE + EB_HEADSIZE;
+ z->extra = z->cextra = extra;
+ return RET_SUCCESS;
+}
+#endif
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ printf("Compiled with THEOS C 5.28 for THEOS 4.x on %s %s.\n\n",
+ __DATE__, __TIME__);
+}
+
diff --git a/theos/zipup.h b/theos/zipup.h
new file mode 100644
index 0000000..1de3f61
--- /dev/null
+++ b/theos/zipup.h
@@ -0,0 +1,19 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+#define fhow O_RDONLY
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/timezone.c b/timezone.c
new file mode 100644
index 0000000..485ec02
--- /dev/null
+++ b/timezone.c
@@ -0,0 +1,815 @@
+/*
+ timezone.c - Zip 3
+
+ Copyright (c) 1990-2004 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2003-May-08 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* Replacement time library functions, based on platform independent public
+ * domain timezone code from ftp://elsie.nci.nih.gov/pub, with mktime and
+ * mkgmtime from our own mktime.c in Zip.
+ *
+ * Contains: tzset()
+ * __tzset()
+ * gmtime()
+ * localtime()
+ * mktime()
+ * mkgmtime()
+ * GetPlatformLocalTimezone() [different versions]
+ */
+
+/* HISTORY/CHANGES
+ * 17 Jun 00, Paul Kienitz, added the PD-based tzset(), localtime(), and so on
+ * to amiga/filedate.c, replacing GNU-based functions which had
+ * replaced time_lib.c, both having been rejected for licensing
+ * reasons. Support for timezone files and leap seconds was removed.
+ *
+ * 23 Aug 00, Paul Kienitz, split into separate timezone.c file, made platform
+ * independent, copied in mktime() and mkgmtime() from Zip, renamed
+ * locale_TZ as GetPlatformLocalTimezone(), for use as a generic
+ * hook by other platforms.
+ */
+
+#ifndef __timezone_c
+#define __timezone_c
+
+
+#include "zip.h"
+#include "timezone.h"
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef IZTZ_DEFINESTDGLOBALS
+long timezone = 0;
+int daylight = 0;
+char *tzname[2];
+#endif
+
+#ifndef IZTZ_GETLOCALETZINFO
+# define IZTZ_GETLOCALETZINFO(ptzstruct, pgenrulefunct) (FALSE)
+#endif
+
+int real_timezone_is_set = FALSE; /* set by tzset() */
+
+
+#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
+#define TZDEFAULT "EST5EDT"
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define EPOCH_WDAY 4 /* Jan 1, 1970 was thursday */
+#define EPOCH_YEAR 1970
+#define TM_YEAR_BASE 1900
+#define FIRST_GOOD_YEAR ((time_t) -1 < (time_t) 1 ? EPOCH_YEAR-68 : EPOCH_YEAR)
+#define LAST_GOOD_YEAR (EPOCH_YEAR + ((time_t) -1 < (time_t) 1 ? 67 : 135))
+
+#define YDAYS(month, year) yr_days[leap(year)][month]
+
+/* Nonzero if `y' is a leap year, else zero. */
+#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/* Number of leap years from EPOCH_YEAR to `y' (not including `y' itself). */
+#define _P4 ((EPOCH_YEAR / 4) * 4 + 1)
+#define _P100 ((EPOCH_YEAR / 100) * 100 + 1)
+#define _P400 ((EPOCH_YEAR / 400) * 400 + 1)
+#define nleap(y) (((y) - _P4) / 4 - ((y) - _P100) / 100 + ((y) - _P400) / 400)
+
+/* Length of month `m' (0 .. 11) */
+#define monthlen(m, y) (yr_days[0][(m)+1] - yr_days[0][m] + \
+ ((m) == 1 && leap(y)))
+
+/* internal module-level constants */
+#ifndef IZ_MKTIME_ONLY
+static ZCONST char gmt[] = "GMT";
+static ZCONST int mon_lengths[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+#endif /* !IZ_MKTIME_ONLY */
+static ZCONST int yr_days[2][MONSPERYEAR+1] = {
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+#ifndef IZ_MKTIME_ONLY
+static ZCONST int year_lengths[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+/* internal variables */
+static struct state statism;
+
+
+/* prototypes of static functions */
+static time_t transtime OF((ZCONST time_t janfirst, ZCONST int year,
+ ZCONST struct rule * ZCONST rulep,
+ ZCONST long offset));
+static void generate_transitions OF((register struct state * ZCONST sp,
+ ZCONST struct rule * ZCONST start,
+ ZCONST struct rule * ZCONST end));
+static ZCONST char *getzname OF((ZCONST char *strp));
+static ZCONST char *getnum OF((ZCONST char *strp, int * ZCONST nump,
+ ZCONST int min, ZCONST int max));
+static ZCONST char *getsecs OF((ZCONST char *strp, long * ZCONST secsp));
+static ZCONST char *getoffset OF((ZCONST char *strp, long * ZCONST offsetp));
+static ZCONST char *getrule OF((ZCONST char *strp, struct rule * ZCONST rulep));
+static int Parse_TZ OF((ZCONST char *name, register struct state * ZCONST sp));
+
+
+static time_t transtime(janfirst, year, rulep, offset)
+ ZCONST time_t janfirst;
+ ZCONST int year;
+ ZCONST struct rule * ZCONST rulep;
+ ZCONST long offset;
+{
+ register int leapyear;
+ register time_t value;
+ register int i;
+ int d, m1, yy0, yy1, yy2, dow;
+
+ value = 0;
+ leapyear = leap(year);
+ switch (rulep->r_type) {
+
+ case JULIAN_DAY:
+ /*
+ ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
+ ** years.
+ ** In non-leap years, or if the day number is 59 or less, just
+ ** add SECSPERDAY times the day number-1 to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
+ if (leapyear && rulep->r_day >= 60)
+ value += SECSPERDAY;
+ break;
+
+ case DAY_OF_YEAR:
+ /*
+ ** n - day of year.
+ ** Just add SECSPERDAY times the day number to the time of
+ ** January 1, midnight, to get the day.
+ */
+ value = janfirst + rulep->r_day * SECSPERDAY;
+ break;
+
+ case MONTH_NTH_DAY_OF_WEEK:
+ /*
+ ** Mm.n.d - nth "dth day" of month m.
+ */
+ value = janfirst;
+/*
+ for (i = 0; i < rulep->r_mon - 1; ++i)
+ value += mon_lengths[leapyear][i] * SECSPERDAY;
+*/
+ value += yr_days[leapyear][rulep->r_mon - 1] * SECSPERDAY;
+
+ /*
+ ** Use Zeller's Congruence to get day-of-week of first day of
+ ** month.
+ */
+ m1 = (rulep->r_mon + 9) % 12 + 1;
+ yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
+ yy1 = yy0 / 100;
+ yy2 = yy0 % 100;
+ dow = ((26 * m1 - 2) / 10 +
+ 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
+ if (dow < 0)
+ dow += DAYSPERWEEK;
+
+ /*
+ ** "dow" is the day-of-week of the first day of the month. Get
+ ** the day-of-month (zero-origin) of the first "dow" day of the
+ ** month.
+ */
+ d = rulep->r_day - dow;
+ if (d < 0)
+ d += DAYSPERWEEK;
+ for (i = 1; i < rulep->r_week; ++i) {
+ if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1])
+ break;
+ d += DAYSPERWEEK;
+ }
+
+ /*
+ ** "d" is the day-of-month (zero-origin) of the day we want.
+ */
+ value += d * SECSPERDAY;
+ break;
+ }
+
+ /*
+ ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
+ ** question. To get the Epoch-relative time of the specified local
+ ** time on that day, add the transition time and the current offset
+ ** from UTC.
+ */
+ return value + rulep->r_time + offset;
+}
+
+static void generate_transitions(sp, start, end)
+ register struct state * ZCONST sp;
+ ZCONST struct rule * ZCONST start;
+ ZCONST struct rule * ZCONST end;
+{
+ register int year;
+ register time_t janfirst;
+ time_t starttime;
+ time_t endtime;
+ long stdoffset = -sp->ttis[0].tt_gmtoff;
+ long dstoffset = -sp->ttis[1].tt_gmtoff;
+ register time_t * atp;
+ register unsigned char * typep;
+
+ /*
+ ** Two transitions per year, from EPOCH_YEAR to LAST_GOOD_YEAR.
+ */
+ sp->timecnt = 2 * (LAST_GOOD_YEAR - EPOCH_YEAR + 1);
+ atp = sp->ats;
+ typep = sp->types;
+ janfirst = 0;
+ for (year = EPOCH_YEAR; year <= LAST_GOOD_YEAR; ++year) {
+ starttime = transtime(janfirst, year, start, stdoffset);
+ endtime = transtime(janfirst, year, end, dstoffset);
+ if (starttime > endtime) {
+ *atp++ = endtime;
+ *typep++ = 0; /* DST ends */
+ *atp++ = starttime;
+ *typep++ = 1; /* DST begins */
+ } else {
+ *atp++ = starttime;
+ *typep++ = 1; /* DST begins */
+ *atp++ = endtime;
+ *typep++ = 0; /* DST ends */
+ }
+ janfirst += year_lengths[leap(year)] * SECSPERDAY;
+ }
+}
+
+static ZCONST char *getzname(strp)
+ ZCONST char *strp;
+{
+ register char c;
+
+ while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
+ c != '+')
+ ++strp;
+ return strp;
+}
+
+static ZCONST char *getnum(strp, nump, min, max)
+ ZCONST char *strp;
+ int * ZCONST nump;
+ ZCONST int min;
+ ZCONST int max;
+{
+ register char c;
+ register int num;
+
+ if (strp == NULL || !isdigit(c = *strp))
+ return NULL;
+ num = 0;
+ do {
+ num = num * 10 + (c - '0');
+ if (num > max)
+ return NULL; /* illegal value */
+ c = *++strp;
+ } while (isdigit(c));
+ if (num < min)
+ return NULL; /* illegal value */
+ *nump = num;
+ return strp;
+}
+
+static ZCONST char *getsecs(strp, secsp)
+ ZCONST char *strp;
+ long * ZCONST secsp;
+{
+ int num;
+
+ /*
+ ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
+ ** "M10.4.6/26", which does not conform to Posix,
+ ** but which specifies the equivalent of
+ ** ``02:00 on the first Sunday on or after 23 Oct''.
+ */
+ strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp = num * (long) SECSPERHOUR;
+ if (*strp == ':') {
+ ++strp;
+ strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num * SECSPERMIN;
+ if (*strp == ':') {
+ ++strp;
+ /* `SECSPERMIN' allows for leap seconds. */
+ strp = getnum(strp, &num, 0, SECSPERMIN);
+ if (strp == NULL)
+ return NULL;
+ *secsp += num;
+ }
+ }
+ return strp;
+}
+
+static ZCONST char *getoffset(strp, offsetp)
+ ZCONST char *strp;
+ long * ZCONST offsetp;
+{
+ register int neg = 0;
+
+ if (*strp == '-') {
+ neg = 1;
+ ++strp;
+ } else if (*strp == '+')
+ ++strp;
+ strp = getsecs(strp, offsetp);
+ if (strp == NULL)
+ return NULL; /* illegal time */
+ if (neg)
+ *offsetp = -*offsetp;
+ return strp;
+}
+
+static ZCONST char *getrule(strp, rulep)
+ ZCONST char *strp;
+ struct rule * ZCONST rulep;
+{
+ if (*strp == 'J') {
+ /*
+ ** Julian day.
+ */
+ rulep->r_type = JULIAN_DAY;
+ ++strp;
+ strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
+ } else if (*strp == 'M') {
+ /*
+ ** Month, week, day.
+ */
+ rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
+ ++strp;
+ strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_week, 1, 5);
+ if (strp == NULL)
+ return NULL;
+ if (*strp++ != '.')
+ return NULL;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
+ } else if (isdigit(*strp)) {
+ /*
+ ** Day of year.
+ */
+ rulep->r_type = DAY_OF_YEAR;
+ strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
+ } else return NULL; /* invalid format */
+ if (strp == NULL)
+ return NULL;
+ if (*strp == '/') {
+ /*
+ ** Time specified.
+ */
+ ++strp;
+ strp = getsecs(strp, &rulep->r_time);
+ } else
+ rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
+ return strp;
+}
+
+static int Parse_TZ(name, sp)
+ ZCONST char *name;
+ register struct state * ZCONST sp;
+{
+ ZCONST char * stdname;
+ ZCONST char * dstname;
+ size_t stdlen;
+ size_t dstlen;
+ long stdoffset;
+ long dstoffset;
+ register char * cp;
+
+ dstname = NULL;
+ stdname = name;
+ name = getzname(name);
+ stdlen = name - stdname;
+ if (stdlen < 3)
+ return -1;
+ if (*name == '\0')
+ return -1;
+ name = getoffset(name, &stdoffset);
+ if (name == NULL)
+ return -1;
+ if (*name != '\0') {
+ dstname = name;
+ name = getzname(name);
+ dstlen = name - dstname; /* length of DST zone name */
+ if (dstlen < 3)
+ return -1;
+ if (*name != '\0' && *name != ',' && *name != ';') {
+ name = getoffset(name, &dstoffset);
+ if (name == NULL)
+ return -1;
+ } else
+ dstoffset = stdoffset - SECSPERHOUR;
+ if (*name == '\0')
+ name = TZDEFRULESTRING;
+ if (*name == ',' || *name == ';') {
+ struct rule start;
+ struct rule end;
+
+ ++name;
+ if ((name = getrule(name, &start)) == NULL)
+ return -1;
+ if (*name++ != ',')
+ return -1;
+ if ((name = getrule(name, &end)) == NULL)
+ return -1;
+ if (*name != '\0')
+ return -1;
+ sp->typecnt = 2; /* standard time and DST */
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ sp->ttis[1].tt_gmtoff = -dstoffset;
+ sp->ttis[1].tt_isdst = 1;
+ sp->ttis[1].tt_abbrind = stdlen + 1;
+ generate_transitions(sp, &start, &end);
+ }
+ } else {
+ dstlen = 0;
+ sp->typecnt = 1; /* only standard time */
+ sp->timecnt = 0;
+ sp->ttis[0].tt_gmtoff = -stdoffset;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ }
+ sp->charcnt = stdlen + 1;
+ if (dstlen != 0)
+ sp->charcnt += dstlen + 1;
+ if ((size_t) sp->charcnt > sizeof(sp->chars))
+ return -1;
+ cp = sp->chars;
+ (void) strncpy(cp, stdname, stdlen);
+ cp += stdlen;
+ *cp++ = '\0';
+ if (dstlen != 0) {
+ (void) strncpy(cp, dstname, dstlen);
+ *(cp + dstlen) = '\0';
+ }
+ return 0;
+}
+
+void tzset()
+{
+ char *TZstring;
+ int dstfirst;
+ static char *old_TZstring = NULL;
+
+ TZstring = getenv("TZ"); /* read TZ envvar */
+ if (old_TZstring && TZstring && !strcmp(old_TZstring, TZstring))
+ /* do not repeatedly parse an unchanged TZ specification */
+ return;
+ if ((TZstring && TZstring[0] && Parse_TZ(TZstring, &statism) == 0)
+ || IZTZ_GETLOCALETZINFO(&statism, generate_transitions)
+ || Parse_TZ(gmt, &statism) == 0) {
+ daylight = statism.typecnt > 1;
+ dstfirst = daylight && statism.ttis[0].tt_isdst && !statism.ttis[1].tt_isdst;
+ timezone = -statism.ttis[dstfirst].tt_gmtoff;
+ tzname[0] = statism.chars + statism.ttis[dstfirst].tt_abbrind;
+ tzname[1] = statism.chars + statism.ttis[!dstfirst].tt_abbrind;
+ real_timezone_is_set = TRUE;
+ if (TZstring) {
+ if (old_TZstring)
+ old_TZstring = realloc(old_TZstring, strlen(TZstring) + 1);
+ else
+ old_TZstring = malloc(strlen(TZstring) + 1);
+ if (old_TZstring)
+ strcpy(old_TZstring, TZstring);
+ }
+ } else {
+ timezone = 0; /* default is GMT0 which means no offsets */
+ daylight = 0; /* from local system time */
+ real_timezone_is_set = FALSE;
+ if (old_TZstring) {
+ free(old_TZstring);
+ old_TZstring = NULL;
+ }
+ }
+#ifdef IZTZ_SETLOCALTZINFO
+ /* Some SAS/C library functions, e.g. stat(), call library */
+ /* __tzset() themselves. So envvar TZ *must* exist in order to */
+ /* to get the right offset from GMT. XXX TRY HARD to fix this! */
+ set_TZ(timezone, daylight);
+#endif /* IZTZ_SETLOCALTZINFO */
+}
+
+/* XXX Does this also help SAS/C library work? */
+void __tzset()
+{
+ if (!real_timezone_is_set) tzset();
+}
+
+static struct tm _tmbuf;
+
+struct tm *gmtime(when)
+ ZCONST time_t *when;
+{
+ long days = *when / SECSPERDAY;
+ long secs = *when % SECSPERDAY;
+ int isleap;
+
+ memset(&_tmbuf, 0, sizeof(_tmbuf)); /* get any nonstandard fields */
+ _tmbuf.tm_wday = (days + EPOCH_WDAY) % 7;
+ _tmbuf.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
+ isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
+ while (days >= year_lengths[isleap]) {
+ days -= year_lengths[isleap];
+ _tmbuf.tm_year++;
+ isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
+ }
+ _tmbuf.tm_mon = 0;
+ _tmbuf.tm_yday = days;
+ while (days >= mon_lengths[isleap][_tmbuf.tm_mon])
+ days -= mon_lengths[isleap][_tmbuf.tm_mon++];
+ _tmbuf.tm_mday = days + 1;
+ _tmbuf.tm_isdst = 0;
+ _tmbuf.tm_sec = secs % SECSPERMIN;
+ _tmbuf.tm_min = (secs / SECSPERMIN) % SECSPERMIN;
+ _tmbuf.tm_hour = secs / SECSPERHOUR;
+ return &_tmbuf;
+}
+
+struct tm *localtime(when)
+ ZCONST time_t *when;
+{
+ time_t localwhen = *when;
+ int timetype;
+ struct tm *ret;
+
+ __tzset();
+ if (statism.timecnt == 0 || localwhen < statism.ats[0])
+ timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
+ !statism.ttis[1].tt_isdst;
+ else {
+ for (timetype = 1; timetype < statism.timecnt; ++timetype)
+ if (localwhen < statism.ats[timetype])
+ break;
+ timetype = statism.types[timetype - 1];
+ }
+ localwhen += statism.ttis[timetype].tt_gmtoff;
+ ret = gmtime(&localwhen);
+ ret->tm_isdst = statism.ttis[timetype].tt_isdst;
+ return ret;
+}
+
+#ifdef NEED__ISINDST
+int _isindst(tb)
+ struct tm *tb;
+{
+ time_t localt; /* time_t equivalent of given tm struct */
+ time_t univt; /* assumed UTC value of given time */
+ long tzoffset_adj; /* timezone-adjustment `remainder' */
+ int bailout_cnt; /* counter of tries for tz correction */
+ int timetype;
+
+ __tzset();
+
+ /* when DST is unsupported in current timezone, DST is always off */
+ if (statism.typecnt <= 1) return FALSE;
+
+ localt = mkgmtime(tb);
+ if (localt == (time_t)-1)
+ /* specified time is out-of-range, default to FALSE */
+ return FALSE;
+
+ univt = localt - statism.ttis[0].tt_gmtoff;
+ bailout_cnt = 3;
+ do {
+ if (statism.timecnt == 0 || univt < statism.ats[0])
+ timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
+ !statism.ttis[1].tt_isdst;
+ else {
+ for (timetype = 1; timetype < statism.timecnt; ++timetype)
+ if (univt < statism.ats[timetype])
+ break;
+ timetype = statism.types[timetype - 1];
+ }
+ if ((tzoffset_adj = localt - univt - statism.ttis[timetype].tt_gmtoff)
+ == 0L)
+ break;
+ univt += tzoffset_adj;
+ } while (--bailout_cnt > 0);
+
+ /* return TRUE when DST is active at given time */
+ return (statism.ttis[timetype].tt_isdst);
+}
+#endif /* NEED__ISINDST */
+#endif /* !IZ_MKTIME_ONLY */
+
+/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
+ of the local time and date in the exploded time structure `tm',
+ adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'.
+ If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of
+ tm_isdst is determined and returned. Otherwise, mktime() assumes this
+ field as valid; its information is used when converting local time
+ to UTC.
+ Return -1 if time in `tm' cannot be represented as time_t value. */
+
+time_t mktime(tm)
+ struct tm *tm;
+{
+ struct tm *ltm; /* Local time. */
+ time_t loctime; /* The time_t value of local time. */
+ time_t then; /* The time to return. */
+ long tzoffset_adj; /* timezone-adjustment `remainder' */
+ int bailout_cnt; /* counter of tries for tz correction */
+ int save_isdst; /* Copy of the tm->isdst input value */
+
+ save_isdst = tm->tm_isdst;
+ loctime = mkgmtime(tm);
+ if (loctime == -1) {
+ tm->tm_isdst = save_isdst;
+ return (time_t)-1;
+ }
+
+ /* Correct for the timezone and any daylight savings time.
+ The correction is verified and repeated when not correct, to
+ take into account the rare case that a change to or from daylight
+ savings time occurs between when it is the time in `tm' locally
+ and when it is that time in Greenwich. After the second correction,
+ the "timezone & daylight" offset should be correct in all cases. To
+ be sure, we allow a third try, but then the loop is stopped. */
+ bailout_cnt = 3;
+ then = loctime;
+ do {
+ ltm = localtime(&then);
+ if (ltm == (struct tm *)NULL ||
+ (tzoffset_adj = loctime - mkgmtime(ltm)) == 0L)
+ break;
+ then += tzoffset_adj;
+ } while (--bailout_cnt > 0);
+
+ if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) {
+ /* Signal failure if timezone adjustment did not converge. */
+ tm->tm_isdst = save_isdst;
+ return (time_t)-1;
+ }
+
+ if (save_isdst >= 0) {
+ if (ltm->tm_isdst && !save_isdst)
+ {
+ if (then + 3600 < then)
+ then = (time_t)-1;
+ else
+ then += 3600;
+ }
+ else if (!ltm->tm_isdst && save_isdst)
+ {
+ if (then - 3600 > then)
+ then = (time_t)-1;
+ else
+ then -= 3600;
+ }
+ ltm->tm_isdst = save_isdst;
+ }
+
+ if (tm != ltm) /* `tm' may already point to localtime's internal storage */
+ *tm = *ltm;
+
+ return then;
+}
+
+
+#ifndef NO_TIME_T_MAX
+ /* Provide default values for the upper limit of the time_t range.
+ These are the result of the decomposition into a `struct tm' for
+ the time value 0xFFFFFFFEL ( = (time_t)-2 ).
+ Note: `(time_t)-1' is reserved for "invalid time"! */
+# ifndef TM_YEAR_MAX
+# define TM_YEAR_MAX 2106
+# endif
+# ifndef TM_MON_MAX
+# define TM_MON_MAX 1 /* February */
+# endif
+# ifndef TM_MDAY_MAX
+# define TM_MDAY_MAX 7
+# endif
+# ifndef TM_HOUR_MAX
+# define TM_HOUR_MAX 6
+# endif
+# ifndef TM_MIN_MAX
+# define TM_MIN_MAX 28
+# endif
+# ifndef TM_SEC_MAX
+# define TM_SEC_MAX 14
+# endif
+#endif /* NO_TIME_T_MAX */
+
+/* Adjusts out-of-range values for `tm' field `tm_member'. */
+#define ADJUST_TM(tm_member, tm_carry, modulus) \
+ if ((tm_member) < 0) { \
+ tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
+ tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
+ } else if ((tm_member) >= (modulus)) { \
+ tm_carry += (tm_member) / (modulus); \
+ tm_member = (tm_member) % (modulus); \
+ }
+
+/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
+ of the Greenwich Mean time and date in the exploded time structure `tm'.
+ This function does always put back normalized values into the `tm' struct,
+ parameter, including the calculated numbers for `tm->tm_yday',
+ `tm->tm_wday', and `tm->tm_isdst'.
+ Returns -1 if the time in the `tm' parameter cannot be represented
+ as valid `time_t' number. */
+
+time_t mkgmtime(tm)
+ struct tm *tm;
+{
+ int years, months, days, hours, minutes, seconds;
+
+ years = tm->tm_year + TM_YEAR_BASE; /* year - 1900 -> year */
+ months = tm->tm_mon; /* 0..11 */
+ days = tm->tm_mday - 1; /* 1..31 -> 0..30 */
+ hours = tm->tm_hour; /* 0..23 */
+ minutes = tm->tm_min; /* 0..59 */
+ seconds = tm->tm_sec; /* 0..61 in ANSI C. */
+
+ ADJUST_TM(seconds, minutes, 60)
+ ADJUST_TM(minutes, hours, 60)
+ ADJUST_TM(hours, days, 24)
+ ADJUST_TM(months, years, 12)
+ if (days < 0)
+ do {
+ if (--months < 0) {
+ --years;
+ months = 11;
+ }
+ days += monthlen(months, years);
+ } while (days < 0);
+ else
+ while (days >= monthlen(months, years)) {
+ days -= monthlen(months, years);
+ if (++months >= 12) {
+ ++years;
+ months = 0;
+ }
+ }
+
+ /* Restore adjusted values in tm structure */
+ tm->tm_year = years - TM_YEAR_BASE;
+ tm->tm_mon = months;
+ tm->tm_mday = days + 1;
+ tm->tm_hour = hours;
+ tm->tm_min = minutes;
+ tm->tm_sec = seconds;
+
+ /* Set `days' to the number of days into the year. */
+ days += YDAYS(months, years);
+ tm->tm_yday = days;
+
+ /* Now calculate `days' to the number of days since Jan 1, 1970. */
+ days = (unsigned)days + 365 * (unsigned)(years - EPOCH_YEAR) +
+ (unsigned)(nleap (years));
+ tm->tm_wday = ((unsigned)days + EPOCH_WDAY) % 7;
+ tm->tm_isdst = 0;
+
+ if (years < EPOCH_YEAR)
+ return (time_t)-1;
+
+#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
+#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
+ if (years > TM_YEAR_MAX ||
+ (years == TM_YEAR_MAX &&
+ (tm->tm_yday > (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) ||
+ (tm->tm_yday == (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) &&
+ (hours > TM_HOUR_MAX ||
+ (hours == TM_HOUR_MAX &&
+ (minutes > TM_MIN_MAX ||
+ (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
+ return (time_t)-1;
+#endif
+#endif
+
+ return (time_t)(SECSPERDAY * (unsigned long)(unsigned)days +
+ SECSPERHOUR * (unsigned long)hours +
+ (unsigned long)(SECSPERMIN * minutes + seconds));
+}
+
+#endif /* __timezone_c */
diff --git a/timezone.h b/timezone.h
new file mode 100644
index 0000000..f4f46f2
--- /dev/null
+++ b/timezone.h
@@ -0,0 +1,83 @@
+/*
+ timezone.h - Zip 3
+
+ Copyright (c) 1990-2004 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2003-May-08 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __timezone_h
+#define __timezone_h
+
+#ifndef IZ_MKTIME_ONLY
+
+/* limits for our timezone info data:
+ * we support only basic standard and daylight time, with max 2 transitions
+ * per year, but for the maximum range of years a 32-bit second counter
+ * can cover (these are 136 years plus a bit more than one month)
+ */
+#define TZ_MAX_TIMES 272 /* (=2*(LastGoodYr + 1 - FirstGoodYr) */
+#define TZ_MAX_TYPES 2 /* We only support basic standard and daylight */
+#ifdef WIN32 /* Win32 tzinfo supplies at max (2 * 32) chars of tz names */
+#define TZ_MAX_CHARS 64 /* Maximum number of abbreviation characters */
+#else
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+#endif
+
+/* supported types of transition rules */
+#define JULIAN_DAY 0 /* Jn - Julian day */
+#define DAY_OF_YEAR 1 /* n - day of year */
+#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
+
+
+struct ttinfo {
+ long tt_gmtoff; /* UTC offset in seconds */
+ int tt_isdst; /* used to set tm_isdst */
+ int tt_abbrind; /* abbreviation list index */
+};
+
+struct state {
+ int timecnt;
+ int typecnt;
+ int charcnt;
+ time_t ats[TZ_MAX_TIMES];
+ unsigned char types[TZ_MAX_TIMES];
+ struct ttinfo ttis[TZ_MAX_TYPES];
+ char chars[TZ_MAX_CHARS];
+};
+
+struct rule {
+ int r_type; /* type of rule--JULIAN_DAY etc */
+ int r_day; /* day number of rule */
+ int r_week; /* week number of rule */
+ int r_mon; /* month number of rule */
+ long r_time; /* transition time of rule */
+};
+
+extern int real_timezone_is_set; /* set by tzset() */
+
+
+/* prototypes of functions not in time.h */
+
+void __tzset OF((void));
+
+#ifdef NEED__ISINDST
+int _isindst OF((struct tm *tb));
+#endif
+
+/* callback function to be supplied by the program that uses this library */
+int GetPlatformLocalTimezone OF((register struct state * ZCONST sp,
+ void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
+ ZCONST struct rule * ZCONST start,
+ ZCONST struct rule * ZCONST end)));
+#ifdef IZTZ_SETLOCALTZINFO
+void set_TZ OF((long time_zone, int day_light));
+#endif
+
+#endif /* !IZ_MKTIME_ONLY */
+
+time_t mkgmtime OF((struct tm *tm));
+
+#endif
diff --git a/tops20/make.mic b/tops20/make.mic
new file mode 100644
index 0000000..5930847
--- /dev/null
+++ b/tops20/make.mic
@@ -0,0 +1,35 @@
+@te no pau e
+@cc -c -q zip
+@cc -c -q zipfil
+@cc -c -q zipup
+@cc -c -q fileio
+@cc -c -q util
+@cc -c -q crc32
+@cc -c -q global
+@cc -c -q deflat
+@cc -c -q trees
+@cc -c -q crypt
+@cc -c -q ttyio
+@cc -c -q tops20
+@cc -i -o zip zip.rel zipfil.rel zipup.rel fileio.rel util.rel crc32.rel global.rel deflat.rel trees.rel crypt.rel ttyio.rel tops20.rel
+@cc -c -q zipnot
+@rename zipfil.c zipfix.c
+@rename fileio.c filiox.c
+@rename util.c utilx.c
+@rename tops20.c tops2x.c
+@cc -c -q -DUTIL zipfix
+@cc -c -q -DUTIL filiox
+@cc -c -q -DUTIL utilx
+@cc -c -q -DUTIL tops2x
+@rename zipfix.c zipfil.c
+@rename filiox.c fileio.c
+@rename utilx.c util.c
+@rename tops2x.c tops20.c
+@cc -i -o zipnot zipnot.rel zipfix.rel filiox.rel utilx.rel global.rel tops2x.rel
+@reset
+@rename zipnot.exe zipnote.exe
+@cc -c -q zipspl
+@cc -i -o zipspl zipspl.rel zipfix.rel filiox.rel utilx.rel global.rel tops2x.rel
+@reset
+@rename zipspl.exe zipsplit.exe
+@kmic
diff --git a/tops20/osdep.h b/tops20/osdep.h
new file mode 100644
index 0000000..c750c2d
--- /dev/null
+++ b/tops20/osdep.h
@@ -0,0 +1,31 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef TOPS20
+#define TOPS20
+#endif
+
+#define NO_PROTO
+#define NO_SYMLINKS
+#define NO_TERMIO
+#define DIRENT
+#define BIG_MEM
+#define REALLY_SHORT_SYMS
+#define window_size winsiz
+
+extern int isatty();
+
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "w8"
+
+#define CBSZ 524288
+#define ZBSZ 524288
+
+#include <sys/types.h>
+#include <sys/stat.h>
diff --git a/tops20/rename.mic b/tops20/rename.mic
new file mode 100644
index 0000000..6a45d26
--- /dev/null
+++ b/tops20/rename.mic
@@ -0,0 +1,6 @@
+@rename zipfile.c zipfil.c
+@rename globals.c global.c
+@rename deflate.c deflat.c
+@rename zipnote.c zipnot.c
+@rename zipsplit.c zipspl.c
+@kmic
diff --git a/tops20/tops20.c b/tops20/tops20.c
new file mode 100644
index 0000000..a2b63e7
--- /dev/null
+++ b/tops20/tops20.c
@@ -0,0 +1,574 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+
+#define PATH_START '<'
+#define PATH_END '>'
+
+/* Extra malloc() space in names for cutpath() */
+#define PAD 5 /* may have to change .FOO] to ]FOO.DIR;1 */
+
+
+#define TRUE 1
+#define FALSE 0
+#define O_RDONLY (0)
+#define O_T20_WILD (1<<18)
+#include <monsym.h> /* Get amazing monsym() macro */
+extern int jsys(), fstat();
+extern char *getcwd();
+extern int _gtjfn(), _rljfn();
+#define JSYS_CLASS 0070000000000
+#define FLD(val,mask) (((unsigned)(val)*((mask)&(-(mask))))&(mask))
+#define _DEFJS(name,class) (FLD(class, JSYS_CLASS) | (monsym(name)&0777777))
+#define JFNS _DEFJS("JFNS%", 1)
+#define GNJFN _DEFJS("GNJFN%", 0)
+static int wfopen(), wfnext(), strlower(), strupper();
+static char *wfname();
+typedef struct {
+ int wfjfn;
+ int more;
+} DIR;
+
+/* Library functions not in (most) header files */
+
+extern int stat(), chmod(), toupper(), tolower();
+
+int utime OF((char *, ztimbuf *));
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+
+local DIR *opendir(n)
+char *n; /* directory name to open */
+/* Open the directory *n, returning a pointer to an allocated DIR, or
+ NULL if error. */
+{
+ DIR *d; /* pointer to malloc'ed directory stream */
+ char *c; /* scans TOPS20 path */
+ int m; /* length of name */
+ char *p; /* temp string */
+
+ if (((d = (DIR *)malloc(sizeof(DIR))) == NULL) ||
+ ((p = (char *)malloc((m = strlen(n)) + 4)) == NULL)) {
+ return NULL;
+ }
+
+/* Directory may be in form "<DIR.SUB1.SUB2>" or "<DIR.SUB1>SUB2.DIRECTORY".
+** If latter, convert to former. */
+
+ if ((m > 0) && (*(c = strcpy(p,n) + m-1) != '>')) {
+ c -= 10;
+ *c-- = '\0'; /* terminate at "DIRECTORY.1" */
+ *c = '>'; /* "." --> ">" */
+ while ((c > p) && (*--c != '>'));
+ *c = '.'; /* ">" --> "." */
+ }
+ strcat(p, "*.*");
+ if ((d->wfjfn = wfopen(p)) == 0) {
+ free((zvoid *)d);
+ free((zvoid *)p);
+ return NULL;
+ }
+ free((zvoid *)p);
+ d->more = TRUE;
+ return (d);
+}
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ char *p;
+ if ((d->more == FALSE) || ((p = wfname(d->wfjfn)) == NULL)) {
+ return NULL;
+ }
+ if (wfnext(d->wfjfn) == 0) {
+ d->more = FALSE;
+ }
+ return p;
+}
+
+
+local void closedir(d)
+DIR *d; /* directory stream to close */
+/* Close the directory stream */
+{
+ free((zvoid *)d);
+}
+
+/* Wildcard filename routines */
+
+/* WFOPEN - open wild card filename
+** Returns wild JFN for filespec, 0 if failure.
+*/
+static int
+wfopen(name)
+char *name;
+{
+ return (_gtjfn(name, (O_RDONLY | O_T20_WILD)));
+}
+
+/* WFNAME - Return filename for wild JFN
+** Returns pointer to dynamically allocated filename string
+*/
+static char *
+wfname(jfn)
+int jfn;
+{
+ char *fp, fname[200];
+ int ablock[5];
+
+ ablock[1] = (int) (fname - 1);
+ ablock[2] = jfn & 0777777; /* jfn, no flags */
+ ablock[3] = 0111110000001; /* DEV+DIR+NAME+TYPE+GEN, punctuate */
+ if (!jsys(JFNS, ablock))
+ return NULL; /* something bad happened */
+ if ((fp = (char *)malloc(strlen(fname) + 1)) == NULL) {
+ return NULL;
+ }
+ strcpy(fp, fname); /* copy the file name here */
+ return fp;
+}
+
+/* WFNEXT - Make wild JFN point to next real file
+** Returns success or failure (not JFN)
+*/
+static int
+wfnext(jfn)
+int jfn;
+{
+ int ablock[5];
+
+ ablock[1] = jfn; /* save jfn and flags */
+ return jsys(GNJFN, ablock);
+}
+
+
+static int
+strupper(s) /* Returns s in uppercase */
+char *s; /* String to be uppercased */
+{
+ char *p;
+
+ p = s;
+ for (; *p; p++)
+ *p = toupper (*p);
+}
+
+static int
+strlower(s) /* Returns s in lowercase. */
+char *s; /* String to be lowercased */
+{
+ char *p;
+
+ p = s;
+ for (; *p; p++)
+ *p = tolower (*p);
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ if (caseflag) {
+ p = malloc(strlen(n) + 1);
+ if (p != NULL)
+ strcpy(p, n);
+ } else
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ if (dirnames && (m = newname(n, 1, caseflag)) != ZE_OK) {
+ return m;
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if ((m = procname(e, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ closedir(d);
+ return m;
+ }
+ }
+ closedir(d);
+ }
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+ int jfn;
+ char *fp, fname[200];
+ int ablock[5];
+
+ jfn = _gtjfn(x, (O_RDONLY));
+ ablock[1] = (int) (fname - 1);
+ ablock[2] = jfn & 0777777; /* jfn, no flags */
+ ablock[3] = 0111100000001; /* DEV+DIR+NAME+TYPE, punctuate */
+ if (!jsys(JFNS, ablock)) {
+ _rljfn(jfn);
+ return NULL; /* something bad happened */
+ }
+ _rljfn(jfn);
+ if ((fp = (char *)malloc(strlen(fname) + 1)) == NULL) {
+ return NULL;
+ }
+ strcpy(fp, fname); /* copy the file name here */
+ x = fp;
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ t = x;
+ if ((n = strrchr(t, ':')) != NULL)
+ t = n + 1;
+ if (*t == PATH_START && (n = strrchr(t, PATH_END)) != NULL)
+ if (*(++t) == '.')
+ /* path is relative to current directory, skip leading '.' */
+ t++;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if ((t = strrchr(n, PATH_END)) != NULL)
+ {
+ *t = '/';
+ while (--t > n)
+ if (*t == '.')
+ *t = '/';
+ }
+
+ /* Fix from Greg Roelofs: */
+ /* Get current working directory and strip from n (t now = n) */
+ {
+ char cwd[256], *p, *q;
+ int c;
+
+ if (getcwd(cwd, 256) && ((p = strchr(cwd, PATH_START)) != NULL))
+ {
+ if (*(++p) == '.')
+ p++;
+ if ((q = strrchr(p, PATH_END)) != NULL)
+ {
+ *q = '/';
+ while (--q > p)
+ if (*q == '.')
+ *q = '/';
+
+ /* strip bogus path parts from n */
+ if (strncmp(n, p, (c=strlen(p))) == 0)
+ {
+ q = n + c;
+ while (*t++ = *q++)
+ ;
+ }
+ }
+ }
+ }
+ strlower(n);
+
+ if (isdir)
+ {
+ if (strcmp((t=n+strlen(n)-6), ".dir;1"))
+ error("directory not version 1");
+ else
+ strcpy(t, "/");
+ }
+
+ if ((t = strrchr(n, '.')) != NULL)
+ {
+ if ( t[1] == '\0') /* "filename." -> "filename" */
+ *t = '\0';
+ }
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+ char *t; /* scans name */
+
+ if ((t = strrchr(n, '/')) == NULL)
+ {
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+ }
+ else
+ {
+ if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
+ return NULL;
+ x[0] = PATH_START;
+ x[1] = '.';
+ strcpy(x + 2, n);
+ *(t = x + 2 + (t - n)) = PATH_END;
+ while (--t > x)
+ if (*t == '/')
+ *t = '.';
+ }
+ strupper(x);
+
+ return x;
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ ztimbuf u; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ /* Set updated and accessed times of f */
+ utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* converted from FNAMX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFDIR) != 0) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+#include <monsym.h> /* Get amazing monsym() macro */
+#define _FBBYV monsym(".FBBYV")
+#define FBBSZ_S -24 /* Obsolete, replace by FLDGET! */
+#define FBBSZ_M 077 /* ditto */
+
+extern int _gtjfn(), _rljfn(), _gtfdb(), stat();
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+ int jfn;
+
+ translate_eol = 0;
+ jfn = _gtjfn(z->name, O_RDONLY);
+ z->att = (((_gtfdb (jfn, _FBBYV) << FBBSZ_S) & FBBSZ_M) != 8) ?
+ ASCII :BINARY;
+ _rljfn(jfn);
+
+#ifdef USE_EF_UT_TIME
+ if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME;
+ z->extra[5] = (char)(z_utim->mtime);
+ z->extra[6] = (char)(z_utim->mtime >> 8);
+ z->extra[7] = (char)(z_utim->mtime >> 16);
+ z->extra[8] = (char)(z_utim->mtime >> 24);
+
+ z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+ z->cextra = z->extra;
+#endif /* USE_EF_UT_TIME */
+
+ return ZE_OK;
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ zipwarn("deletedir not implemented yet", "");
+ return 127;
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if 0
+ char buf[40];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+# if 0
+ "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
+# else
+# ifdef __COMPILER_KCC__
+ "KCC", "",
+# else
+ "unknown compiler", "",
+# endif
+# endif
+#endif
+
+ "TOPS-20",
+
+#if defined(foobar) || defined(FOOBAR)
+ " (Foo BAR)", /* OS version or hardware */
+#else
+ "",
+#endif /* Foo BAR */
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
diff --git a/tops20/zipup.h b/tops20/zipup.h
new file mode 100644
index 0000000..47ec563
--- /dev/null
+++ b/tops20/zipup.h
@@ -0,0 +1,18 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define O_RDONLY (0)
+#define O_UNCONVERTED (0400) /* Forced NO conversion requested */
+#define fhow (O_RDONLY | O_UNCONVERTED)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/trees.c b/trees.c
new file mode 100644
index 0000000..aefe639
--- /dev/null
+++ b/trees.c
@@ -0,0 +1,1474 @@
+/*
+ trees.h - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * trees.c by Jean-loup Gailly
+ *
+ * This is a new version of im_ctree.c originally written by Richard B. Wales
+ * for the defunct implosion method.
+ * The low level bit string handling routines from bits.c (originally
+ * im_bits.c written by Richard B. Wales) have been merged into this version
+ * of trees.c.
+ *
+ * PURPOSE
+ *
+ * Encode various sets of source values using variable-length
+ * binary code trees.
+ * Output the resulting variable-length bit strings.
+ * Compression can be done to a file or to memory.
+ *
+ * DISCUSSION
+ *
+ * The PKZIP "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in the ZIP file in a compressed form
+ * which is itself a Huffman encoding of the lengths of
+ * all the code strings (in ascending order by source values).
+ * The actual code strings are reconstructed from the lengths in
+ * the UNZIP process, as described in the "application note"
+ * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ * The PKZIP "deflate" file format interprets compressed file data
+ * as a sequence of bits. Multi-bit strings in the file may cross
+ * byte boundaries without restriction.
+ * The first bit of each byte is the low-order bit.
+ *
+ * The routines in this file allow a variable-length bit value to
+ * be output right-to-left (useful for literal values). For
+ * left-to-right output (useful for code strings from the tree routines),
+ * the bits must have been reversed first with bi_reverse().
+ *
+ * For in-memory compression, the compressed bit stream goes directly
+ * into the requested output buffer. The buffer is limited to 64K on
+ * 16 bit machines; flushing of the output buffer during compression
+ * process is not supported.
+ * The input data is read in blocks by the (*read_buf)() function.
+ *
+ * For more details about input to and output from the deflation routines,
+ * see the actual input functions for (*read_buf)(), flush_outbuf(), and
+ * the filecompress() resp. memcompress() wrapper functions which handle
+ * the I/O setup.
+ *
+ * REFERENCES
+ *
+ * Lynch, Thomas J.
+ * Data Compression: Techniques and Applications, pp. 53-55.
+ * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ *
+ * INTERFACE
+ *
+ * void ct_init (ush *attr, int *method)
+ * Allocate the match buffer, initialize the various tables and save
+ * the location of the internal file attribute (ascii/binary) and
+ * method (DEFLATE/STORE)
+ *
+ * void ct_tally (int dist, int lc);
+ * Save the match info and tally the frequency counts.
+ *
+ * uzoff_t flush_block (char *buf, ulg stored_len, int eof)
+ * Determine the best encoding for the current block: dynamic trees,
+ * static trees or store, and output the encoded block to the zip
+ * file. Returns the total compressed length for the file so far.
+ *
+ * void bi_init (char *tgt_buf, unsigned tgt_size, int flsh_allowed)
+ * Initialize the bit string routines.
+ *
+ * Most of the bit string output functions are only used internally
+ * in this source file, they are normally declared as "local" routines:
+ *
+ * local void send_bits (int value, int length)
+ * Write out a bit string, taking the source bits right to
+ * left.
+ *
+ * local unsigned bi_reverse (unsigned code, int len)
+ * Reverse the bits of a bit string, taking the source bits left to
+ * right and emitting them right to left.
+ *
+ * local void bi_windup (void)
+ * Write out any remaining bits in an incomplete byte.
+ *
+ * local void copy_block(char *buf, unsigned len, int header)
+ * Copy a stored block to the zip file, storing first the length and
+ * its one's complement if requested.
+ *
+ * All output that exceeds the bitstring output buffer size (as initialized
+ * by bi_init() is fed through an externally provided transfer routine
+ * which flushes the bitstring output buffer on request and resets the
+ * buffer fill counter:
+ *
+ * extern void flush_outbuf(char *o_buf, unsigned *o_idx);
+ *
+ */
+#define __TREES_C
+
+/* Put zip.h first as when using 64-bit file environment in unix ctype.h
+ defines off_t and then while other files are using an 8-byte off_t this
+ file gets a 4-byte off_t. Once zip.h sets the large file defines can
+ then include ctype.h and get 8-byte off_t. 8/14/04 EG */
+#include "zip.h"
+#include <ctype.h>
+
+#ifndef USE_ZLIB
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+
+local int near extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int near extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int near extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+# ifdef SMALL_MEM
+# define LIT_BUFSIZE 0x2000
+# else
+# ifdef MEDIUM_MEM
+# define LIT_BUFSIZE 0x4000
+# else
+# define LIT_BUFSIZE 0x8000
+# endif
+# endif
+#endif
+#define DIST_BUFSIZE LIT_BUFSIZE
+/* Sizes of match buffers for literals/lengths and distances. There are
+ * 4 reasons for limiting LIT_BUFSIZE to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input data is
+ * still in the window so we can still emit a stored block even when input
+ * comes from standard input. (This can also be done for all blocks if
+ * LIT_BUFSIZE is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting trees
+ * more frequently.
+ * - I can't count above 4
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+/* ===========================================================================
+ * Local data
+ */
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+local ct_data near dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+local ct_data near dyn_dtree[2*D_CODES+1]; /* distance tree */
+
+local ct_data near static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see ct_init
+ * below).
+ */
+
+local ct_data near static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local ct_data near bl_tree[2*BL_CODES+1];
+/* Huffman tree for the bit lengths */
+
+typedef struct tree_desc {
+ ct_data near *dyn_tree; /* the dynamic tree */
+ ct_data near *static_tree; /* corresponding static tree or NULL */
+ int near *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+ int max_code; /* largest code with non zero frequency */
+} tree_desc;
+
+local tree_desc near l_desc =
+{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
+
+local tree_desc near d_desc =
+{dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0};
+
+local tree_desc near bl_desc =
+{bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0};
+
+
+local ush near bl_count[MAX_BITS+1];
+/* number of codes at each bit length for an optimal tree */
+
+local uch near bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+local int near heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+local int heap_len; /* number of elements in the heap */
+local int heap_max; /* element of largest frequency */
+/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+local uch near depth[2*L_CODES+1];
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local int near base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int near base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#ifndef DYN_ALLOC
+ local uch far l_buf[LIT_BUFSIZE]; /* buffer for literals/lengths */
+ local ush far d_buf[DIST_BUFSIZE]; /* buffer for distances */
+#else
+ local uch far *l_buf;
+ local ush far *d_buf;
+#endif
+
+local uch near flag_buf[(LIT_BUFSIZE/8)];
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, and thus indicating the presence or absence of a distance.
+ */
+
+local unsigned last_lit; /* running index in l_buf */
+local unsigned last_dist; /* running index in d_buf */
+local unsigned last_flags; /* running index in flag_buf */
+local uch flags; /* current flags not yet saved in flag_buf */
+local uch flag_bit; /* current bit used in flags */
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+local ulg opt_len; /* bit length of current block with optimal trees */
+local ulg static_len; /* bit length of current block with static trees */
+
+/* zip64 support 08/29/2003 R.Nausedat */
+/* now all file sizes and offsets are zoff_t 7/24/04 EG */
+local uzoff_t cmpr_bytelen; /* total byte length of compressed file */
+local ulg cmpr_len_bits; /* number of bits past 'cmpr_bytelen' */
+
+#ifdef DEBUG
+local uzoff_t input_len; /* total byte length of input file */
+/* input_len is for debugging only since we can get it by other means. */
+#endif
+
+local ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */
+local int *file_method; /* pointer to DEFLATE or STORE */
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+local int flush_flg;
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local unsigned bi_buf;
+#else
+unsigned bi_buf;
+#endif
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits). The width of bi_buf must be at least 16 bits.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf may be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local int bi_valid;
+#else
+int bi_valid;
+#endif
+/* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local char *out_buf;
+#else
+char *out_buf;
+#endif
+/* Current output buffer. */
+
+#if (!defined(ASMV) || !defined(RISCOS))
+local unsigned out_offset;
+#else
+unsigned out_offset;
+#endif
+/* Current offset in output buffer.
+ * On 16 bit machines, the buffer is limited to 64K.
+ */
+
+#if !defined(ASMV) || !defined(RISCOS)
+local unsigned out_size;
+#else
+unsigned out_size;
+#endif
+/* Size of current output buffer */
+
+/* Output a 16 bit value to the bit stream, lower (oldest) byte first */
+#define PUTSHORT(w) \
+{ if (out_offset >= out_size-1) \
+ flush_outbuf(out_buf, &out_offset); \
+ out_buf[out_offset++] = (char) ((w) & 0xff); \
+ out_buf[out_offset++] = (char) ((ush)(w) >> 8); \
+}
+
+#define PUTBYTE(b) \
+{ if (out_offset >= out_size) \
+ flush_outbuf(out_buf, &out_offset); \
+ out_buf[out_offset++] = (char) (b); \
+}
+
+#ifdef DEBUG
+local uzoff_t bits_sent; /* bit length of the compressed data */
+extern uzoff_t isize; /* byte length of input file */
+#endif
+
+extern long block_start; /* window offset of current block */
+extern unsigned near strstart; /* window offset of current string */
+
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void init_block OF((void));
+local void pqdownheap OF((ct_data near *tree, int k));
+local void gen_bitlen OF((tree_desc near *desc));
+local void gen_codes OF((ct_data near *tree, int max_code));
+local void build_tree OF((tree_desc near *desc));
+local void scan_tree OF((ct_data near *tree, int max_code));
+local void send_tree OF((ct_data near *tree, int max_code));
+local int build_bl_tree OF((void));
+local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
+local void compress_block OF((ct_data near *ltree, ct_data near *dtree));
+local void set_file_type OF((void));
+#if (!defined(ASMV) || !defined(RISCOS))
+local void send_bits OF((int value, int length));
+local unsigned bi_reverse OF((unsigned code, int len));
+#endif
+local void bi_windup OF((void));
+local void copy_block OF((char *buf, unsigned len, int header));
+
+
+#ifndef DEBUG
+# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(c, tree) \
+ { if (verbose>1) fprintf(mesg,"\ncd %3d ",(c)); \
+ send_bits(tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+#define Max(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+void ct_init(attr, method)
+ ush *attr; /* pointer to internal file attribute */
+ int *method; /* pointer to compression method */
+{
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+
+ file_type = attr;
+ file_method = method;
+ cmpr_len_bits = 0L;
+ cmpr_bytelen = (uzoff_t)0;
+#ifdef DEBUG
+ input_len = (uzoff_t)0;
+#endif
+
+ if (static_dtree[0].Len != 0) return; /* ct_init already called */
+
+#ifdef DYN_ALLOC
+ d_buf = (ush far *) zcalloc(DIST_BUFSIZE, sizeof(ush));
+ l_buf = (uch far *) zcalloc(LIT_BUFSIZE/2, 2);
+ /* Avoid using the value 64K on 16 bit machines */
+ if (l_buf == NULL || d_buf == NULL)
+ ziperr(ZE_MEM, "ct_init: out of memory");
+#endif
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ length_code[length++] = (uch)code;
+ }
+ }
+ Assert(length == 256, "ct_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert(dist == 256, "ct_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert(dist == 256, "ct_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data near *)static_ltree, L_CODES+1);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = (ush)bi_reverse(n, 5);
+ }
+
+ /* Initialize the first block of the first file: */
+ init_block();
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block()
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
+
+ dyn_ltree[END_BLOCK].Freq = 1;
+ opt_len = static_len = 0L;
+ last_lit = last_dist = last_flags = 0;
+ flags = 0; flag_bit = 1;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(tree, top) \
+{\
+ top = heap[SMALLEST]; \
+ heap[SMALLEST] = heap[heap_len--]; \
+ pqdownheap(tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(tree, k)
+ ct_data near *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = heap[k];
+ int j = k << 1; /* left son of k */
+ int htemp; /* required because of bug in SASC compiler */
+
+ while (j <= heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
+
+ /* Exit if v is smaller than both sons */
+ htemp = heap[j];
+ if (smaller(tree, v, htemp)) break;
+
+ /* Exchange v with the smallest son */
+ heap[k] = htemp;
+ k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(desc)
+ tree_desc near *desc; /* the tree descriptor */
+{
+ ct_data near *tree = desc->dyn_tree;
+ int near *extra = desc->extra_bits;
+ int base = desc->extra_base;
+ int max_code = desc->max_code;
+ int max_length = desc->max_length;
+ ct_data near *stree = desc->static_tree;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[heap[heap_max]].Len = 0; /* root of the heap */
+
+ for (h = heap_max+1; h < HEAP_SIZE; h++) {
+ n = heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ opt_len += (ulg)f * (bits + xbits);
+ if (stree) static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (bl_count[bits] == 0) bits--;
+ bl_count[bits]--; /* move one leaf down the tree */
+ bl_count[bits+1] += (ush)2; /* move one overflow item as its brother */
+ bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = bl_count[bits];
+ while (n != 0) {
+ m = heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (ush)bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ opt_len += ((long)bits-(long)tree[m].Len)*(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code)
+ ct_data near *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (ush)((code + bl_count[bits-1]) << 1);
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert(code + bl_count[MAX_BITS]-1 == (1<< ((ush) MAX_BITS)) - 1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
+
+ Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(desc)
+ tree_desc near *desc; /* the tree descriptor */
+{
+ ct_data near *tree = desc->dyn_tree;
+ ct_data near *stree = desc->static_tree;
+ int elems = desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node = elems; /* next internal node of the tree */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ heap_len = 0, heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ heap[++heap_len] = max_code = n;
+ depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (heap_len < 2) {
+ int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
+ tree[new].Freq = 1;
+ depth[new] = 0;
+ opt_len--; if (stree) static_len -= stree[new].Len;
+ /* new is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ pqremove(tree, n); /* n = node of least frequency */
+ m = heap[SMALLEST]; /* m = node of next least frequency */
+
+ heap[--heap_max] = n; /* keep the nodes sorted by frequency */
+ heap[--heap_max] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = (ush)(tree[n].Freq + tree[m].Freq);
+ depth[node] = (uch) (Max(depth[n], depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == bl_tree) {
+ fprintf(mesg,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ heap[SMALLEST] = node++;
+ pqdownheap(tree, SMALLEST);
+
+ } while (heap_len >= 2);
+
+ heap[--heap_max] = heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen((tree_desc near *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data near *)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+local void scan_tree (tree, max_code)
+ ct_data near *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)-1; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ bl_tree[curlen].Freq += (ush)count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) bl_tree[curlen].Freq++;
+ bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ bl_tree[REPZ_3_10].Freq++;
+ } else {
+ bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (tree, max_code)
+ ct_data near *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(curlen, bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(curlen, bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
+
+ } else {
+ send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree()
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree((ct_data near *)dyn_ltree, l_desc.max_code);
+ scan_tree((ct_data near *)dyn_dtree, d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree((tree_desc near *)(&bl_desc));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(lcodes, dcodes, blcodes)
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert(lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(lcodes-257, 5);
+ /* not +255 as stated in appnote.txt 1.93a or -256 in 2.04c */
+ send_bits(dcodes-1, 5);
+ send_bits(blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %s",
+ zip_fuzofft(bits_sent, NULL, NULL)));
+
+ send_tree((ct_data near *)dyn_ltree, lcodes-1); /* send the literal tree */
+ Tracev((stderr, "\nlit tree: sent %s",
+ zip_fuzofft(bits_sent, NULL, NULL)));
+
+ send_tree((ct_data near *)dyn_dtree, dcodes-1); /* send the distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld",
+ zip_fuzofft(bits_sent, NULL, NULL)));
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length (in bytes) for the file so far.
+ */
+/* zip64 support 08/29/2003 R.Nausedat */
+uzoff_t flush_block(buf, stored_len, eof)
+ char *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
+
+ /* Check if the file is ascii or binary */
+ if (*file_type == (ush)UNKNOWN) set_file_type();
+
+ /* Construct the literal and distance trees */
+ build_tree((tree_desc near *)(&l_desc));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
+
+ build_tree((tree_desc near *)(&d_desc));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree();
+
+ /* Determine the best encoding. Compute first the block length in bytes */
+ opt_lenb = (opt_len+3+7)>>3;
+ static_lenb = (static_len+3+7)>>3;
+#ifdef DEBUG
+ input_len += stored_len; /* for debugging only */
+#endif
+
+ Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+ opt_lenb, opt_len, static_lenb, static_len, stored_len,
+ last_lit, last_dist));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+#ifndef PGP /* PGP can't handle stored blocks */
+ /* If compression failed and this is the first and last block,
+ * the whole file is transformed into a stored file:
+ */
+#ifdef FORCE_METHOD
+ if (level == 1 && eof && file_method != NULL &&
+ cmpr_bytelen == (uzoff_t)0 && cmpr_len_bits == 0L
+ ) { /* force stored file */
+#else
+ if (stored_len <= opt_lenb && eof && file_method != NULL &&
+ cmpr_bytelen == (uzoff_t)0 && cmpr_len_bits == 0L &&
+ seekable() && !use_descriptors) {
+#endif
+ /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+ if (buf == NULL) error ("block vanished");
+
+ copy_block(buf, (unsigned)stored_len, 0); /* without header */
+ cmpr_bytelen = stored_len;
+ *file_method = STORE;
+ } else
+#endif /* PGP */
+
+#ifdef FORCE_METHOD
+ if (level <= 2 && buf != (char*)NULL) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)NULL) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ send_bits((STORED_BLOCK<<1)+eof, 3); /* send block type */
+ cmpr_bytelen += ((cmpr_len_bits + 3 + 7) >> 3) + stored_len + 4;
+ cmpr_len_bits = 0L;
+
+ copy_block(buf, (unsigned)stored_len, 1); /* with header */
+
+#ifdef FORCE_METHOD
+ } else if (level == 3) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits((STATIC_TREES<<1)+eof, 3);
+ compress_block((ct_data near *)static_ltree, (ct_data near *)static_dtree);
+ cmpr_len_bits += 3 + static_len;
+ cmpr_bytelen += cmpr_len_bits >> 3;
+ cmpr_len_bits &= 7L;
+ } else {
+ send_bits((DYN_TREES<<1)+eof, 3);
+ send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+ compress_block((ct_data near *)dyn_ltree, (ct_data near *)dyn_dtree);
+ cmpr_len_bits += 3 + opt_len;
+ cmpr_bytelen += cmpr_len_bits >> 3;
+ cmpr_len_bits &= 7L;
+ }
+ Assert(((cmpr_bytelen << 3) + cmpr_len_bits) == bits_sent,
+ "bad compressed size");
+ init_block();
+
+ if (eof) {
+#if defined(PGP) && !defined(MMAP)
+ /* Wipe out sensitive data for pgp */
+# ifdef DYN_ALLOC
+ extern uch *window;
+# else
+ extern uch window[];
+# endif
+ memset(window, 0, (unsigned)(2*WSIZE-1)); /* -1 needed if WSIZE=32K */
+#else /* !PGP */
+ Assert(input_len == isize, "bad input size");
+#endif
+ bi_windup();
+ cmpr_len_bits += 7; /* align on byte boundary */
+ }
+ Tracev((stderr,"\ncomprlen %s(%s) ",
+ zip_fuzofft( cmpr_bytelen + (cmpr_len_bits>>3), NULL, NULL),
+ zip_fuzofft( (cmpr_bytelen << 3) + cmpr_len_bits - 7*eof, NULL, NULL)));
+ Trace((stderr, "\n"));
+
+ return cmpr_bytelen + (cmpr_len_bits >> 3);
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ct_tally (dist, lc)
+ int dist; /* distance of matched string */
+ int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ l_buf[last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ dyn_ltree[lc].Freq++;
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
+
+ dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+ dyn_dtree[d_code(dist)].Freq++;
+
+ d_buf[last_dist++] = (ush)dist;
+ flags |= flag_bit;
+ }
+ flag_bit <<= 1;
+
+ /* Output the flags if they fill a byte: */
+ if ((last_lit & 7) == 0) {
+ flag_buf[last_flags++] = flags;
+ flags = 0, flag_bit = 1;
+ }
+ /* Try to guess if it is profitable to stop the current block here */
+ if (level > 2 && (last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)last_lit*8L;
+ ulg in_length = (ulg)strstart-block_start;
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+ last_lit, last_dist, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
+ }
+ return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
+ /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(ltree, dtree)
+ ct_data near *ltree; /* literal tree */
+ ct_data near *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned dx = 0; /* running index in d_buf */
+ unsigned fx = 0; /* running index in flag_buf */
+ uch flag = 0; /* current flags */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (last_lit != 0) do {
+ if ((lx & 7) == 0) flag = flag_buf[fx++];
+ lc = l_buf[lx++];
+ if ((flag & 1) == 0) {
+ send_code(lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = length_code[lc];
+ send_code(code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(lc, extra); /* send the extra length bits */
+ }
+ dist = d_buf[dx++];
+ /* Here, dist is the match distance - 1 */
+ code = d_code(dist);
+ Assert(code < D_CODES, "bad d_code");
+
+ send_code(code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+ flag >>= 1;
+ } while (lx < last_lit);
+
+ send_code(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to TEXT (ASCII) or BINARY, using following algorithm:
+ * - TEXT, either ASCII or an ASCII-compatible extension such as ISO-8859,
+ * UTF-8, etc., when the following two conditions are satisfied:
+ * a) There are no non-portable control characters belonging to the
+ * "black list" (0..6, 14..25, 28..31).
+ * b) There is at least one printable character belonging to the
+ * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ *
+ * Note that the following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ *
+ * Also note that, unlike in the previous 20% binary detection algorithm,
+ * any control characters in the black list will set the file type to
+ * BINARY. If a text file contains a single accidental black character,
+ * the file will be flagged as BINARY in the archive.
+ *
+ * IN assertion: the fields freq of dyn_ltree are set.
+ */
+local void set_file_type()
+{
+ /* bit-mask of black-listed bytes
+ * bit is set if byte is black-listed
+ * set bits 0..6, 14..25, and 28..31
+ * 0xf3ffc07f = binary 11110011111111111100000001111111
+ */
+ unsigned long mask = 0xf3ffc07fL;
+ int n;
+
+ /* Check for non-textual ("black-listed") bytes. */
+ for (n = 0; n <= 31; n++, mask >>= 1)
+ if ((mask & 1) && (dyn_ltree[n].Freq != 0))
+ {
+ *file_type = BINARY;
+ return;
+ }
+
+ /* Check for textual ("white-listed") bytes. */
+ *file_type = ASCII;
+ if (dyn_ltree[9].Freq != 0 || dyn_ltree[10].Freq != 0
+ || dyn_ltree[13].Freq != 0)
+ return;
+ for (n = 32; n < LITERALS; n++)
+ if (dyn_ltree[n].Freq != 0)
+ return;
+
+ /* This deflate stream is either empty, or
+ * it has tolerated ("gray-listed") bytes only.
+ */
+ *file_type = BINARY;
+}
+
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+void bi_init (tgt_buf, tgt_size, flsh_allowed)
+ char *tgt_buf;
+ unsigned tgt_size;
+ int flsh_allowed;
+{
+ out_buf = tgt_buf;
+ out_size = tgt_size;
+ out_offset = 0;
+ flush_flg = flsh_allowed;
+
+ bi_buf = 0;
+ bi_valid = 0;
+#ifdef DEBUG
+ bits_sent = (uzoff_t)0;
+#endif
+}
+
+#if (!defined(ASMV) || !defined(RISCOS))
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+local void send_bits(value, length)
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+#ifdef DEBUG
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ bits_sent += (uzoff_t)length;
+#endif
+ /* If not enough room in bi_buf, use (bi_valid) bits from bi_buf and
+ * (Buf_size - bi_valid) bits from value to flush the filled bi_buf,
+ * then fill in the rest of (value), leaving (length - (Buf_size-bi_valid))
+ * unused bits in bi_buf.
+ */
+ bi_buf |= (value << bi_valid);
+ bi_valid += length;
+ if (bi_valid > (int)Buf_size) {
+ PUTSHORT(bi_buf);
+ bi_valid -= Buf_size;
+ bi_buf = (unsigned)value >> (length - bi_valid);
+ }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+#endif /* !ASMV || !RISCOS */
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+local void bi_windup()
+{
+ if (bi_valid > 8) {
+ PUTSHORT(bi_buf);
+ } else if (bi_valid > 0) {
+ PUTBYTE(bi_buf);
+ }
+ if (flush_flg) {
+ flush_outbuf(out_buf, &out_offset);
+ }
+ bi_buf = 0;
+ bi_valid = 0;
+#ifdef DEBUG
+ bits_sent = (bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ *
+ * Buffer Overwrite fix
+ *
+ * A buffer flush has been added to fix a bug when encrypting deflated files
+ * with embedded "copied blocks". When encrypting, the flush_out() routine
+ * modifies its data buffer because encryption is done "in-place" in
+ * zfwrite(), whereas without encryption, the flush_out() data buffer is
+ * left unaltered. This can be a problem as noted below by the submitter.
+ *
+ * "But an exception comes when a block of stored data (data that could not
+ * be compressed) is being encrypted. In this case, the data that is passed
+ * to zfwrite (and is therefore encrypted-in-place) is actually a block of
+ * data from within the sliding input window that is being managed by
+ * deflate.c.
+ *
+ * "Since part of the sliding input window has now been overwritten by
+ * encrypted (and essentially random) data, deflate.c's search for previous
+ * text that matches the current text will usually fail but on rare
+ * occasions will find a match with something in the encrypted data. This
+ * incorrect match then causes incorrect information to be placed in the
+ * ZIP file."
+ *
+ * The problem results in the zip file having bad data and so a bad CRC.
+ * This does not happen often and to recreate the problem a large file
+ * with non-compressable data is needed so that deflate chooses to store the
+ * data. A test file of 400 MB seems large enough to recreate the problem
+ * using a command such as
+ * zip -1 -e crcerror.zip testfile.dat
+ * maybe half the time.
+ *
+ * This problem has been fixed by copying the data into the deflate output
+ * buffer before calling flush_outbuf(), when encryption is enabled.
+ *
+ * Thanks to the nice people at WinZip for identifying the problem and
+ * passing it on. Also see Changes.
+ *
+ * 2006-03-06 EG, CS
+ */
+local void copy_block(block, len, header)
+ char *block; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(); /* align on byte boundary */
+
+ if (header) {
+ PUTSHORT((ush)len);
+ PUTSHORT((ush)~len);
+#ifdef DEBUG
+ bits_sent += 2*16;
+#endif
+ }
+ if (flush_flg) {
+ flush_outbuf(out_buf, &out_offset);
+ if (key != (char *)NULL) { /* key is the global password pointer */
+ /* Encryption modifies the data in the output buffer. But the
+ * copied input data must remain intact for further deflate
+ * string matching lookups. Therefore, the input data is
+ * copied into the compression output buffer for flushing
+ * to the compressed/encrypted output stream.
+ */
+ while(len > 0) {
+ out_offset = (len < out_size ? len : out_size);
+ memcpy(out_buf, block, out_offset);
+ block += out_offset;
+ len -= out_offset;
+ flush_outbuf(out_buf, &out_offset);
+ }
+ } else {
+ /* Without encryption, the output routines do not touch the
+ * written data, so there is no need for an additional copy
+ * operation.
+ */
+ out_offset = len;
+ flush_outbuf(block, &out_offset);
+ }
+ } else if (out_offset + len > out_size) {
+ error("output buffer too small for in-memory compression");
+ } else {
+ memcpy(out_buf + out_offset, block, len);
+ out_offset += len;
+ }
+#ifdef DEBUG
+ bits_sent += (ulg)len<<3;
+#endif
+}
+
+#endif /* !USE_ZLIB */
diff --git a/ttyio.c b/ttyio.c
new file mode 100644
index 0000000..5899fdc
--- /dev/null
+++ b/ttyio.c
@@ -0,0 +1,702 @@
+/*
+ ttyio.c - Zip 3
+
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ ttyio.c
+
+ This file contains routines for doing console input/output, including code
+ for non-echoing input. It is used by the encryption/decryption code but
+ does not contain any restricted code itself. This file is shared between
+ Info-ZIP's Zip and UnZip.
+
+ Contains: echo() (VMS only)
+ Echon() (Unix only)
+ Echoff() (Unix only)
+ screensize() (Unix only)
+ zgetch() (Unix, VMS, and non-Unix/VMS versions)
+ getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS)
+
+ ---------------------------------------------------------------------------*/
+
+#define __TTYIO_C /* identifies this source module */
+
+#include "zip.h"
+#include "crypt.h"
+
+#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
+/* Non-echo console/keyboard input is needed for (en/de)cryption's password
+ * entry, and for UnZip(SFX)'s MORE and Pause features.
+ * (The corresponding #endif is found at the end of this module.)
+ */
+
+#include "ttyio.h"
+
+#ifndef PUTC
+# define PUTC putc
+#endif
+
+#ifdef ZIP
+# ifdef GLOBAL /* used in Amiga system headers, maybe others too */
+# undef GLOBAL
+# endif
+# define GLOBAL(g) g
+#else
+# define GLOBAL(g) G.g
+#endif
+
+#if (defined(__ATHEOS__) || defined(__BEOS__)) /* why yes, we do */
+# define HAVE_TERMIOS_H
+#endif
+
+#ifdef _POSIX_VERSION
+# ifndef USE_POSIX_TERMIOS
+# define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */
+# endif
+# ifndef HAVE_TERMIOS_H
+# define HAVE_TERMIOS_H /* POSIX termios.h */
+# endif
+#endif /* _POSIX_VERSION */
+
+#ifdef UNZIP /* Zip handles this with the unix/configure script */
+# ifndef _POSIX_VERSION
+# if (defined(SYSV) || defined(CRAY)) && !defined(__MINT__)
+# ifndef USE_SYSV_TERMIO
+# define USE_SYSV_TERMIO
+# endif
+# ifdef COHERENT
+# ifndef HAVE_TERMIO_H
+# define HAVE_TERMIO_H
+# endif
+# ifdef HAVE_SYS_TERMIO_H
+# undef HAVE_SYS_TERMIO_H
+# endif
+# else /* !COHERENT */
+# ifdef HAVE_TERMIO_H
+# undef HAVE_TERMIO_H
+# endif
+# ifndef HAVE_SYS_TERMIO_H
+# define HAVE_SYS_TERMIO_H
+# endif
+# endif /* ?COHERENT */
+# endif /* (SYSV || CRAY) && !__MINT__ */
+# endif /* !_POSIX_VERSION */
+# if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
+# ifndef NO_FCNTL_H
+# define NO_FCNTL_H
+# endif
+# endif /* !(BSD4_4 || SYSV || __convexc__) */
+#endif /* UNZIP */
+
+#ifdef HAVE_TERMIOS_H
+# ifndef USE_POSIX_TERMIOS
+# define USE_POSIX_TERMIOS
+# endif
+#endif
+
+#if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H))
+# ifndef USE_SYSV_TERMIO
+# define USE_SYSV_TERMIO
+# endif
+#endif
+
+#if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE))
+# include <sys/ioctl.h>
+# define GOT_IOCTL_H
+ /* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */
+#endif
+
+#ifndef HAVE_WORKING_GETCH
+ /* include system support for switching of console echo */
+# ifdef VMS
+# include <descrip.h>
+# include <iodef.h>
+# include <ttdef.h>
+# include <starlet.h>
+# include <ssdef.h>
+# else /* !VMS */
+# ifdef HAVE_TERMIOS_H
+# include <termios.h>
+# define sgttyb termios
+# define sg_flags c_lflag
+# define GTTY(f, s) tcgetattr(f, (zvoid *) s)
+# define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s)
+# else /* !HAVE_TERMIOS_H */
+# ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */
+# ifdef HAVE_TERMIO_H
+# include <termio.h>
+# endif
+# ifdef HAVE_SYS_TERMIO_H
+# include <sys/termio.h>
+# endif
+# ifdef NEED_PTEM
+# include <sys/stream.h>
+# include <sys/ptem.h>
+# endif
+# define sgttyb termio
+# define sg_flags c_lflag
+# define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s)
+# define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s)
+# else /* !USE_SYSV_TERMIO */
+# ifndef CMS_MVS
+# if (!defined(MINIX) && !defined(GOT_IOCTL_H))
+# include <sys/ioctl.h>
+# endif
+# include <sgtty.h>
+# define GTTY gtty
+# define STTY stty
+# ifdef UNZIP
+ /*
+ * XXX : Are these declarations needed at all ????
+ */
+ /*
+ * GRR: let's find out... Hmmm, appears not...
+ int gtty OF((int, struct sgttyb *));
+ int stty OF((int, struct sgttyb *));
+ */
+# endif
+# endif /* !CMS_MVS */
+# endif /* ?USE_SYSV_TERMIO */
+# endif /* ?HAVE_TERMIOS_H */
+# ifndef NO_FCNTL_H
+# ifndef UNZIP
+# include <fcntl.h>
+# endif
+# else
+ char *ttyname OF((int));
+# endif
+# endif /* ?VMS */
+#endif /* !HAVE_WORKING_GETCH */
+
+
+
+#ifndef HAVE_WORKING_GETCH
+#ifdef VMS
+
+static struct dsc$descriptor_s DevDesc =
+ {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"};
+ /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
+
+/*
+ * Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c
+ * and hence on Joe Meadows' file.c code.
+ */
+int echo(opt)
+ int opt;
+{
+ /*
+ * For VMS v5.x:
+ * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
+ * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
+ * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
+ * System Services Reference Manual, pp. sys-23, sys-379
+ * fixed-length descriptor info: Programming, Vol. 3, System Services,
+ * Intro to System Routines, sec. 2.9.2
+ * Greg Roelofs, 15 Aug 91
+ */
+
+ short DevChan, iosb[4];
+ long status;
+ unsigned long ttmode[2]; /* space for 8 bytes */
+
+
+ /* assign a channel to standard input */
+ status = sys$assign(&DevDesc, &DevChan, 0, 0);
+ if (!(status & 1))
+ return status;
+
+ /* use sys$qio and the IO$_SENSEMODE function to determine the current
+ * tty status (for password reading, could use IO$_READVBLK function
+ * instead, but echo on/off will be more general)
+ */
+ status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
+ ttmode, 8, 0, 0, 0, 0);
+ if (!(status & 1))
+ return status;
+ status = iosb[0];
+ if (!(status & 1))
+ return status;
+
+ /* modify mode buffer to be either NOECHO or ECHO
+ * (depending on function argument opt)
+ */
+ if (opt == 0) /* off */
+ ttmode[1] |= TT$M_NOECHO; /* set NOECHO bit */
+ else
+ ttmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */
+
+ /* use the IO$_SETMODE function to change the tty status */
+ status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
+ ttmode, 8, 0, 0, 0, 0);
+ if (!(status & 1))
+ return status;
+ status = iosb[0];
+ if (!(status & 1))
+ return status;
+
+ /* deassign the sys$input channel by way of clean-up */
+ status = sys$dassgn(DevChan);
+ if (!(status & 1))
+ return status;
+
+ return SS$_NORMAL; /* we be happy */
+
+} /* end function echo() */
+
+
+/*
+ * Read a single character from keyboard in non-echoing mode (VMS).
+ * (returns EOF in case of errors)
+ */
+int tt_getch()
+{
+ short DevChan, iosb[4];
+ long status;
+ char kbbuf[16]; /* input buffer with - some - excess length */
+
+ /* assign a channel to standard input */
+ status = sys$assign(&DevDesc, &DevChan, 0, 0);
+ if (!(status & 1))
+ return EOF;
+
+ /* read a single character from SYS$COMMAND (no-echo) and
+ * wait for completion
+ */
+ status = sys$qiow(0,DevChan,
+ IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
+ &iosb, 0, 0,
+ &kbbuf, 1, 0, 0, 0, 0);
+ if ((status&1) == 1)
+ status = iosb[0];
+
+ /* deassign the sys$input channel by way of clean-up
+ * (for this step, we do not need to check the completion status)
+ */
+ sys$dassgn(DevChan);
+
+ /* return the first char read, or EOF in case the read request failed */
+ return (int)(((status&1) == 1) ? (uch)kbbuf[0] : EOF);
+
+} /* end function tt_getch() */
+
+
+#else /* !VMS: basically Unix */
+
+
+/* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */
+#ifndef CMS_MVS
+
+#ifdef ZIP /* moved to globals.h for UnZip */
+ static int echofd=(-1); /* file descriptor whose echo is off */
+#endif
+
+/*
+ * Turn echo off for file descriptor f. Assumes that f is a tty device.
+ */
+void Echoff(__G__ f)
+ __GDEF
+ int f; /* file descriptor for which to turn echo off */
+{
+ struct sgttyb sg; /* tty device structure */
+
+ GLOBAL(echofd) = f;
+ GTTY(f, &sg); /* get settings */
+ sg.sg_flags &= ~ECHO; /* turn echo off */
+ STTY(f, &sg);
+}
+
+/*
+ * Turn echo back on for file descriptor echofd.
+ */
+void Echon(__G)
+ __GDEF
+{
+ struct sgttyb sg; /* tty device structure */
+
+ if (GLOBAL(echofd) != -1) {
+ GTTY(GLOBAL(echofd), &sg); /* get settings */
+ sg.sg_flags |= ECHO; /* turn echo on */
+ STTY(GLOBAL(echofd), &sg);
+ GLOBAL(echofd) = -1;
+ }
+}
+
+#endif /* !CMS_MVS */
+#endif /* ?VMS */
+
+
+#if (defined(UNZIP) && !defined(FUNZIP))
+
+#ifdef ATH_BEO_UNX
+#ifdef MORE
+
+/*
+ * Get the number of lines on the output terminal. SCO Unix apparently
+ * defines TIOCGWINSZ but doesn't support it (!M_UNIX).
+ *
+ * GRR: will need to know width of terminal someday, too, to account for
+ * line-wrapping.
+ */
+
+#if (defined(TIOCGWINSZ) && !defined(M_UNIX))
+
+int screensize(tt_rows, tt_cols)
+ int *tt_rows;
+ int *tt_cols;
+{
+ struct winsize wsz;
+#ifdef DEBUG_WINSZ
+ static int firsttime = TRUE;
+#endif
+
+ /* see termio(4) under, e.g., SunOS */
+ if (ioctl(1, TIOCGWINSZ, &wsz) == 0) {
+#ifdef DEBUG_WINSZ
+ if (firsttime) {
+ firsttime = FALSE;
+ fprintf(stderr, "ttyio.c screensize(): ws_row = %d\n",
+ wsz.ws_row);
+ fprintf(stderr, "ttyio.c screensize(): ws_col = %d\n",
+ wsz.ws_col);
+ }
+#endif
+ /* number of rows */
+ if (tt_rows != NULL)
+ *tt_rows = (int)((wsz.ws_row > 0) ? wsz.ws_row : 24);
+ /* number of columns */
+ if (tt_cols != NULL)
+ *tt_cols = (int)((wsz.ws_col > 0) ? wsz.ws_col : 80);
+ return 0; /* signal success */
+ } else { /* this happens when piping to more(1), for example */
+#ifdef DEBUG_WINSZ
+ if (firsttime) {
+ firsttime = FALSE;
+ fprintf(stderr,
+ "ttyio.c screensize(): ioctl(TIOCGWINSZ) failed\n"));
+ }
+#endif
+ /* VT-100 assumed to be minimal hardware */
+ if (tt_rows != NULL)
+ *tt_rows = 24;
+ if (tt_cols != NULL)
+ *tt_cols = 80;
+ return 1; /* signal failure */
+ }
+}
+
+#else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */
+
+int screensize(tt_rows, tt_cols)
+ int *tt_rows;
+ int *tt_cols;
+{
+ char *envptr, *getenv();
+ int n;
+ int errstat = 0;
+
+ /* GRR: this is overly simplistic, but don't have access to stty/gtty
+ * system anymore
+ */
+ if (tt_rows != NULL) {
+ envptr = getenv("LINES");
+ if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
+ /* VT-100 assumed to be minimal hardware */
+ *tt_rows = 24;
+ errstat = 1; /* signal failure */
+ } else {
+ *tt_rows = n;
+ }
+ }
+ if (tt_cols != NULL) {
+ envptr = getenv("COLUMNS");
+ if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
+ *tt_cols = 80;
+ errstat = 1; /* signal failure */
+ } else {
+ *tt_cols = n;
+ }
+ }
+ return errstat;
+}
+
+#endif /* ?(TIOCGWINSZ && !M_UNIX) */
+#endif /* MORE */
+
+
+/*
+ * Get a character from the given file descriptor without echo or newline.
+ */
+int zgetch(__G__ f)
+ __GDEF
+ int f; /* file descriptor from which to read */
+{
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+ char oldmin, oldtim;
+#endif
+ char c;
+ struct sgttyb sg; /* tty device structure */
+
+ GTTY(f, &sg); /* get settings */
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+ oldmin = sg.c_cc[VMIN]; /* save old values */
+ oldtim = sg.c_cc[VTIME];
+ sg.c_cc[VMIN] = 1; /* need only one char to return read() */
+ sg.c_cc[VTIME] = 0; /* no timeout */
+ sg.sg_flags &= ~ICANON; /* canonical mode off */
+#else
+ sg.sg_flags |= CBREAK; /* cbreak mode on */
+#endif
+ sg.sg_flags &= ~ECHO; /* turn echo off, too */
+ STTY(f, &sg); /* set cbreak mode */
+ GLOBAL(echofd) = f; /* in case ^C hit (not perfect: still CBREAK) */
+
+ read(f, &c, 1); /* read our character */
+
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+ sg.c_cc[VMIN] = oldmin; /* restore old values */
+ sg.c_cc[VTIME] = oldtim;
+ sg.sg_flags |= ICANON; /* canonical mode on */
+#else
+ sg.sg_flags &= ~CBREAK; /* cbreak mode off */
+#endif
+ sg.sg_flags |= ECHO; /* turn echo on */
+ STTY(f, &sg); /* restore canonical mode */
+ GLOBAL(echofd) = -1;
+
+ return (int)(uch)c;
+}
+
+
+#else /* !ATH_BEO_UNX */
+#ifndef VMS /* VMS supplies its own variant of getch() */
+
+
+int zgetch(__G__ f)
+ __GDEF
+ int f; /* file descriptor from which to read (must be open already) */
+{
+ char c, c2;
+
+/*---------------------------------------------------------------------------
+ Get a character from the given file descriptor without echo; can't fake
+ CBREAK mode (i.e., newline required), but can get rid of all chars up to
+ and including newline.
+ ---------------------------------------------------------------------------*/
+
+ echoff(f);
+ read(f, &c, 1);
+ if (c != '\n')
+ do {
+ read(f, &c2, 1); /* throw away all other chars up thru newline */
+ } while (c2 != '\n');
+ echon();
+ return (int)c;
+}
+
+#endif /* !VMS */
+#endif /* ?ATH_BEO_UNX */
+
+#endif /* UNZIP && !FUNZIP */
+#endif /* !HAVE_WORKING_GETCH */
+
+
+#if CRYPT /* getp() is only used with full encryption */
+
+/*
+ * Simple compile-time check for source compatibility between
+ * zcrypt and ttyio:
+ */
+#if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7))
+ error: This Info-ZIP tool requires zcrypt 2.7 or later.
+#endif
+
+/*
+ * Get a password of length n-1 or less into *p using the prompt *m.
+ * The entered password is not echoed.
+ */
+
+#ifdef HAVE_WORKING_GETCH
+/*
+ * For the AMIGA, getch() is defined as Agetch(), which is in
+ * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch()
+ * uses the infrastructure that is already in place in filedate.c, it is
+ * smaller. With this function, echoff() and echon() are not needed.
+ *
+ * For the MAC, a non-echo macgetch() function is defined in the MacOS
+ * specific sources which uses the event handling mechanism of the
+ * desktop window manager to get a character from the keyboard.
+ *
+ * For the other systems in this section, a non-echo getch() function
+ * is either contained the C runtime library (conio package), or getch()
+ * is defined as an alias for a similar system specific RTL function.
+ */
+
+#ifndef WINDLL /* WINDLL does not support a console interface */
+#ifndef QDOS /* QDOS supplies a variant of this function */
+
+/* This is the getp() function for all systems (with TTY type user interface)
+ * that supply a working `non-echo' getch() function for "raw" console input.
+ */
+char *getp(__G__ m, p, n)
+ __GDEF
+ ZCONST char *m; /* prompt for password */
+ char *p; /* return value: line input */
+ int n; /* bytes available in p[] */
+{
+ char c; /* one-byte buffer for read() to use */
+ int i; /* number of characters input */
+ char *w; /* warning on retry */
+
+ /* get password */
+ w = "";
+ do {
+ fputs(w, stderr); /* warning if back again */
+ fputs(m, stderr); /* display prompt and flush */
+ fflush(stderr);
+ i = 0;
+ do { /* read line, keeping first n characters */
+ if ((c = (char)getch()) == '\r')
+ c = '\n'; /* until user hits CR */
+ if (c == 8 || c == 127) {
+ if (i > 0) i--; /* the `backspace' and `del' keys works */
+ }
+ else if (i < n)
+ p[i++] = c; /* truncate past n */
+ } while (c != '\n');
+ PUTC('\n', stderr); fflush(stderr);
+ w = "(line too long--try again)\n";
+ } while (p[i-1] != '\n');
+ p[i-1] = 0; /* terminate at newline */
+
+ return p; /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* !QDOS */
+#endif /* !WINDLL */
+
+
+#else /* !HAVE_WORKING_GETCH */
+
+
+#if (defined(ATH_BEO_UNX) || defined(__MINT__))
+
+#ifndef _PATH_TTY
+# ifdef __MINT__
+# define _PATH_TTY ttyname(2)
+# else
+# define _PATH_TTY "/dev/tty"
+# endif
+#endif
+
+char *getp(__G__ m, p, n)
+ __GDEF
+ ZCONST char *m; /* prompt for password */
+ char *p; /* return value: line input */
+ int n; /* bytes available in p[] */
+{
+ char c; /* one-byte buffer for read() to use */
+ int i; /* number of characters input */
+ char *w; /* warning on retry */
+ int f; /* file descriptor for tty device */
+
+#ifdef PASSWD_FROM_STDIN
+ /* Read from stdin. This is unsafe if the password is stored on disk. */
+ f = 0;
+#else
+ /* turn off echo on tty */
+
+ if ((f = open(_PATH_TTY, 0)) == -1)
+ return NULL;
+#endif
+ /* get password */
+ w = "";
+ do {
+ fputs(w, stderr); /* warning if back again */
+ fputs(m, stderr); /* prompt */
+ fflush(stderr);
+ i = 0;
+ echoff(f);
+ do { /* read line, keeping n */
+ read(f, &c, 1);
+ if (i < n)
+ p[i++] = c;
+ } while (c != '\n');
+ echon();
+ PUTC('\n', stderr); fflush(stderr);
+ w = "(line too long--try again)\n";
+ } while (p[i-1] != '\n');
+ p[i-1] = 0; /* terminate at newline */
+
+#ifndef PASSWD_FROM_STDIN
+ close(f);
+#endif
+
+ return p; /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* ATH_BEO_UNX || __MINT__ */
+
+
+
+#if (defined(VMS) || defined(CMS_MVS))
+
+char *getp(__G__ m, p, n)
+ __GDEF
+ ZCONST char *m; /* prompt for password */
+ char *p; /* return value: line input */
+ int n; /* bytes available in p[] */
+{
+ char c; /* one-byte buffer for read() to use */
+ int i; /* number of characters input */
+ char *w; /* warning on retry */
+ FILE *f; /* file structure for SYS$COMMAND device */
+
+#ifdef PASSWD_FROM_STDIN
+ f = stdin;
+#else
+ if ((f = fopen(ctermid(NULL), "r")) == NULL)
+ return NULL;
+#endif
+
+ /* get password */
+ fflush(stdout);
+ w = "";
+ do {
+ if (*w) /* bug: VMS apparently adds \n to NULL fputs */
+ fputs(w, stderr); /* warning if back again */
+ fputs(m, stderr); /* prompt */
+ fflush(stderr);
+ i = 0;
+ echoff(f);
+ do { /* read line, keeping n */
+ if ((c = (char)getc(f)) == '\r')
+ c = '\n';
+ if (i < n)
+ p[i++] = c;
+ } while (c != '\n');
+ echon();
+ PUTC('\n', stderr); fflush(stderr);
+ w = "(line too long--try again)\n";
+ } while (p[i-1] != '\n');
+ p[i-1] = 0; /* terminate at newline */
+#ifndef PASSWD_FROM_STDIN
+ fclose(f);
+#endif
+
+ return p; /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* VMS || CMS_MVS */
+#endif /* ?HAVE_WORKING_GETCH */
+#endif /* CRYPT */
+#endif /* CRYPT || (UNZIP && !FUNZIP) */
diff --git a/ttyio.h b/ttyio.h
new file mode 100644
index 0000000..df6a4ed
--- /dev/null
+++ b/ttyio.h
@@ -0,0 +1,229 @@
+/*
+ ttyio.h - Zip 3
+
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ ttyio.h
+ */
+
+#ifndef __ttyio_h /* don't include more than once */
+#define __ttyio_h
+
+#ifndef __crypt_h
+# include "crypt.h" /* ensure that encryption header file has been seen */
+#endif
+
+#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
+/*
+ * Non-echo keyboard/console input support is needed and enabled.
+ */
+
+#ifndef __G /* UnZip only, for now (DLL stuff) */
+# define __G
+# define __G__
+# define __GDEF
+# define __GPRO void
+# define __GPRO__
+#endif
+
+#ifndef ZCONST /* UnZip only (until have configure script like Zip) */
+# define ZCONST const
+#endif
+
+#if (defined(MSDOS) || defined(OS2) || defined(WIN32))
+# ifndef DOS_OS2_W32
+# define DOS_OS2_W32
+# endif
+#endif
+
+#if (defined(DOS_OS2_W32) || defined(__human68k__))
+# ifndef DOS_H68_OS2_W32
+# define DOS_H68_OS2_W32
+# endif
+#endif
+
+#if (defined(DOS_OS2_W32) || defined(FLEXOS))
+# ifndef DOS_FLX_OS2_W32
+# define DOS_FLX_OS2_W32
+# endif
+#endif
+
+#if (defined(DOS_H68_OS2_W32) || defined(FLEXOS))
+# ifndef DOS_FLX_H68_OS2_W32
+# define DOS_FLX_H68_OS2_W32
+# endif
+#endif
+
+#if (defined(__ATHEOS__) || defined(__BEOS__) || defined(UNIX))
+# ifndef ATH_BEO_UNX
+# define ATH_BEO_UNX
+# endif
+#endif
+
+#if (defined(VM_CMS) || defined(MVS))
+# ifndef CMS_MVS
+# define CMS_MVS
+# endif
+#endif
+
+
+/* Function prototypes */
+
+/* The following systems supply a `non-echo' character input function "getch()"
+ * (or an alias) and do not need the echoff() / echon() function pair.
+ */
+#ifdef AMIGA
+# define echoff(f)
+# define echon()
+# define getch() Agetch()
+# define HAVE_WORKING_GETCH
+#endif /* AMIGA */
+
+#ifdef ATARI
+# define echoff(f)
+# define echon()
+# include <osbind.h>
+# define getch() (Cnecin() & 0x000000ff)
+# define HAVE_WORKING_GETCH
+#endif
+
+#ifdef MACOS
+# define echoff(f)
+# define echon()
+# define getch() macgetch()
+# define HAVE_WORKING_GETCH
+#endif
+
+#ifdef NLM
+# define echoff(f)
+# define echon()
+# define HAVE_WORKING_GETCH
+#endif
+
+#ifdef QDOS
+# define echoff(f)
+# define echon()
+# define HAVE_WORKING_GETCH
+#endif
+
+#ifdef RISCOS
+# define echoff(f)
+# define echon()
+# define getch() SWI_OS_ReadC()
+# define HAVE_WORKING_GETCH
+#endif
+
+#ifdef DOS_H68_OS2_W32
+# define echoff(f)
+# define echon()
+# ifdef WIN32
+# ifndef getch
+# define getch() getch_win32()
+# endif
+# else /* !WIN32 */
+# ifdef __EMX__
+# ifndef getch
+# define getch() _read_kbd(0, 1, 0)
+# endif
+# else /* !__EMX__ */
+# ifdef __GO32__
+# include <pc.h>
+# define getch() getkey()
+# else /* !__GO32__ */
+# include <conio.h>
+# endif /* ?__GO32__ */
+# endif /* ?__EMX__ */
+# endif /* ?WIN32 */
+# define HAVE_WORKING_GETCH
+#endif /* DOS_H68_OS2_W32 */
+
+#ifdef FLEXOS
+# define echoff(f)
+# define echon()
+# define getch() getchar() /* not correct, but may not be on a console */
+# define HAVE_WORKING_GETCH
+#endif
+
+/* For VM/CMS and MVS, we do not (yet) have any support to switch terminal
+ * input echo on and off. The following "fake" definitions allow inclusion
+ * of crypt support and UnZip's "pause prompting" features, but without
+ * any echo suppression.
+ */
+#ifdef CMS_MVS
+# define echoff(f)
+# define echon()
+#endif
+
+#ifdef TANDEM
+# define echoff(f)
+# define echon()
+# define getch() zgetch() /* defined in TANDEMC */
+# define HAVE_WORKING_GETCH
+#endif
+
+/* The THEOS C runtime library supplies the function conmask() to toggle
+ * terminal input echo on (conmask("e")) and off (conmask("n")). But,
+ * since THEOS C RTL also contains a working non-echo getch() function,
+ * the echo toggles are not needed.
+ */
+#ifdef THEOS
+# define echoff(f)
+# define echon()
+# define HAVE_WORKING_GETCH
+#endif
+
+/* VMS has a single echo() function in ttyio.c to toggle terminal
+ * input echo on and off.
+ */
+#ifdef VMS
+# define echoff(f) echo(0)
+# define echon() echo(1)
+# define getch() tt_getch()
+# define FGETCH(f) tt_getch()
+ int echo OF((int));
+ int tt_getch OF((void));
+#endif
+
+/* For all other systems, ttyio.c supplies the two functions Echoff() and
+ * Echon() for suppressing and (re)enabling console input echo.
+ */
+#ifndef echoff
+# define echoff(f) Echoff(__G__ f)
+# define echon() Echon(__G)
+ void Echoff OF((__GPRO__ int f));
+ void Echon OF((__GPRO));
+#endif
+
+/* this stuff is used by MORE and also now by the ctrl-S code; fileio.c only */
+#if (defined(UNZIP) && !defined(FUNZIP))
+# ifdef HAVE_WORKING_GETCH
+# define FGETCH(f) getch()
+# endif
+# ifndef FGETCH
+ /* default for all systems where no getch()-like function is available */
+ int zgetch OF((__GPRO__ int f));
+# define FGETCH(f) zgetch(__G__ f)
+# endif
+#endif /* UNZIP && !FUNZIP */
+
+#if (CRYPT && !defined(WINDLL))
+ char *getp OF((__GPRO__ ZCONST char *m, char *p, int n));
+#endif
+
+#else /* !(CRYPT || (UNZIP && !FUNZIP)) */
+
+/*
+ * No need for non-echo keyboard/console input; provide dummy definitions.
+ */
+#define echoff(f)
+#define echon()
+
+#endif /* ?(CRYPT || (UNZIP && !FUNZIP)) */
+
+#endif /* !__ttyio_h */
diff --git a/unix/Makefile b/unix/Makefile
new file mode 100644
index 0000000..abd0c44
--- /dev/null
+++ b/unix/Makefile
@@ -0,0 +1,329 @@
+# Makefile for Zip, ZipNote, ZipCloak and ZipSplit
+
+# what you can make ...
+all:
+ @echo ''
+ @echo 'Make what? You must say what system to make Zip for--e.g.'
+ @echo '"make generic".'
+ @echo 'Choices: generic, generic_gcc, att6300nodir,'
+ @echo 'coherent, cray_v3, cygwin, lynx, minix, os390,'
+ @echo 'qnx, qnxnto, solaris, solaris_gcc'
+ @echo 'Try first "make -f unix/Makefile generic" as'
+ @echo 'it should autodetect and set the proper flags.'
+ @echo 'To make the manuals use "make zipsman" after Zip is made.'
+ @echo 'See the files INSTALL and zip.txt for more information.'
+ @echo ''
+
+list: all
+
+#MAKE = make -f unix/Makefile
+MAKEF = -f unix/Makefile
+SHELL = /bin/sh
+LN = ln -s
+
+# (to use the GNU compiler, change cc to gcc in CC)
+CC = cc
+BIND = $(CC)
+AS = $(CC) -c
+CPP = /lib/cpp
+E =
+
+# probably can change this to 'install' if you have it
+INSTALL_PROGRAM = cp
+# probably can change this to 'install -d' if you have it
+# XXX NextStep 3.3 and Openstep 4.x don't know about -p !
+INSTALL_D = mkdir -p
+CHMOD = chmod
+BINFLAGS = 755
+MANFLAGS = 644
+
+# target directories - where to install executables and man pages to
+prefix = /usr/local
+BINDIR = $(prefix)/bin
+MANEXT=1
+MANDIR = $(prefix)/man/man$(MANEXT)
+ZIPMANUAL = zip.txt
+ZIPMANUALcloak = zipcloak.txt
+ZIPMANUALnote = zipnote.txt
+ZIPMANUALsplit = zipsplit.txt
+ZIPMANUALs = zip.txt zipcloak.txt zipnote.txt zipsplit.txt
+PKGDIR = IZzip
+VERSION = Version 3.0
+
+# Our bzip2 directory
+IZ_OUR_BZIP2_DIR = bzip2
+
+# flags
+# CFLAGS flags for C compile
+# LFLAGS1 flags after output file spec, before obj file list
+# LFLAGS2 flags after obj file list (libraries, etc)
+CFLAGS_NOOPT = -I. -DUNIX $(LOCAL_ZIP)
+CFLAGS = -O2 $(CFLAGS_NOOPT)
+LFLAGS1 =
+LFLAGS2 = -s
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+ unix.o crc32.o zbz2err.o
+OBJI = deflate.o trees.o
+OBJA =
+OCRCU8 =
+OCRCTB = crc32_.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o unix_.o $(OCRCU8)
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) $(OCRCTB) crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h unix/osdep.h
+
+# suffix rules
+.SUFFIXES:
+.SUFFIXES: _.o .o .c .doc .1
+.c_.o:
+ $(CC) -c $(CFLAGS) -DUTIL -o $@ $<
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+.1.doc:
+ nroff -man $< | col -bx | uniq > $@
+
+# rules for zip, zipnote, zipcloak, zipsplit, and the Zip MANUALs.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o zipup.o zipfile.o fileio.o crc32.o crypt.o: crc32.h
+zipcloak.o zipfile_.o fileio_.o crc32_.o crypt_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: unix/zipup.h
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(AS) _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+crc_i386.o: crc_i386.S
+ $(CPP) crc_i386.S > _crc_i386.s
+ $(AS) _crc_i386.s
+ mv _crc_i386.o crc_i386.o
+ rm -f _crc_i386.s
+
+unix.o: unix/unix.c
+ $(CC) -c $(CFLAGS) unix/unix.c
+
+unix_.o: unix/unix.c
+ $(CC) -c $(CFLAGS) -DUTIL -o $@ unix/unix.c
+
+ZIPS = zip$E zipcloak$E zipnote$E zipsplit$E
+
+zips: $(ZIPS)
+zipsman: $(ZIPS) $(ZIPMANUALs)
+
+zip$E: $(OBJZ) $(OBJI) $(OBJA) $(LIB_BZ)
+ $(BIND) -o zip$E $(LFLAGS1) $(OBJZ) $(OBJI) $(OBJA) $(LFLAGS2)
+zipnote$E: $(OBJN)
+ $(BIND) -o zipnote$E $(LFLAGS1) $(OBJN) $(LFLAGS2)
+zipcloak$E: $(OBJC) $(OCRCTB)
+ $(BIND) -o zipcloak$E $(LFLAGS1) $(OBJC) $(LFLAGS2)
+zipsplit$E: $(OBJS)
+ $(BIND) -o zipsplit$E $(LFLAGS1) $(OBJS) $(LFLAGS2)
+
+$(ZIPMANUAL): man/zip.1
+ nroff -man man/zip.1 | col -bx | uniq > $(ZIPMANUAL)
+
+$(ZIPMANUALcloak): man/zipcloak.1
+ nroff -man man/zipcloak.1 | col -bx | uniq > $(ZIPMANUALcloak)
+
+$(ZIPMANUALnote): man/zipnote.1
+ nroff -man man/zipnote.1 | col -bx | uniq > $(ZIPMANUALnote)
+
+$(ZIPMANUALsplit): man/zipsplit.1
+ nroff -man man/zipsplit.1 | col -bx | uniq > $(ZIPMANUALsplit)
+
+
+# bzip2 object library
+
+$(IZ_OUR_BZIP2_DIR)/libbz2.a : $(IZ_OUR_BZIP2_DIR)/Makefile
+ @echo "Building bzip2 object library..."
+ ( cd $(IZ_OUR_BZIP2_DIR); \
+ $(MAKE) CC="$(CC_BZ)" CFLAGS="$(CFLAGS_BZ)" libbz2.a )
+ @echo " bzip2 object library created."
+
+
+# install
+install: $(ZIPS)
+ -$(INSTALL_D) $(BINDIR)
+ $(INSTALL_PROGRAM) $(ZIPS) $(BINDIR)
+ -cd $(BINDIR); $(CHMOD) $(BINFLAGS) $(ZIPS)
+ -$(INSTALL_D) $(MANDIR)
+ $(INSTALL_PROGRAM) man/zip.1 $(MANDIR)/zip.$(MANEXT)
+ $(CHMOD) $(MANFLAGS) $(MANDIR)/zip.$(MANEXT)
+ $(INSTALL_PROGRAM) man/zipcloak.1 $(MANDIR)/zipcloak.$(MANEXT)
+ $(CHMOD) $(MANFLAGS) $(MANDIR)/zipcloak.$(MANEXT)
+ $(INSTALL_PROGRAM) man/zipnote.1 $(MANDIR)/zipnote.$(MANEXT)
+ $(CHMOD) $(MANFLAGS) $(MANDIR)/zipnote.$(MANEXT)
+ $(INSTALL_PROGRAM) man/zipsplit.1 $(MANDIR)/zipsplit.$(MANEXT)
+ $(CHMOD) $(MANFLAGS) $(MANDIR)/zipsplit.$(MANEXT)
+
+uninstall:
+ -cd $(BINDIR); rm -f $(ZIPS)
+ -cd $(MANDIR); rm -f \
+ zip.$(MANEXT) zipcloak.$(MANEXT) zipnote.$(MANEXT) zipsplit.$(MANEXT)
+
+
+flags: unix/configure
+ sh unix/configure "${CC}" "${CFLAGS_NOOPT}" "${IZ_BZIP2}"
+
+# These symbols, when #defined using -D have these effects on compilation:
+# ZMEM - includes C language versions of memset(), memcpy(),
+# and memcmp() (util.c).
+# HAVE_DIRENT_H - use <dirent.h> instead of <sys/dir.h>
+# NODIR - for 3B1, which has neither getdents() nor opendir().
+# HAVE_NDIR_H - use <ndir.h> (unix/unix.c).
+# HAVE_SYS_DIR_H - use <sys/dir.h>
+# HAVE_SYS_NDIR_H - use <sys/ndir.h>
+# UTIL - select routines for utilities (note, cloak, split)
+# NO_RMDIR - remove directories using a system("rmdir ...") call.
+# NO_PROTO - cannot handle ANSI prototypes
+# NO_CONST - cannot handle ANSI const
+# NO_LARGE_FILE_SUPPORT - do not enable Large File support even if available.
+# NO_ZIP64_SUPPORT - do not enable Zip64 archive support even if available.
+# NO_UNICODE_SUPPORT - do not enable Unicode support even if available.
+# NO_BZIP2_SUPPORT - do not compile in bzip2 code even if available.
+
+# Generic targets:
+
+generic: flags
+ eval $(MAKE) $(MAKEF) zips `cat flags`
+
+generic_gcc:
+ $(MAKE) $(MAKEF) generic CC=gcc CPP="gcc -E"
+
+# AT&T 6300 PLUS (don't know yet how to allocate 64K bytes):
+att6300nodir:
+ $(MAKE) $(MAKEF) zips LFLAGS1="-Ml -s" \
+ CFLAGS="-DUNIX -I. -O -Ml -DNO_RMDIR -DDYN_ALLOC -DMEDIUM_MEM \
+-DWSIZE=16384 -DNO_STDLIB_H -DNO_STDDEF_H -DNO_RENAME \
+-DNO_MKTIME -DNO_SIZE_T -DNO_VOID -DNO_PROTO -DNO_DIR \
+-DNO_CONST -DHAVE_TERMIO_H" \
+ "LFLAGS2="
+
+# Coherent (AS definition not needed for gcc)
+coherent:
+ $(MAKE) $(MAKEF) zips CFLAGS="-DUNIX -I. -O -DDIRENT -DASMV" \
+ AS="as -gx" OBJA=match.o
+
+# Cray Unicos 6.1, Standard C compiler 3.0 (all routines except trees.c
+# may be compiled with vector3; internal compiler bug in 3.0.2.3 and
+# earlier requires vector2 for trees.c)
+cray_v3:
+ $(MAKE) $(MAKEF) zips CC="scc" \
+ CFLAGS="-DUNIX -I. -O -h vector2 -h scalar3 -DHAVE_DIRENT_H"
+
+# Cygwin
+cygwin:
+ $(MAKE) $(MAKEF) generic CC="gcc" CPP="gcc -E" EXE=".exe"
+
+# LynxOS
+lynx:
+ $(MAKE) $(MAKEF) generic CC=gcc CPP="gcc -E" CFLAGS="$(CFLAGS) \
+ -DNO_UNDERLINE -DLynx -DLYNX LFLAGS2="$LFLAGS2 -lc_p"
+
+# MINIX 1.5.10 with Bruce Evans 386 patches and gcc/GNU make
+minix:
+ $(MAKE) $(MAKEF) zips CFLAGS="-DUNIX -I. -O -DDIRENT -DMINIX" CC=gcc
+ chmem =262144 zip
+
+# IBM OS/390 (formerly MVS) compiled under "OpenEdition" shell
+# You can make the zip executable with IBM's make, but you will
+# get errors dealing with the _.o targets for the other executables
+# (zipcloak, etc). GNU make will build all the executables.
+# If you have GNU make in your path as gmake, you can uncomment
+# the following, but it shouldn't be needed:
+#MAKE = gmake
+
+os390:
+ $(MAKE) $(MAKEF) zips CFLAGS="$(CF) -I. -DUNIX -DOS390 -DEBCDIC \
+ -DSYSV -DNO_PARAM_H" LFLAGS2=""
+
+# QNX is "special" because out /bin/sh is ksh and it doesn't grok the
+# configure script properly, generating a bad flags file. D'oh! [cjh]
+#
+# QNX/Neutrino is "special" because you don't have any native development
+# tools yet. Set ARCH to "x86", "ppcbe", "ppcle", "mipsbe", or "mipsle"
+# to produce x86, PowerPC (big- or little-endian) and MIPS (big-
+# or little-endian) using gcc. [cjh]
+qnx:
+ $(MAKE) $(MAKEF) zips LN=ln CC=cc CFLAGS="-DUNIX -I. -O \
+ -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -DNO_MKTEMP"
+
+qnxnto:
+ @if [ "$(ARCH)" = "" ] ; then \
+ echo "You didn't set ARCH; I'll assume you meant ARCH=x86..." ; \
+ echo "" ; \
+ $(MAKE) $(MAKEF) zips LN=ln CC="qcc -Vgcc_ntox86" \
+ CFLAGS="-g -DUNIX -I. -O -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -DNO_MKTEMP" \
+ LFLAGS2=-g ; \
+ else \
+ echo "Making zip for $(ARCH)..." ; \
+ echo "" ; \
+ $(MAKE) $(MAKEF) zips LN=ln CC="qcc -Vgcc_nto$(ARCH)" \
+ CFLAGS="-g -DUNIX -I. -O -DHAVE_DIRENT_H -DHAVE_TERMIOS_H -DNO_MKTEMP" \
+ LFLAGS2=-g ; \
+ fi
+
+# Solaris: Generic, plus generation of installable package.
+solaris: generic svr4package
+
+# Solaris with GCC: generic_gcc, plus generation of installable package
+solaris_gcc: generic_gcc svr4package
+
+# Package generation interface (by JBush). Originally tested under Sun Solaris.
+# Other SVr4s may be very similar, and could possibly use this.
+# Note: Expects version info to be stored in VERSION macro variable.
+# See "README" under ./unix/Packaging
+svr4package:
+ @echo "Creating SVR4 package for Unix ..."
+ -@rm -rf ./$(PKGDIR) ./$(PKGDIR)_`uname -p`.pkg
+ -@sed -e "s/.VERSION./$(VERSION)/g" \
+ -e "s/.PSTAMP./$(LOGNAME)_`date | tr ' ' '_'`/g" \
+ -e "s/.ARCH./Solaris_`uname -rp | tr ' ' ','`/g" \
+ ./unix/Packaging/pkginfo.in > ./unix/Packaging/pkginfo
+ -@sed -e "s/.ARCH./`uname -p`/g" \
+ ./unix/Packaging/preinstall.in > ./unix/Packaging/preinstall
+ /usr/bin/pkgmk -d . -b . -r . -f ./unix/Packaging/prototype $(PKGDIR)
+ /usr/bin/pkgtrans -o -s . $(PKGDIR)_`uname -p`.pkg $(PKGDIR)
+ @echo " "
+ @echo "To install, copy $(PKGDIR)_`uname -p`.pkg to the target system, and"
+ @echo "issue the command (as root): pkgadd -d $(PKGDIR)_`uname -p`.pkg"
+ @echo " "
+
+# make a distribution
+dist: $(ZIPMANUAL)
+ eval zip -r9 zip`sed -e '/VERSION/!d' -e 's/.*"\(.*\)".*/\1/' \
+ -e 's/[.]//g' -e 's/ .*//g' -e q revision.h` *
+
+# clean up after making stuff and installing it
+clean:
+ rm -f *.o $(ZIPS) flags
+ rm -rf $(PKGDIR)
+
+clean_bzip2 :
+ @if test -f "$(IZ_OUR_BZIP2_DIR)/Makefile"; then \
+ ( cd $(IZ_OUR_BZIP2_DIR); make clean ); \
+ else \
+ if test -z "$(IZ_OUR_BZIP2_DIR)"; then \
+ echo "No bzip2 directory (\"IZ_OUR_BZIP2_DIR\") specified."; \
+ else \
+ echo "No bzip2 make file found: $(IZ_OUR_BZIP2_DIR)/Makefile."; \
+ fi; \
+ fi
+
+clean_exe :
+ rm -f $(ZIPS)
+#
diff --git a/unix/Packaging/README b/unix/Packaging/README
new file mode 100644
index 0000000..6b2a451
--- /dev/null
+++ b/unix/Packaging/README
@@ -0,0 +1,44 @@
+Solaris packaging
+-----------------
+
+To generate a Solaris package for Info-ZIP zip utilities,
+first see the top level INSTALL and README files. Do a
+"make solaris", which will automatically build two Solaris
+installable package files for the package, IZzip.
+
+ IZzip -- Solaris installable package in directory format.
+ IZzip_$(arch).pkg -- Solaris installable package in "stream" format.
+
+ Where: $(arch) := system architecture, currently i386, sparc, or ppc.
+ (use "uname -p" to determine)
+
+The ".pkg" file is a single file datastream that can be compressed
+and/or ftp'd. This is the recommended form, because all required
+files are resident in the archive, and it is easily distributed.
+
+To install, simply:
+
+ 1) copy the package to the target system's /tmp directory.
+ 2) login or su to root
+ 3) pkgadd -d /tmp/IZzip_$(arch).pkg
+ 4) add /opt/Info-ZIP/IZzip/bin to PATH
+ 5) add /opt/Info-ZIP/IZzip/man to MANPATH
+
+This works for both SPARC and x86.
+
+Ongoing maintenance:
+
+ Keep the files, "prototype" and "pkginfo.in" up to date.
+ Observe variable substitutions made by "Makefile".
+ See manpages for pkginfo(1), pkginfo(4), pkgmk(1), pkgproto(1)
+
+Variations:
+
+ If you wish the base directory to be set to something other than
+ /opt/Info-ZIP, change the setting BASEDIR in pkginfo.in and
+ re-run the make.
+
+
+-John Bush (John.Bush@East.Sun.COM)
+ July 20, 1996
+
diff --git a/unix/Packaging/pkginfo.in b/unix/Packaging/pkginfo.in
new file mode 100644
index 0000000..c31395d
--- /dev/null
+++ b/unix/Packaging/pkginfo.in
@@ -0,0 +1,13 @@
+PKG=IZzip
+NAME=Info-ZIP Zip Utilities
+CATEGORY=application
+VENDOR=Info-ZIP
+EMAIL=http://info-zip.org/zip-bug.html
+HOTLINE=http://info-zip.org/zip-bug.html
+DESC=Copyrighted FREEWARE. See README, WHERE, and docs in pkg's doc dir.
+CLASSES=none
+BASEDIR=/opt/Info-ZIP
+#BASEDIR=/usr/local
+VERSION=".VERSION."
+PSTAMP=".PSTAMP."
+ARCH=".ARCH."
diff --git a/unix/Packaging/postinstall b/unix/Packaging/postinstall
new file mode 100644
index 0000000..086ec26
--- /dev/null
+++ b/unix/Packaging/postinstall
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Info-ZIP Zip post-installation script.
+#
+# Last revised: 2007-09-29 SMS. Zip 3.0.
+#
+# Post installation script (simply inform installer about PATH etc)
+#
+echo ''
+echo 'Installation is complete. Users should adjust their environment'
+echo 'variables to include these directories:'
+echo " PATH: ${BASEDIR}/${PKG}/bin"
+echo " MANPATH: ${BASEDIR}/${PKG}/man"
+echo ''
+echo "Commands like the following may be added to a user's shell start-up"
+echo 'file (.cshrc, .login, .profile, ...) to do this:'
+echo ''
+echo ' For a Bourne-like shell:'
+echo " PATH=\"\${PATH}:${BASEDIR}/${PKG}/bin\""
+echo " MANPATH=\"\${MANPATH}:${BASEDIR}/${PKG}/man\""
+echo ' export PATH MANPATH'
+echo ''
+echo ' For a C shell:'
+echo " setenv PATH \"\${PATH}:${BASEDIR}/${PKG}/bin\""
+echo " setenv MANPATH \"\${MANPATH}:${BASEDIR}/${PKG}/man\""
+echo ''
+echo "See the files under ${BASEDIR}/${PKG}/doc for more information."
+echo ''
+exit 0
diff --git a/unix/Packaging/preinstall.in b/unix/Packaging/preinstall.in
new file mode 100644
index 0000000..de1961b
--- /dev/null
+++ b/unix/Packaging/preinstall.in
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Info-ZIP Zip pre-installation script.
+#
+# Last revised: 2007-09-29 SMS. Zip 3.0.
+#
+# pkgadd should set a good PATH, but just in case, ...
+PATH="/sbin:/usr/bin:${PATH}"
+export PATH
+echo ''
+echo 'Please report problems to Info-ZIP using:'
+echo ''
+echo ' http://info-zip.org/zip-bug.html'
+echo ''
+arch=`uname -p`
+if [ "arch_${arch}" != "arch_.ARCH." ]; then
+ echo "This product MUST be installed on a Solaris \".ARCH.\" system."
+ echo "This system appears to have \"${arch}\" architecture, not \".ARCH.\"."
+ echo "Please install the version for the \".ARCH.\" architecture."
+ echo 'Aborting installation...'
+ returncode=1
+else
+ echo "Installing on \".ARCH.\" architecture..."
+ returncode=0
+fi
+echo ''
+sleep 4
+exit ${returncode:-1}
+#
diff --git a/unix/Packaging/prototype b/unix/Packaging/prototype
new file mode 100644
index 0000000..002eaf6
--- /dev/null
+++ b/unix/Packaging/prototype
@@ -0,0 +1,29 @@
+d none $BASEDIR 0755 root bin
+d none $PKG 0755 root bin
+d none $PKG/doc 0755 root bin
+f none $PKG/doc/BUGS=BUGS 0644 root bin
+f none $PKG/doc/CHANGES=CHANGES 0644 root bin
+f none $PKG/doc/INSTALL=INSTALL 0644 root bin
+f none $PKG/doc/LICENSE=LICENSE 0644 root bin
+f none $PKG/doc/README=README 0644 root bin
+f none $PKG/doc/TODO=TODO 0644 root bin
+f none $PKG/doc/USexport.msg=USexport.msg 0644 root bin
+f none $PKG/doc/WHATSNEW=WHATSNEW 0644 root bin
+f none $PKG/doc/WHERE=WHERE 0644 root bin
+f none $PKG/doc/zip.txt=zip.txt 0644 root bin
+d none $PKG/man 0755 root bin
+d none $PKG/man/man1 0755 root bin
+f none $PKG/man/man1/zip.1=man/zip.1 0644 root bin
+f none $PKG/man/man1/zipcloak.1=man/zipcloak.1 0644 root bin
+f none $PKG/man/man1/zipnote.1=man/zipnote.1 0644 root bin
+f none $PKG/man/man1/zipsplit.1=man/zipsplit.1 0644 root bin
+d none $PKG/bin 0755 root bin
+f none $PKG/bin/zip=zip 0755 root bin
+f none $PKG/bin/zipcloak=zipcloak 0755 root bin
+f none $PKG/bin/zipnote=zipnote 0755 root bin
+f none $PKG/bin/zipsplit=zipsplit 0755 root bin
+i README
+i pkginfo
+i prototype
+i preinstall
+i postinstall
diff --git a/unix/README.OS390 b/unix/README.OS390
new file mode 100644
index 0000000..6fef92b
--- /dev/null
+++ b/unix/README.OS390
@@ -0,0 +1,85 @@
+
+OS/390 is IBM's follow-on to MVS and includes a POSIX, XOPEN,
+XPG4, build environment, a Unix-style filesystem (called HFS), and
+a POSIX (Born) shell. This port uses this environment and is a fairly
+straight-forward port of ZIP's Unix port - but uses the existing EBCDIC
+code. This port does not work with non-HFS (traditional MVS)
+filesystems.
+
+I believe all my changes are isolated with #ifdef's.
+
+Here's some text which might be useful for an OS390 README or
+the manual.
+
+ZIP for OS390 HFS datasets
+--------------------------
+Allows you to create ZIP archives from the OS/390 OpenEdition
+command prompt. This port uses standard Unix-style I/O routines
+and only works with HFS files.
+
+Usage
+-----
+By default, ZIP does not perform character-set translation, but has
+options to make it easy to convert text files to be compatible with
+other systems
+ zip zipfile list # add the files in 'list' to archive 'zipfile'
+ zip -a zipfile list # same as above, but translate files to ASCII
+ zip -al zipfile list # same as above, translate linefeeds to DOS style
+ zip -all zipfile list # same as '-a', translate linefeeds to UNIX style
+
+Build process
+-------------
+Assuming GNU make is available in your path and is called "gmake" (See
+the notes on Makefile changes below) and a C compiler is available as
+"cc", then type
+ gmake -f unix/Makefile MAKE=gmake os390
+
+If GNU make is not available, the existing makefile can create zip, but will
+error on the other executable (zipsplit, zipcloak, zipnote) if you type
+ make -f unix/Makefile os390
+
+Overview of Changes
+-------------------
+The OS/390 port is treated as a variant of the Unix port. EBCDIC support
+was already implemented for CMS/MVS-batch ports. The specific changes I
+made are summarized below.
+
+unix/Makefile - zip uses a unusual _.o target which IBM's make can't handle.
+Since the Makefile has a macro called MAKE that is used for a recursive
+call to make, I changed the MACRO to call "gmake" - GNU's make - which
+can handle the _.o target. If you don't have GNU make, you can
+workaround by manually applying symlinks from whatever.c to whatever_.c.
+Alternatively, the whatever_.o files could be explicitely added for os390.
+
+I added an os390 target with appropriate defines.
+
+zipup.c - added code (#ifdef OS390) to convert test to ASCII if -a flag
+was set.
+
+zip.c - changed logic which always used DOS-style newlines when -a was
+set to be consistent with other port (DOS newlines if -l option)
+
+zipfile.c - miscellaneous changes to force storing file names and
+descriptions in ASCII in the zip directory. This makes zip files
+portable across all platforms. This in turn meant names did not
+need to be translated when displaying messages.
+
+zip.h - strtoasc was missing a closing parenthesis.
+
+ebcdic.h - changed translation table to be consistent with current IBM
+recommendations - exact same changes to ebcdic.h as in my unzip port.
+
+tailor.h - define huge/far/near to be empty
+
+unix/unix.c - substantial changes to deal with mode flags. Under
+the current XOPEN standards, some of the traditional unix file mode
+bits need not be in fixed locations, but standard access macros must be
+available to access the values. The old unix.c code just picked up these
+values and saved them as-is where unzip interpreted them. Existing
+Unix system provided the macros for XOPEN compliance, but left the flags
+in their traditional locations. OS/390 has a brand new filesystem which
+is XOPEN compliant without revealing the positions of these flags.
+To create the bitmask in the same format unzip expects, the macros are
+tested one-by-one to set the appropriate bits. This same logic should
+work on any XOPEN system, but takes more instructions (I did test this
+logic on Linux).
diff --git a/unix/configure b/unix/configure
new file mode 100644
index 0000000..73ba803
--- /dev/null
+++ b/unix/configure
@@ -0,0 +1,695 @@
+:
+#!/bin/sh -x
+# The above : is necessary on some buggy systems.
+
+# configure: Guess values for system-dependent variables
+# Output the flag definitions to the file "flags".
+#
+# Parameters: $1 = $CC, $2 = $CFLAGS, $3 = $IZ_BZIP2
+#
+# This file is typically called from Makefile rather than executed
+# from the command line.
+#
+# To construct zip automatically using this file, type
+# "make -f unix/Makefile generic".
+# If this fails, then type "make list" to get a list of special targets.
+
+trap "rm -f conftest* core a.out; exit 1" 1 2 3 15
+
+CC=${1-cc}
+CFLAGS=${2-"-I. -DUNIX"}
+LFLAGS1=''
+LFLAGS2=''
+LN="ln -s"
+
+CFLAGS_OPT=''
+
+# bzip2
+IZ_BZIP2=${3-}
+CFLAGS_BZ=''
+
+
+echo 'Check C compiler type (optimization options)'
+# Sun C?
+cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __SUNPRO_C
+ bad code
+#endif
+ return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+if test $? -eq 0; then
+ CFLAGS_OPT='-xO3'
+ echo " Sun C ($CFLAGS_OPT)"
+else
+ # Tru64 DEC/Compaq/HP C?
+ cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __DECC
+ bad code
+#endif
+ return 0;
+}
+_EOF_
+ $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+ if test $? -eq 0; then
+ CFLAGS_OPT='-O3'
+ echo " DEC C ($CFLAGS_OPT)"
+ else
+ # HP-UX HP C?
+ cat > conftest.c << _EOF_
+int main()
+{
+#ifdef __GNUC__
+ bad code
+#endif
+#ifndef __hpux
+ bad code
+#endif
+ return 0;
+}
+_EOF_
+ $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+ if test $? -eq 0; then
+ # HP-UX, not GCC. Lame bundled or real ANSI compiler?
+ CFLAGS_OPT_TRY="+O3 +Onolimit"
+ $CC $CFLAGS $CFLAGS_OPT_TRY -c conftest.c 2>&1 | \
+ grep '(Bundled)' > /dev/null
+ if test $? -ne 0; then
+ CFLAGS_OPT="$CFLAGS_OPT_TRY"
+ echo " HP-UX ANSI C ($CFLAGS_OPT)"
+ else
+ echo ' HP-UX Bundled C (no opt)'
+ fi
+ else
+ # GNU C?
+ cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __GNUC__
+ bad code
+#endif
+ return 0;
+}
+_EOF_
+ $CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+ if test $? -eq 0; then
+ CFLAGS_OPT='-O3'
+ echo " GNU C ($CFLAGS_OPT)"
+ # Special Mac OS X shared library "ld" option?
+ if test ` uname -s 2> /dev/null ` = 'Darwin'; then
+ lf='-Wl,-search_paths_first'
+ $CC $CFLAGS $lf conftest.c > /dev/null 2>/dev/null
+ if test $? -eq 0; then
+ LFLAGS2="${LFLAGS2} ${lf}"
+ fi
+ rm -f conftest
+ fi
+ else
+ CFLAGS_OPT='-O'
+ echo " Other-unknown C ($CFLAGS_OPT)"
+ fi
+ fi
+ fi
+fi
+
+# optimization flags
+if test -n "${CFLAGS_OPT}"; then
+ CFLAGS="${CFLAGS} ${CFLAGS_OPT}"
+ CFLAGS_BZ="${CFLAGS_BZ} ${CFLAGS_OPT}"
+fi
+
+
+# bzip2
+
+echo "Check bzip2 support"
+CC_BZ="${CC}"
+LIB_BZ=''
+if test -n "${IZ_BZIP2}"; then
+ echo " Check for bzip2 compiled library in IZ_BZIP2 (${IZ_BZIP2})"
+ if test -f "${IZ_BZIP2}/libbz2.a"; then
+#
+# A bzip2 library built with BZ_NO_STDIO should have an
+# unresolved external, "bz_internal_error". The default,
+# full-function library will not mention it.
+#
+ nm ${IZ_BZIP2}/libbz2.a | grep bz_internal_error > /dev/null
+ if test $? -eq 0; then
+ echo " Found bzip2 BZ_NO_STDIO library, ${IZ_BZIP2}/libbz2.a"
+ else
+ echo " Found bzip2 library, ${IZ_BZIP2}/libbz2.a,"
+ echo " but library not compiled with BZ_NO_STDIO"
+ echo " WARNING: We recommend using a bzip2 library compiled"
+ echo " with BZ_NO_STDIO defined for proper error handling"
+ echo " Please see the Zip installation instructions in bzip2/install.txt"
+ echo " Continuing anyway with standard bzip2 library..."
+ fi
+ if test -f "${IZ_BZIP2}/bzlib.h"; then
+ CFLAGS="${CFLAGS} -I${IZ_BZIP2} -DBZIP2_SUPPORT"
+ LFLAGS2="${LFLAGS2} -L${IZ_BZIP2} -lbz2"
+ echo "-- Found bzip2 library - linking in bzip2"
+ else
+ echo " ${IZ_BZIP2}/bzlib.h not found"
+ echo "-- Since IZ_BZIP2 defined, skipping OS and bzip2 dir checks - no bzip2"
+ fi
+ else
+ echo " ${IZ_BZIP2}/libbz2.a not found"
+ echo "-- Since IZ_BZIP2 defined, skipping OS and bzip2 checks - no bzip2"
+ fi
+else
+ echo " Check for bzip2 in bzip2 directory"
+ IZ_BZIP2=bzip2
+ if test -f "${IZ_BZIP2}/libbz2.a"; then
+ nm ${IZ_BZIP2}/libbz2.a | grep bz_internal_error > /dev/null
+ if test $? -eq 0; then
+ echo " Found bzip2 BZ_NO_STDIO library in bzip2 directory"
+ else
+ echo " Found bzip2 library in bzip2 directory,"
+ echo " but not built with the BZ_NO_STDIO option"
+ echo " WARNING: We recommend using a bzip2 library compiled"
+ echo " with BZ_NO_STDIO defined for proper error handling"
+ echo " Please see the Zip installation instructions"
+ echo " Continuing anyway with standard bzip2 library..."
+ fi
+ fi
+ if test -f "bzip2/bzlib.h" -a -f "bzip2/libbz2.a"; then
+ CFLAGS="${CFLAGS} -I${IZ_BZIP2} -DBZIP2_SUPPORT"
+ LFLAGS2="${LFLAGS2} -Lbzip2 -lbz2"
+ echo "-- Found bzip2 library - linking in bzip2"
+ else
+ if test -f "bzip2/bzlib.c" -a -f "bzip2/bzlib.h"; then
+ echo "-- No library, but found bzip2 source in bzip2 directory"
+ echo "-- Will try to build bzip2 library from source and link in"
+#
+# Arrange to build a BZ_NO_STDIO bzip2 object library using the
+# same compiler and optimization options as used for Zip, and
+# to compile and link Zip with bzip2.
+#
+ CFLAGS_BZ="${CFLAGS_BZ} -DBZ_NO_STDIO"
+ LIB_BZ="bzip2/libbz2.a"
+ CFLAGS="${CFLAGS} -Ibzip2 -DBZIP2_SUPPORT"
+ LFLAGS2="${LFLAGS2} -Lbzip2 -lbz2"
+ else
+ echo " Check if OS already has bzip2 library installed"
+ cat > conftest.c << _EOF_
+#include "bzlib.h"
+int main()
+{
+ bz_stream strm;
+ BZ2_bzCompressEnd(&strm);
+ return 0;
+}
+_EOF_
+ $CC $CFLAGS -o conftest conftest.c -lbz2 > /dev/null 2>/dev/null
+ if test $? -eq 0; then
+ echo "-- OS supports bzip2 - linking in bzip2"
+ CFLAGS="${CFLAGS} -DBZIP2_SUPPORT"
+ LFLAGS2="${LFLAGS2} -lbz2"
+ else
+ echo "-- Either bzlib.h or libbz2.a not found - no bzip2"
+ fi
+ fi
+ fi
+fi
+
+
+echo Check for the C preprocessor
+# on SVR4, cc -E does not produce correct assembler files. Need /lib/cpp.
+CPP="${CC} -E"
+# solaris as(1) needs -P, maybe others as well ?
+[ -f /usr/ccs/lib/cpp ] && CPP="/usr/ccs/lib/cpp -P"
+[ -f /usr/lib/cpp ] && CPP=/usr/lib/cpp
+[ -f /lib/cpp ] && CPP=/lib/cpp
+[ -f /usr/bin/cpp ] && CPP=/usr/bin/cpp
+[ -f /xenix ] && CPP="${CC} -E"
+[ -f /lynx.os ] && CPP="${CC} -E"
+
+echo "#include <stdio.h>" > conftest.c
+$CPP conftest.c >/dev/null 2>/dev/null || CPP="${CC} -E"
+
+
+echo Check if we can use asm code
+OBJA=""
+OCRCU8=""
+if eval "$CPP match.S > _match.s 2>/dev/null"; then
+ if test ! -s _match.s || grep error < _match.s > /dev/null; then
+ :
+ elif eval "$CC -c _match.s >/dev/null 2>/dev/null" && [ -f _match.o ]; then
+ CFLAGS="${CFLAGS} -DASMV"
+ OBJA="match.o"
+ echo "int foo() { return 0;}" > conftest.c
+ $CC -c conftest.c >/dev/null 2>/dev/null
+ echo Check if compiler generates underlines
+ nm conftest.o | grep "(^|[^_])foo" >/dev/null 2>/dev/null
+ [ $? -eq 0 ] && CPP="${CPP} -DNO_UNDERLINE"
+ if eval "$CPP crc_i386.S > _crc_i386.s 2>/dev/null"; then
+ if eval "$CC -c _crc_i386.s >/dev/null 2>/dev/null" && [ -f _crc_i386.o ]
+ then
+ OBJA="$OBJA crc_i386.o"
+ OCRCU8="crc_i386.o"
+ CFLAGS="${CFLAGS} -DASM_CRC"
+ fi
+ fi
+ fi
+fi
+rm -f _match.s _match.o _crc_i386.s _crc_i386.o
+
+
+# ANSI options for compilers that don't have __STDC__ defined by default
+# Currently HPUX, pyramid, Dynix, AIX, OSF/1 and ultrix
+
+echo Check for ANSI options
+cat > conftest.c << _EOF_
+int main()
+{
+#ifndef __STDC__
+ forget it
+#endif
+ return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+ for OPT in -Ae -Xa -qlanglvl=ansi -std1 -std
+ do
+ $CC $CFLAGS $OPT -c conftest.c > /dev/null 2>/dev/null
+ [ $? -eq 0 ] && CFLAGS="${CFLAGS} ${OPT}" && break
+ done
+fi
+
+
+echo Check for prototypes
+echo "int main(int argc, char *argv[]) { return 0; }" > conftest.c
+$CC $CFLAGS -c conftest.c > /dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_PROTO"
+
+# const check currently handles mips cc and non ANSI compilers.
+# does it need more ?
+echo Check the handling of const
+cat > conftest.c << _EOF_
+typedef int charset[2];
+int main()
+{
+ const charset x;
+ const char *foo;
+ return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_CONST"
+
+
+echo Check for time_t
+cat > conftest.c << _EOF_
+#include <sys/types.h>
+#include <time.h>
+int main()
+{
+ time_t t;
+ return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_TIME_T"
+
+
+echo Check for size_t
+cat > conftest.c << _EOF_
+#include <sys/types.h>
+int main()
+{
+ size_t s;
+ return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_SIZE_T"
+
+
+echo Check for off_t
+cat > conftest.c << _EOF_
+#include <sys/types.h>
+int main()
+{
+ off_t s;
+ return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_OFF_T"
+
+
+echo Check size of UIDs and GIDs
+echo "(Now zip stores variable size UIDs/GIDs using a new extra field. This"
+echo " tests if this OS uses 16-bit UIDs/GIDs and so if the old 16-bit storage"
+echo " should also be used for backward compatibility.)"
+# Added 2008-04-15 CS
+cat > conftest.c << _EOF_
+# define _LARGEFILE_SOURCE /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */
+# define _LARGE_FILES /* some OSes need this for 64-bit off_t */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+int main()
+{
+ struct stat s;
+
+ printf(" s.st_uid is %u bytes\n", sizeof(s.st_uid));
+ printf(" s.st_gid is %u bytes\n", sizeof(s.st_gid));
+
+ /* see if have 16-bit UID */
+ if (sizeof(s.st_uid) != 2) {
+ return 1;
+ }
+ /* see if have 16-bit GID */
+ if (sizeof(s.st_gid) != 2) {
+ return 2;
+ }
+ return 3;
+}
+_EOF_
+# compile it
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+ echo -- UID/GID test failed on compile - disabling old 16-bit UID/GID support
+ CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+else
+# run it
+ ./conftest
+ r=$?
+ if [ $r -eq 1 ]; then
+ echo -- UID not 2 bytes - disabling old 16-bit UID/GID support
+ CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+ elif [ $r -eq 2 ]; then
+ echo -- GID not 2 bytes - disabling old 16-bit UID/GID support
+ CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+ elif [ $r -eq 3 ]; then
+ echo -- 16-bit UIDs and GIDs - keeping old 16-bit UID/GID support
+ else
+ echo -- test failed - conftest returned $r - disabling old 16-bit UID/GID support
+ CFLAGS="${CFLAGS} -DUIDGID_NOT_16BIT"
+ fi
+fi
+
+
+# Now we set the 64-bit file environment and check the size of off_t
+# Added 11/4/2003 EG
+# Revised 8/12/2004 EG
+
+echo Check for Large File Support
+cat > conftest.c << _EOF_
+# define _LARGEFILE_SOURCE /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */
+# define _LARGE_FILES /* some OSes need this for 64-bit off_t */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+int main()
+{
+ off_t offset;
+ struct stat s;
+ /* see if have 64-bit off_t */
+ if (sizeof(offset) < 8)
+ return 1;
+ printf(" off_t is %d bytes\n", sizeof(off_t));
+ /* see if have 64-bit stat */
+ if (sizeof(s.st_size) < 8) {
+ printf(" s.st_size is %d bytes\n", sizeof(s.st_size));
+ return 2;
+ }
+ return 3;
+}
+_EOF_
+# compile it
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+ echo -- no Large File Support
+else
+# run it
+ ./conftest
+ r=$?
+ if [ $r -eq 1 ]; then
+ echo -- no Large File Support - no 64-bit off_t
+ elif [ $r -eq 2 ]; then
+ echo -- no Large File Support - no 64-bit stat
+ elif [ $r -eq 3 ]; then
+ echo -- yes we have Large File Support!
+ CFLAGS="${CFLAGS} -DLARGE_FILE_SUPPORT"
+ else
+ echo -- no Large File Support - conftest returned $r
+ fi
+fi
+
+
+# Check for wide char for Unicode support
+# Added 11/24/2005 EG
+
+echo Check for wide char support
+cat > conftest.c << _EOF_
+#include <stdlib.h>
+#include <stdio.h>
+int main()
+{
+ int wsize;
+ wchar_t *wide_string;
+
+ if ((wide_string = (wchar_t *)malloc(4 * sizeof(wchar_t))) == NULL) {
+ return 0;
+ }
+ /* get wide string */
+ wsize = mbstowcs(wide_string, "foo", 3);
+ wide_string[wsize] = (wchar_t) NULL;
+ return 1;
+}
+_EOF_
+# compile it
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+# OCRCU8 is used by all utilities if Unicode is enabled
+# OCRCTB is only used by zipcloak
+if [ $? -ne 0 ]; then
+ echo -- no Unicode support
+ OCRCU8=""
+ OCRCTB="crc32_.o"
+else
+# have wide char support
+ echo -- have wchar_t - enabling Unicode support
+ CFLAGS="${CFLAGS} -DUNICODE_SUPPORT"
+ OCRCU8="crc32_.o ${OCRCU8}"
+ OCRCTB=""
+fi
+
+
+# from configure 2.4i (Onno) 12/5/04
+
+echo Check for gcc no-builtin flag
+# -fno-builtin since version 2
+cat > conftest.c << _EOF_
+int main()
+{
+#if __GNUC__ >= 2
+ return 0;
+#else
+ forget it
+#endif
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -eq 0 ] && BFLAG="-fno-builtin"
+
+
+# Check for missing functions
+# add NO_'function_name' to flags if missing
+
+for func in rmdir strchr strrchr rename mktemp mktime mkstemp
+do
+ echo Check for $func
+ echo "int main(){ $func(); return 0; }" > conftest.c
+ $CC $BFLAG -o conftest conftest.c >/dev/null 2>/dev/null
+ [ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_`echo $func | tr '[a-z]' '[A-Z]'`"
+done
+
+
+echo Check for memset
+echo "int main(){ char k; memset(&k,0,0); return 0; }" > conftest.c
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DZMEM"
+
+
+echo Check for memmove
+cat > conftest.c << _EOF_
+#include <string.h>
+int main() { int a; int b = 0; memmove( &a, &b, sizeof( a)); return a; }
+_EOF_
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNEED_MEMMOVE"
+
+
+echo Check for strerror
+cat > conftest.c << _EOF_
+#include <string.h>
+int main() { strerror( 0); return 0; }
+_EOF_
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNEED_STRERROR"
+
+echo Check for errno declaration
+cat > conftest.c << _EOF_
+#include <errno.h>
+main()
+{
+ errno = 0;
+ return 0;
+}
+_EOF_
+$CC $CFLAGS -c conftest.c >/dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_ERRNO"
+
+
+echo Check for directory libraries
+cat > conftest.c << _EOF_
+int main() { return closedir(opendir(".")); }
+_EOF_
+
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+ OPT=""
+ for lib in ndir dir ucb bsd BSD PW x dirent
+ do
+ $CC -o conftest conftest.c -l$lib >/dev/null 2>/dev/null
+ [ $? -eq 0 ] && OPT=-l$lib && break
+ done
+ if [ ${OPT} ]; then
+ LFLAGS2="${LFLAGS2} ${OPT}"
+ else
+ CFLAGS="${CFLAGS} -DNO_DIR"
+ fi
+fi
+
+
+# Dynix/ptx 1.3 needed this
+
+echo Check for readlink
+echo "int main(){ return readlink(); }" > conftest.c
+$CC -o conftest conftest.c >/dev/null 2>/dev/null
+if [ $? -ne 0 ]; then
+ $CC -o conftest conftest.c -lseq >/dev/null 2>/dev/null
+ [ $? -eq 0 ] && LFLAGS2="${LFLAGS2} -lseq"
+fi
+
+
+echo Check for directory include file
+OPT=""
+for inc in dirent.h sys/ndir.h ndir.h sys/dir.h
+do
+ echo "#include <$inc>" > conftest.c
+ $CPP conftest.c > /dev/null 2>/dev/null
+ [ $? -eq 0 ] && OPT="-DHAVE_`echo $inc | tr '[a-z]./' '[A-Z]__'`" && break
+done
+CFLAGS="${CFLAGS} ${OPT}"
+
+
+echo Check for nonexistent include files
+for inc in stdlib.h stddef.h unistd.h fcntl.h string.h
+do
+ echo "#include <$inc>" > conftest.c
+ $CPP conftest.c >/dev/null 2>/dev/null
+ [ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_`echo $inc | tr '[a-z]./' '[A-Z]__'`"
+done
+
+
+echo Check for term I/O include file
+OPT=""
+for inc in termios.h termio.h sgtty.h
+do
+ echo "#include <$inc>" > conftest.c
+ $CPP conftest.c > /dev/null 2>/dev/null
+ [ $? -eq 0 ] && OPT="-DHAVE_`echo $inc | tr '[a-z]./' '[A-Z]__'`" && break
+done
+CFLAGS="${CFLAGS} ${OPT}"
+
+
+# needed for AIX (and others ?) when mmap is used
+
+echo Check for valloc
+cat > conftest.c << _EOF_
+main()
+{
+#ifdef MMAP
+ valloc();
+#endif
+}
+_EOF_
+$CC ${CFLAGS} -c conftest.c > /dev/null 2>/dev/null
+[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DNO_VALLOC"
+
+
+echo Check for /usr/local/bin and /usr/local/man
+BINDIR=$HOME/bin
+[ -d /usr/local/bin ] && BINDIR=/usr/local/bin
+
+MANDIR=manl
+[ -d /usr/man/manl ] && MANDIR=/usr/man/manl
+[ -d /usr/local/man/manl ] && MANDIR=/usr/local/man/manl
+[ -d /usr/local/man/man1 ] && MANDIR=/usr/local/man/man1
+
+
+echo Check for OS-specific flags
+if [ -f /usr/bin/hostinfo ]; then
+ if /usr/bin/hostinfo | grep NeXT > /dev/null; then
+ CFLAGS="${CFLAGS} -posix"
+ LFLAGS1="${LFLAGS1} -posix -object"
+ fi
+# XXX ATT6300, Cray
+elif [ -f /xenix ]; then
+ if uname -p | grep 286 > /dev/null; then
+ CFLAGS="${CFLAGS} -LARGE -Mel2 -DMEDIUM_MEM -DWSIZE=16384 -DNO_VOID"
+ LFLAGS1="${LFLAGS1} -LARGE -Mel2"
+ fi
+elif uname -X >/dev/null 2>/dev/null; then
+# SCO shared library check
+ echo "int main() { return 0;}" > conftest.c
+ $CC -o conftest conftest.c -lc_s -nointl >/dev/null 2> /dev/null
+ [ $? -eq 0 ] && LFLAGS2="-lc_s -nointl"
+else
+ SYSTEM=`uname -s 2>/dev/null` || SYSTEM="unknown"
+ echo "int main() { return 0;}" > conftest.c
+ case $SYSTEM in
+ OSF1|ULTRIX)
+ echo Check for -Olimit option
+ $CC ${CFLAGS} -Olimit 1000 -o conftest conftest.c >/dev/null 2>/dev/null
+ [ $? -eq 0 ] && CFLAGS="${CFLAGS} -Olimit 1000"
+ ;;
+### HP-UX)
+### echo Check for +Onolimit option
+### $CC ${CFLAGS} +Onolimit -o conftest conftest.c >/dev/null 2>/dev/null
+### [ $? -eq 0 ] && CFLAGS="${CFLAGS} +Onolimit"
+### ;;
+### SunOS)
+### CFLAGS="${CFLAGS} -D_FILE_OFFSET_BITS=64"
+### ;;
+ esac
+fi
+
+
+echo Check for symbolic links
+ln -s /dev/null null > /dev/null 2>/dev/null || LN=ln
+
+
+rm -f a.out conftest.c conftest.o conftest null
+
+echo CC=\"${CC}\" CFLAGS=\"${CFLAGS}\" CPP=\"${CPP}\" OBJA=\"${OBJA}\" \
+ OCRCU8=\"${OCRCU8}\" OCRCTB=\"${OCRCTB}\" \
+ BINDIR=${BINDIR} MANDIR=${MANDIR} LFLAGS1=\"${LFLAGS1}\" \
+ LFLAGS2=\"${LFLAGS2}\" LN=\"${LN}\" \
+ CC_BZ=\"${CC_BZ}\" CFLAGS_BZ=\"${CFLAGS_BZ}\" \
+ IZ_BZIP2=\"${IZ_BZIP2}\" LIB_BZ=\"${LIB_BZ}\" > flags
+
diff --git a/unix/osdep.h b/unix/osdep.h
new file mode 100644
index 0000000..10f8ee9
--- /dev/null
+++ b/unix/osdep.h
@@ -0,0 +1,80 @@
+/*
+ unix/osdep.h - Zip 3
+
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#ifdef NO_LARGE_FILE_SUPPORT
+# ifdef LARGE_FILE_SUPPORT
+# undef LARGE_FILE_SUPPORT
+# endif
+#endif
+
+#ifdef LARGE_FILE_SUPPORT
+ /* 64-bit Large File Support */
+
+ /* The following Large File Summit (LFS) defines turn on large file support on
+ Linux (probably 2.4 or later kernel) and many other unixen */
+
+# define _LARGEFILE_SOURCE /* some OSes need this for fseeko */
+# define _LARGEFILE64_SOURCE
+# define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */
+# define _LARGE_FILES /* some OSes need this for 64-bit off_t */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* printf format size prefix for zoff_t values */
+#ifdef LARGE_FILE_SUPPORT
+# define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+#else
+# define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+#endif
+
+#ifdef NO_OFF_T
+ typedef long zoff_t;
+ typedef unsigned long uzoff_t;
+#else
+ typedef off_t zoff_t;
+# if defined(LARGE_FILE_SUPPORT) && !(defined(__alpha) && defined(__osf__))
+ typedef unsigned long long uzoff_t;
+# else
+ typedef unsigned long uzoff_t;
+# endif
+#endif
+ typedef struct stat z_stat;
+
+
+/* Automatically set ZIP64_SUPPORT if LFS */
+
+#ifdef LARGE_FILE_SUPPORT
+# ifndef NO_ZIP64_SUPPORT
+# ifndef ZIP64_SUPPORT
+# define ZIP64_SUPPORT
+# endif
+# else
+# ifdef ZIP64_SUPPORT
+# undef ZIP64_SUPPORT
+# endif
+# endif
+#endif
+
+
+/* Process files in binary mode */
+#if defined(__DJGPP__) || defined(__CYGWIN__)
+# define FOPR "rb"
+# define FOPM "r+b"
+# define FOPW "wb"
+#endif
+
+
+/* Enable the "UT" extra field (time info) */
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+# define USE_EF_UT_TIME
+#endif
diff --git a/unix/unix.c b/unix/unix.c
new file mode 100644
index 0000000..f4d655d
--- /dev/null
+++ b/unix/unix.c
@@ -0,0 +1,1100 @@
+/*
+ unix/unix.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#ifndef UTIL /* the companion #endif is a bit of ways down ... */
+
+#include <time.h>
+
+#if defined(MINIX) || defined(__mpexl)
+# ifdef S_IWRITE
+# undef S_IWRITE
+# endif /* S_IWRITE */
+# define S_IWRITE S_IWUSR
+#endif /* MINIX */
+
+#if (!defined(S_IWRITE) && defined(S_IWUSR))
+# define S_IWRITE S_IWUSR
+#endif
+
+#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
+# include <dirent.h>
+#else /* !HAVE_DIRENT_H */
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+# ifndef dirent
+# define dirent direct
+# endif
+#endif /* HAVE_DIRENT_H || _POSIX_VERSION */
+
+#define PAD 0
+#define PATH_END '/'
+
+/* Library functions not in (most) header files */
+
+#ifdef _POSIX_VERSION
+# include <utime.h>
+#else
+ int utime OF((char *, time_t *));
+#endif
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+
+#ifdef NO_DIR /* for AT&T 3B1 */
+#include <sys/dir.h>
+#ifndef dirent
+# define dirent direct
+#endif
+typedef FILE DIR;
+/*
+** Apparently originally by Rich Salz.
+** Cleaned up and modified by James W. Birdsall.
+*/
+
+#define opendir(path) fopen(path, "r")
+
+struct dirent *readdir(dirp)
+DIR *dirp;
+{
+ static struct dirent entry;
+
+ if (dirp == NULL)
+ return NULL;
+ for (;;)
+ if (fread (&entry, sizeof (struct dirent), 1, dirp) == 0)
+ return NULL;
+ else if (entry.d_ino)
+ return (&entry);
+} /* end of readdir() */
+
+#define closedir(dirp) fclose(dirp)
+#endif /* NO_DIR */
+
+
+local char *readd(d)
+DIR *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct dirent *e;
+
+ e = readdir(d);
+ return e == NULL ? (char *) NULL : e->d_name;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ z_stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+#ifdef OS390
+ if (S_ISREG(s.st_mode) || S_ISLNK(s.st_mode))
+#else
+# ifdef S_IFLNK
+ if ((s.st_mode & S_IFREG) == S_IFREG || (s.st_mode & S_IFLNK) == S_IFLNK)
+# else
+ if ((s.st_mode & S_IFREG) == S_IFREG)
+# endif
+#endif
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ }
+#ifdef OS390
+ else if (S_ISDIR(s.st_mode))
+#else
+ else if ((s.st_mode & S_IFDIR) == S_IFDIR)
+#endif
+ {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) */
+#ifdef OS390
+ else if (S_ISFIFO(s.st_mode))
+#else
+ else if ((s.st_mode & S_IFIFO) == S_IFIFO)
+#endif
+ {
+ if (allow_fifo) {
+ /* FIFO (Named Pipe) - handle as normal file */
+ /* add or remove name of FIFO */
+ /* zip will stop if FIFO is open and wait for pipe to be fed and closed */
+ if (noisy) zipwarn("Reading FIFO (Named Pipe): ", n);
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ zipwarn("ignoring FIFO (Named Pipe) - use -FI to read: ", n);
+ return ZE_OK;
+ }
+ } /* S_IFIFO */
+ else
+ zipwarn("ignoring special file: ", n);
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t = NULL; /* shortened name */
+ int dosflag;
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ /* Strip "//host/share/" part of a UNC name */
+ if (!strncmp(x,"//",2) && (x[2] != '\0' && x[2] != '/')) {
+ n = x + 2;
+ while (*n != '\0' && *n != '/')
+ n++; /* strip host name */
+ if (*n != '\0') {
+ n++;
+ while (*n != '\0' && *n != '/')
+ n++; /* strip `share' name */
+ }
+ if (*n != '\0')
+ t = n + 1;
+ } else
+ t = x;
+ while (*t == '/')
+ t++; /* strip leading '/' chars to get a relative path */
+ while (*t == '.' && t[1] == '/')
+ t += 2; /* strip redundant leading "./" sections */
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+
+#ifdef EBCDIC
+ strtoasc(n, n); /* here because msname() needs native coding */
+#endif
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+
+ if (isdir) return n; /* avoid warning on unused variable */
+ return n;
+}
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+#ifdef EBCDIC
+ strtoebc(x, n);
+#else
+ strcpy(x, n);
+#endif
+ return x;
+}
+
+/*
+ * XXX use ztimbuf in both POSIX and non POSIX cases ?
+ */
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#ifdef _POSIX_VERSION
+ struct utimbuf u; /* argument for utime() const ?? */
+#else
+ time_t u[2]; /* argument for utime() */
+#endif
+
+ /* Convert DOS time to time_t format in u */
+#ifdef _POSIX_VERSION
+ u.actime = u.modtime = dos2unixtime(d);
+ utime(f, &u);
+#else
+ u[0] = u[1] = dos2unixtime(d);
+ utime(f, u);
+#endif
+
+}
+
+ulg filetime(f, a, n, t)
+ char *f; /* name of file to get info on */
+ ulg *a; /* return value: file attributes */
+ zoff_t *n; /* return value: file size */
+ iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ z_stat s; /* results of stat() */
+ /* converted to pointer from using FNMAX - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (strcmp(f, "-") == 0) {
+ if (zfstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ }
+ else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+#ifndef OS390
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+#else
+/*
+** The following defines are copied from the unizip source and represent the
+** legacy Unix mode flags. These fixed bit masks are no longer required
+** by XOPEN standards - the S_IS### macros being the new recommended method.
+** The approach here of setting the legacy flags by testing the macros should
+** work under any _XOPEN_SOURCE environment (and will just rebuild the same bit
+** mask), but is required if the legacy bit flags differ from legacy Unix.
+*/
+#define UNX_IFDIR 0040000 /* Unix directory */
+#define UNX_IFREG 0100000 /* Unix regular file */
+#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */
+#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */
+#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */
+#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */
+#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */
+ {
+ mode_t legacy_modes;
+
+ /* Initialize with permission bits--which are not implementation-optional */
+ legacy_modes = s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
+ if (S_ISDIR(s.st_mode))
+ legacy_modes |= UNX_IFDIR;
+ if (S_ISREG(s.st_mode))
+ legacy_modes |= UNX_IFREG;
+ if (S_ISLNK(s.st_mode))
+ legacy_modes |= UNX_IFLNK;
+ if (S_ISBLK(s.st_mode))
+ legacy_modes |= UNX_IFBLK;
+ if (S_ISCHR(s.st_mode))
+ legacy_modes |= UNX_IFCHR;
+ if (S_ISFIFO(s.st_mode))
+ legacy_modes |= UNX_IFIFO;
+ if (S_ISSOCK(s.st_mode))
+ legacy_modes |= UNX_IFSOCK;
+ *a = ((ulg)legacy_modes << 16) | !(s.st_mode & S_IWRITE);
+ }
+#endif
+ if ((s.st_mode & S_IFMT) == S_IFDIR) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = t->mtime; /* best guess, (s.st_ctime: last status change!!) */
+ }
+ return unix2dostime(&s.st_mtime);
+}
+
+
+#ifndef QLZIP /* QLZIP Unix2QDOS cross-Zip supplies an extended variant */
+
+int set_new_unix_extra_field(z, s)
+ struct zlist far *z;
+ z_stat *s;
+ /* New unix extra field.
+ Currently only UIDs and GIDs are stored. */
+{
+ int uid_size;
+ int gid_size;
+ int ef_data_size;
+ char *extra;
+ char *cextra;
+ ulg id;
+ int b;
+
+ uid_size = sizeof(s->st_uid);
+ gid_size = sizeof(s->st_gid);
+
+/* New extra field
+ tag (2 bytes)
+ size (2 bytes)
+ version (1 byte)
+ uid_size (1 byte - size in bytes)
+ uid (variable)
+ gid_size (1 byte - size in bytes)
+ gid (variable)
+ */
+
+ ef_data_size = 1 + 1 + uid_size + 1 + gid_size;
+
+ if ((extra = (char *)malloc(z->ext + 4 + ef_data_size)) == NULL)
+ return ZE_MEM;
+ if ((cextra = (char *)malloc(z->ext + 4 + ef_data_size)) == NULL)
+ return ZE_MEM;
+
+ if (z->ext)
+ memcpy(extra, z->extra, z->ext);
+ if (z->cext)
+ memcpy(cextra, z->cextra, z->cext);
+
+ free(z->extra);
+ z->extra = extra;
+ free(z->cextra);
+ z->cextra = cextra;
+
+ z->extra[z->ext + 0] = 'u';
+ z->extra[z->ext + 1] = 'x';
+ z->extra[z->ext + 2] = (char)ef_data_size; /* length of data part */
+ z->extra[z->ext + 3] = 0;
+ z->extra[z->ext + 4] = 1; /* version */
+
+ /* UID */
+ z->extra[z->ext + 5] = (char)(uid_size); /* uid size in bytes */
+ b = 6;
+ id = (ulg)(s->st_uid);
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ if (uid_size > 1) {
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ if (uid_size > 2) {
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ if (uid_size == 8) {
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ }
+ }
+ }
+
+ /* GID */
+ b++;
+ z->extra[z->ext + b] = (char)(gid_size); /* gid size in bytes */
+ b++;
+ id = (ulg)(s->st_gid);
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ if (gid_size > 1) {
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ if (gid_size > 2) {
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ if (gid_size == 8) {
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ b++;
+ id = id >> 8;
+ z->extra[z->ext + b] = (char)(id & 0xFF);
+ }
+ }
+ }
+
+ /* copy local extra field to central directory extra field */
+ memcpy((z->cextra) + z->cext, (z->extra) + z->ext, 4 + ef_data_size);
+
+ z->ext = z->ext + 4 + ef_data_size;
+ z->cext = z->cext + 4 + ef_data_size;
+
+ return ZE_OK;
+}
+
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* store full data in local header but just modification time stamp info
+ in central header */
+{
+ z_stat s;
+ char *name;
+ int len = strlen(z->name);
+
+ /* For the full sized UT local field including the UID/GID fields, we
+ * have to stat the file again. */
+
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "set_extra_field");
+ }
+ strcpy(name, z->name);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (LSSTAT(name, &s)) {
+ free(name);
+ return ZE_OPEN;
+ }
+ free(name);
+
+#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+
+/* The flag UIDGID_NOT_16BIT should be set by the pre-compile configuration
+ script when it detects st_uid or st_gid sizes differing from 16-bit.
+ */
+#ifndef UIDGID_NOT_16BIT
+ /* The following "second-level" check for st_uid and st_gid members being
+ 16-bit wide is only added as a safety precaution in case the "first-level"
+ check failed to define the UIDGID_NOT_16BIT symbol.
+ The first-level check should have been implemented in the automatic
+ compile configuration process.
+ */
+# ifdef UIDGID_ARE_16B
+# undef UIDGID_ARE_16B
+# endif
+ /* The following expression is a compile-time constant and should (hopefully)
+ get optimized away by any sufficiently intelligent compiler!
+ */
+# define UIDGID_ARE_16B (sizeof(s.st_uid) == 2 && sizeof(s.st_gid) == 2)
+
+# define EB_L_UX2_SIZE (EB_HEADSIZE + EB_UX2_MINLEN)
+# define EB_C_UX2_SIZE EB_HEADSIZE
+# define EF_L_UNIX_SIZE (EB_L_UT_SIZE + (UIDGID_ARE_16B ? EB_L_UX2_SIZE : 0))
+# define EF_C_UNIX_SIZE (EB_C_UT_SIZE + (UIDGID_ARE_16B ? EB_C_UX2_SIZE : 0))
+#else
+# define EF_L_UNIX_SIZE EB_L_UT_SIZE
+# define EF_C_UNIX_SIZE EB_C_UT_SIZE
+#endif /* !UIDGID_NOT_16BIT */
+
+ if ((z->extra = (char *)malloc(EF_L_UNIX_SIZE)) == NULL)
+ return ZE_MEM;
+ if ((z->cextra = (char *)malloc(EF_C_UNIX_SIZE)) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = (char)EB_UT_LEN(2); /* length of data part of local e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME; /* st_ctime != creation */
+ z->extra[5] = (char)(s.st_mtime);
+ z->extra[6] = (char)(s.st_mtime >> 8);
+ z->extra[7] = (char)(s.st_mtime >> 16);
+ z->extra[8] = (char)(s.st_mtime >> 24);
+ z->extra[9] = (char)(s.st_atime);
+ z->extra[10] = (char)(s.st_atime >> 8);
+ z->extra[11] = (char)(s.st_atime >> 16);
+ z->extra[12] = (char)(s.st_atime >> 24);
+
+#ifndef UIDGID_NOT_16BIT
+ /* Only store the UID and GID in the old Ux extra field if the runtime
+ system provides them in 16-bit wide variables. */
+ if (UIDGID_ARE_16B) {
+ z->extra[13] = 'U';
+ z->extra[14] = 'x';
+ z->extra[15] = (char)EB_UX2_MINLEN; /* length of data part of local e.f. */
+ z->extra[16] = 0;
+ z->extra[17] = (char)(s.st_uid);
+ z->extra[18] = (char)(s.st_uid >> 8);
+ z->extra[19] = (char)(s.st_gid);
+ z->extra[20] = (char)(s.st_gid >> 8);
+ }
+#endif /* !UIDGID_NOT_16BIT */
+
+ z->ext = EF_L_UNIX_SIZE;
+
+ memcpy(z->cextra, z->extra, EB_C_UT_SIZE);
+ z->cextra[EB_LEN] = (char)EB_UT_LEN(1);
+#ifndef UIDGID_NOT_16BIT
+ if (UIDGID_ARE_16B) {
+ /* Copy header of Ux extra field from local to central */
+ memcpy(z->cextra+EB_C_UT_SIZE, z->extra+EB_L_UT_SIZE, EB_C_UX2_SIZE);
+ z->cextra[EB_LEN+EB_C_UT_SIZE] = 0;
+ }
+#endif
+ z->cext = EF_C_UNIX_SIZE;
+
+#if 0 /* UID/GID presence is now signaled by central EF_IZUNIX2 field ! */
+ /* lower-middle external-attribute byte (unused until now):
+ * high bit => (have GMT mod/acc times) >>> NO LONGER USED! <<<
+ * second-high bit => have Unix UID/GID info
+ * NOTE: The high bit was NEVER used in any official Info-ZIP release,
+ * but its future use should be avoided (if possible), since it
+ * was used as "GMT mod/acc times local extra field" flags in Zip beta
+ * versions 2.0j up to 2.0v, for about 1.5 years.
+ */
+ z->atx |= 0x4000;
+#endif /* never */
+
+ /* new unix extra field */
+ set_new_unix_extra_field(z, &s);
+
+ return ZE_OK;
+}
+
+#endif /* !QLZIP */
+
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+# ifdef NO_RMDIR
+ /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
+ int r, len;
+ char *s; /* malloc'd string for system command */
+
+ len = strlen(d);
+ if ((s = malloc(len + 34)) == NULL)
+ return 127;
+
+ sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
+ r = system(s);
+ free(s);
+ return r;
+# else /* !NO_RMDIR */
+ return rmdir(d);
+# endif /* ?NO_RMDIR */
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__386BSD__) || \
+ defined(__OpenBSD__) || defined(__bsdi__)
+#include <sys/param.h> /* for the BSD define */
+/* if we have something newer than NET/2 we'll use uname(3) */
+#if (BSD > 199103)
+#include <sys/utsname.h>
+#endif /* BSD > 199103 */
+#endif /* __{Net,Free,Open,386}BSD__ || __bsdi__ */
+
+void version_local()
+{
+#ifdef __GNUC__
+# ifdef NX_CURRENT_COMPILER_RELEASE
+ char compiler_name[80];
+# endif
+#else
+# if (defined( __SUNPRO_C))
+ char compiler_name[33];
+# else
+# if (defined( __HP_cc) || defined( __IBMC__))
+ char compiler_name[33];
+# else
+# if (defined( __DECC_VER))
+ char compiler_name[33];
+ int compiler_typ;
+# else
+# if ((defined(CRAY) || defined(cray)) && defined(_RELEASE))
+ char compiler_name[40];
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifdef BSD
+# if (BSD > 199103)
+ struct utsname u;
+ char os_name[40];
+# else
+# if defined(__NETBSD__))
+ static ZCONST char *netbsd[] = { "_ALPHA", "", "A", "B" };
+ char os_name[40];
+# endif /* __NETBSD__ */
+# endif /* BSD > 199103 */
+#else /* !BSD */
+#if ((defined(CRAY) || defined(cray)) && defined(_UNICOS))
+ char os_name[40];
+#endif /* (CRAY && defined(_UNICOS)) */
+#endif /* ?BSD */
+
+/* Define the compiler name and version string */
+#ifdef __GNUC__
+# ifdef NX_CURRENT_COMPILER_RELEASE
+ sprintf(compiler_name, "NeXT DevKit %d.%02d (gcc " __VERSION__ ")",
+ NX_CURRENT_COMPILER_RELEASE/100, NX_CURRENT_COMPILER_RELEASE%100);
+# define COMPILER_NAME compiler_name
+# else
+# define COMPILER_NAME "gcc " __VERSION__
+# endif
+#else /* !__GNUC__ */
+# if defined(__SUNPRO_C)
+ sprintf( compiler_name, "Sun C version %x", __SUNPRO_C);
+# define COMPILER_NAME compiler_name
+# else
+# if (defined( __HP_cc))
+ if ((__HP_cc% 100) == 0)
+ {
+ sprintf( compiler_name, "HP C version A.%02d.%02d",
+ (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100));
+ }
+ else
+ {
+ sprintf( compiler_name, "HP C version A.%02d.%02d.%02d",
+ (__HP_cc/ 10000), ((__HP_cc% 10000)/ 100), (__HP_cc% 100));
+ }
+# define COMPILER_NAME compiler_name
+# else
+# if (defined( __DECC_VER))
+ sprintf( compiler_name, "DEC C version %c%d.%d-%03d",
+ ((compiler_typ = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
+ (compiler_typ == 8 ? 'S' : 'V')),
+ __DECC_VER / 10000000,
+ (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000);
+# define COMPILER_NAME compiler_name
+# else
+# if ((defined(CRAY) || defined(cray)) && defined(_RELEASE))
+ sprintf(compiler_name, "cc version %d", _RELEASE);
+# define COMPILER_NAME compiler_name
+# else
+# ifdef __IBMC__
+ sprintf( compiler_name, "IBM C version %d.%d.%d",
+ (__IBMC__/ 100), ((__IBMC__/ 10)% 10), (__IBMC__% 10));
+# define COMPILER_NAME compiler_name
+# else
+# ifdef __VERSION__
+# define COMPILER_NAME "cc " __VERSION__
+# else
+# define COMPILER_NAME "cc "
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif /* ?__GNUC__ */
+
+
+/* Define the name to use for the OS we're compiling on */
+#if defined(sgi) || defined(__sgi)
+# define OS_NAME "Silicon Graphics IRIX"
+#else
+#ifdef sun
+# ifdef sparc
+# ifdef __SVR4
+# define OS_NAME "Sun SPARC/Solaris"
+# else /* may or may not be SunOS */
+# define OS_NAME "Sun SPARC"
+# endif
+# else
+# if defined(sun386) || defined(i386)
+# define OS_NAME "Sun 386i"
+# else
+# if defined(mc68020) || defined(__mc68020__)
+# define OS_NAME "Sun 3"
+# else /* mc68010 or mc68000: Sun 2 or earlier */
+# define OS_NAME "Sun 2"
+# endif
+# endif
+# endif
+#else
+#ifdef __hpux
+# define OS_NAME "HP-UX"
+#else
+#ifdef __osf__
+# define OS_NAME "DEC OSF/1"
+#else
+#ifdef _AIX
+# define OS_NAME "IBM AIX"
+#else
+#ifdef aiws
+# define OS_NAME "IBM RT/AIX"
+#else
+#if defined(CRAY) || defined(cray)
+# ifdef _UNICOS
+ sprintf(os_name, "Cray UNICOS release %d", _UNICOS);
+# define OS_NAME os_name
+# else
+# define OS_NAME "Cray UNICOS"
+# endif
+#else
+#if defined(uts) || defined(UTS)
+# define OS_NAME "Amdahl UTS"
+#else
+#ifdef NeXT
+# ifdef mc68000
+# define OS_NAME "NeXTStep/black"
+# else
+# define OS_NAME "NeXTStep for Intel"
+# endif
+#else
+#if defined(linux) || defined(__linux__)
+# ifdef __ELF__
+# define OS_NAME "Linux ELF"
+# else
+# define OS_NAME "Linux a.out"
+# endif
+#else
+#ifdef MINIX
+# define OS_NAME "Minix"
+#else
+#ifdef M_UNIX
+# define OS_NAME "SCO Unix"
+#else
+#ifdef M_XENIX
+# define OS_NAME "SCO Xenix"
+#else
+#ifdef BSD
+# if (BSD > 199103)
+# define OS_NAME os_name
+ uname(&u);
+ sprintf(os_name, "%s %s", u.sysname, u.release);
+# else
+# ifdef __NetBSD__
+# define OS_NAME os_name
+# ifdef NetBSD0_8
+ sprintf(os_name, "NetBSD 0.8%s", netbsd[NetBSD0_8]);
+# else
+# ifdef NetBSD0_9
+ sprintf(os_name, "NetBSD 0.9%s", netbsd[NetBSD0_9]);
+# else
+# ifdef NetBSD1_0
+ sprintf(os_name, "NetBSD 1.0%s", netbsd[NetBSD1_0]);
+# endif /* NetBSD1_0 */
+# endif /* NetBSD0_9 */
+# endif /* NetBSD0_8 */
+# else
+# ifdef __FreeBSD__
+# define OS_NAME "FreeBSD 1.x"
+# else
+# ifdef __bsdi__
+# define OS_NAME "BSD/386 1.0"
+# else
+# ifdef __386BSD__
+# define OS_NAME "386BSD"
+# else
+# define OS_NAME "Unknown BSD"
+# endif /* __386BSD__ */
+# endif /* __bsdi__ */
+# endif /* FreeBSD */
+# endif /* NetBSD */
+# endif /* BSD > 199103 */
+#else
+#ifdef __CYGWIN__
+# define OS_NAME "Cygwin"
+#else
+#if defined(i686) || defined(__i686) || defined(__i686__)
+# define OS_NAME "Intel 686"
+#else
+#if defined(i586) || defined(__i586) || defined(__i586__)
+# define OS_NAME "Intel 586"
+#else
+#if defined(i486) || defined(__i486) || defined(__i486__)
+# define OS_NAME "Intel 486"
+#else
+#if defined(i386) || defined(__i386) || defined(__i386__)
+# define OS_NAME "Intel 386"
+#else
+#ifdef pyr
+# define OS_NAME "Pyramid"
+#else
+#if defined(ultrix) || defined(__ultrix)
+# if defined(mips) || defined(__mips)
+# define OS_NAME "DEC/MIPS"
+# else
+# if defined(vax) || defined(__vax)
+# define OS_NAME "DEC/VAX"
+# else /* __alpha? */
+# define OS_NAME "DEC/Alpha"
+# endif
+# endif
+#else
+#ifdef gould
+# define OS_NAME "Gould"
+#else
+#ifdef MTS
+# define OS_NAME "MTS"
+#else
+#ifdef __convexc__
+# define OS_NAME "Convex"
+#else
+#ifdef __QNX__
+# define OS_NAME "QNX 4"
+#else
+#ifdef __QNXNTO__
+# define OS_NAME "QNX Neutrino"
+#else
+#ifdef __APPLE__
+# ifdef __i386__
+# define OS_NAME "Mac OS X Intel"
+# else /* __i386__ */
+# ifdef __ppc__
+# define OS_NAME "Mac OS X PowerPC"
+# else /* __ppc__ */
+# ifdef __ppc64__
+# define OS_NAME "Mac OS X PowerPC64"
+# else /* __ppc64__ */
+# define OS_NAME "Mac OS X"
+# endif /* __ppc64__ */
+# endif /* __ppc__ */
+# endif /* __i386__ */
+#else
+# define OS_NAME "Unknown"
+#endif /* Apple */
+#endif /* QNX Neutrino */
+#endif /* QNX 4 */
+#endif /* Convex */
+#endif /* MTS */
+#endif /* Gould */
+#endif /* DEC */
+#endif /* Pyramid */
+#endif /* 386 */
+#endif /* 486 */
+#endif /* 586 */
+#endif /* 686 */
+#endif /* Cygwin */
+#endif /* BSD */
+#endif /* SCO Xenix */
+#endif /* SCO Unix */
+#endif /* Minix */
+#endif /* Linux */
+#endif /* NeXT */
+#endif /* Amdahl */
+#endif /* Cray */
+#endif /* RT/AIX */
+#endif /* AIX */
+#endif /* OSF/1 */
+#endif /* HP-UX */
+#endif /* Sun */
+#endif /* SGI */
+
+
+/* Define the compile date string */
+#ifdef __DATE__
+# define COMPILE_DATE " on " __DATE__
+#else
+# define COMPILE_DATE ""
+#endif
+
+ printf("Compiled with %s for Unix (%s)%s.\n\n",
+ COMPILER_NAME, OS_NAME, COMPILE_DATE);
+
+} /* end function version_local() */
+
+
+/* 2006-03-23 SMS.
+ * Emergency replacement for strerror(). (Useful on SunOS 4.*.)
+ * Enable by specifying "LOCAL_UNZIP=-DNEED_STRERROR=1" on the "make"
+ * command line.
+ */
+
+#ifdef NEED_STRERROR
+
+char *strerror( err)
+ int err;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ static char no_msg[ 64];
+
+ if ((err >= 0) && (err < sys_nerr))
+ {
+ return sys_errlist[ err];
+ }
+ else
+ {
+ sprintf( no_msg, "(no message, code = %d.)", err);
+ return no_msg;
+ }
+}
+
+#endif /* def NEED_STRERROR */
+
+
+/* 2006-03-23 SMS.
+ * Emergency replacement for memmove(). (Useful on SunOS 4.*.)
+ * Enable by specifying "LOCAL_UNZIP=-DNEED_MEMMOVE=1" on the "make"
+ * command line.
+ */
+
+#ifdef NEED_MEMMOVE
+
+/* memmove.c -- copy memory.
+ Copy LENGTH bytes from SOURCE to DEST. Does not null-terminate.
+ In the public domain.
+ By David MacKenzie <djm@gnu.ai.mit.edu>.
+ Adjusted by SMS.
+*/
+
+void *memmove(dest0, source0, length)
+ void *dest0;
+ void const *source0;
+ size_t length;
+{
+ char *dest = dest0;
+ char const *source = source0;
+ if (source < dest)
+ /* Moving from low mem to hi mem; start at end. */
+ for (source += length, dest += length; length; --length)
+ *--dest = *--source;
+ else if (source != dest)
+ {
+ /* Moving from hi mem to low mem; start at beginning. */
+ for (; length; --length)
+ *dest++ = *source++;
+ }
+ return dest0;
+}
+
+#endif /* def NEED_MEMMOVE */
diff --git a/unix/zipup.h b/unix/zipup.h
new file mode 100644
index 0000000..0fc3f89
--- /dev/null
+++ b/unix/zipup.h
@@ -0,0 +1,24 @@
+/*
+ unix/zipup.h - Zip 3
+
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..73317da
--- /dev/null
+++ b/util.c
@@ -0,0 +1,1450 @@
+/*
+ util.c
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * util.c by Mark Adler.
+ */
+#define __UTIL_C
+
+#include "zip.h"
+#include "ebcdic.h"
+#include <ctype.h>
+
+#ifdef MSDOS16
+# include <dos.h>
+#endif
+
+#ifdef NO_MKTIME
+# ifndef IZ_MKTIME_ONLY
+# define IZ_MKTIME_ONLY /* only mktime() related code is pulled in */
+# endif
+# include "timezone.c"
+#endif
+
+uch upper[256], lower[256];
+/* Country-dependent case map table */
+
+
+#ifndef UTIL /* UTIL picks out namecmp code (all utils) */
+
+/* RISC OS uses # as its single-character wildcard */
+#ifdef RISCOS
+# define WILDCHR_SINGLE '#'
+# define WILDCHR_MULTI '*'
+# define DIRSEP_CHR '.'
+#endif
+
+#ifdef VMS
+# define WILDCHR_SINGLE '%'
+# define WILDCHR_MULTI '*'
+# define DIRSEP_CHR '.'
+#endif
+
+#ifndef WILDCHR_SINGLE
+# define WILDCHR_SINGLE '?'
+#endif
+#ifndef WILDCHR_MULTI
+# define WILDCHR_MULTI '*'
+#endif
+#ifndef DIRSEP_CHR
+# define DIRSEP_CHR '/'
+#endif
+
+/* Local functions */
+local int recmatch OF((ZCONST char *, ZCONST char *, int));
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ local long recmatchw OF((ZCONST wchar_t *, ZCONST wchar_t *, int));
+#endif
+local int count_args OF((char *s));
+
+#ifdef MSDOS16
+ local unsigned ident OF((unsigned chr));
+#endif
+
+#ifndef HAVE_FSEEKABLE
+
+/* 2004-11-12 SMS.
+ Changed to use z*o() functions, and ftell() test from >= 0 to != -1.
+ This solves problems with negative 32-bit offsets, even on small-file
+ products.
+*/
+int fseekable( fp)
+FILE *fp;
+{
+ zoff_t x;
+
+ return (fp == NULL ||
+ ((zfseeko( fp, ((zoff_t) -1), SEEK_CUR) == 0) && /* Seek ok. */
+ ((x = zftello( fp)) != ((zoff_t) -1)) && /* Tell ok. */
+ (zfseeko( fp, ((zoff_t) 1), SEEK_CUR) == 0) && /* Seek ok. */
+ (zftello( fp) == x+ 1))); /* Tells agree. */
+}
+#endif /* HAVE_FSEEKABLE */
+
+
+char *isshexp(p)
+char *p; /* candidate sh expression */
+/* If p is a sh expression, a pointer to the first special character is
+ returned. Otherwise, NULL is returned. */
+{
+ for (; *p; INCSTR(p))
+ if (*p == '\\' && *(p+1))
+ p++;
+#ifdef VMS
+ else if (*p == WILDCHR_SINGLE || *p == WILDCHR_MULTI)
+#else /* !VMS */
+ else if (*p == WILDCHR_SINGLE || *p == WILDCHR_MULTI || *p == '[')
+#endif /* ?VMS */
+ return p;
+ return NULL;
+}
+
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+
+wchar_t *isshexpw(pw)
+ wchar_t *pw; /* candidate sh expression */
+/* If pw is a sh expression, a pointer to the first special character is
+ returned. Otherwise, NULL is returned. */
+{
+ for (; *pw; pw++)
+ if (*pw == (wchar_t)'\\' && *(pw+1))
+ pw++;
+ else if (*pw == (wchar_t)WILDCHR_SINGLE || *pw == (wchar_t)WILDCHR_MULTI ||
+ *pw == (wchar_t)'[')
+ return pw;
+ return NULL;
+}
+
+# endif
+#endif
+
+
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+
+local long recmatchw(pw, sw, cs)
+ZCONST wchar_t *pw; /* sh pattern to match */
+ZCONST wchar_t *sw; /* string to match it to */
+int cs; /* flag: force case-sensitive matching */
+/* Recursively compare the sh pattern p with the string s and return 1 if
+ they match, and 0 or 2 if they don't or if there is a syntax error in the
+ pattern. This routine recurses on itself no deeper than the number of
+ characters in the pattern. */
+{
+ long c; /* pattern char or start of range in [-] loop */
+ /* Get first character, the pattern for new recmatch calls follows */
+
+ c = (long)*(pw++);
+
+ /* If that was the end of the pattern, match if string empty too */
+ if (c == 0)
+ return *sw == 0;
+
+ /* '?' matches any character (but not an empty string) */
+ if ((wchar_t)c == (wchar_t)WILDCHR_SINGLE) {
+ if (wild_stop_at_dir)
+ return (*sw && *sw != (wchar_t)DIRSEP_CHR) ? recmatchw(pw, sw + 1, cs) : 0;
+ else
+ return *sw ? recmatchw(pw, sw + 1, cs) : 0;
+ }
+
+ /* WILDCHR_MULTI ('*') matches any number of characters, including zero */
+ if (!no_wild && (wchar_t)c == (wchar_t)WILDCHR_MULTI)
+ {
+ if (wild_stop_at_dir) {
+ /* Check for an immediately following WILDCHR_MULTI */
+ if (*pw != (wchar_t)WILDCHR_MULTI) {
+ /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */
+ for (; *sw && *sw != (wchar_t)DIRSEP_CHR; sw++)
+ if ((c = recmatchw(pw, sw, cs)) != 0)
+ return c;
+ /* end of pattern: matched if at end of string, else continue */
+ if (*pw == 0)
+ return (*sw == 0);
+ /* continue to match if at DIRSEP_CHR in pattern, else give up */
+ return (*pw == (wchar_t)DIRSEP_CHR || (*pw == (wchar_t)'\\' &&
+ pw[1] == (wchar_t)DIRSEP_CHR))
+ ? recmatchw(pw, sw, cs) : 2;
+ }
+ /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */
+ pw++; /* move p past the second WILDCHR_MULTI */
+ /* continue with the normal non-WILD_STOP_AT_DIR code */
+ } /* wild_stop_at_dir */
+
+ /* Not wild_stop_at_dir */
+ if (*pw == 0)
+ return 1;
+ if (!isshexpw((wchar_t *)pw))
+ {
+ /* optimization for rest of pattern being a literal string */
+
+ /* optimization to handle patterns like *.txt */
+ /* if the first char in the pattern is '*' and there */
+ /* are no other shell expression chars, i.e. a literal string */
+ /* then just compare the literal string at the end */
+
+ ZCONST wchar_t *swrest;
+
+ swrest = sw + (wcslen(sw) - wcslen(pw));
+ if (swrest - sw < 0)
+ /* remaining literal string from pattern is longer than rest of
+ test string, there can't be a match
+ */
+ return 0;
+ else
+ /* compare the remaining literal pattern string with the last bytes
+ of the test string to check for a match */
+ return ((cs ? wcscmp(pw, swrest) : _wcsicmp(pw, swrest)) == 0);
+ }
+ else
+ {
+ /* pattern contains more wildcards, continue with recursion... */
+ for (; *sw; sw++)
+ if ((c = recmatchw(pw, sw, cs)) != 0)
+ return c;
+ return 2; /* 2 means give up--shmatch will return false */
+ }
+ }
+
+ /* Parse and process the list of characters and ranges in brackets */
+ if (!no_wild && allow_regex && (wchar_t)c == '[')
+ {
+ int e; /* flag true if next char to be taken literally */
+ ZCONST wchar_t *qw; /* pointer to end of [-] group */
+ int r; /* flag true to match anything but the range */
+
+ if (*sw == 0) /* need a character to match */
+ return 0;
+ pw += (r = (*pw == (wchar_t)'!' || *pw == (wchar_t)'^')); /* see if reverse */
+ for (qw = pw, e = 0; *qw; qw++) /* find closing bracket */
+ if (e)
+ e = 0;
+ else
+ if (*qw == (wchar_t)'\\')
+ e = 1;
+ else if (*qw == (wchar_t)']')
+ break;
+ if (*qw != (wchar_t)']') /* nothing matches if bad syntax */
+ return 0;
+ for (c = 0, e = *pw == (wchar_t)'-'; pw < qw; pw++) /* go through the list */
+ {
+ if (e == 0 && *pw == (wchar_t)'\\') /* set escape flag if \ */
+ e = 1;
+ else if (e == 0 && *pw == (wchar_t)'-') /* set start of range if - */
+ c = *(pw-1);
+ else
+ {
+ wchar_t cc = (cs ? *sw : towupper(*sw));
+ wchar_t uc = (wchar_t) c;
+
+ if (*(pw+1) != (wchar_t)'-')
+ for (uc = uc ? uc : *pw; cc <= *pw; uc++)
+ /* compare range */
+ if ((cs ? uc : towupper(uc)) == cc)
+ return r ? 0 : recmatchw(qw + 1, sw + 1, cs);
+ c = e = 0; /* clear range, escape flags */
+ }
+ }
+ return r ? recmatchw(qw + 1, sw + 1, cs) : 0;
+ /* bracket match failed */
+ }
+
+ /* If escape ('\'), just compare next character */
+ if (!no_wild && (wchar_t)c == (wchar_t)'\\')
+ if ((c = *pw++) == '\0') /* if \ at end, then syntax error */
+ return 0;
+
+ /* Just a character--compare it */
+ return (cs ? (wchar_t)c == *sw : towupper((wchar_t)c) == towupper(*sw)) ?
+ recmatchw(pw, sw + 1, cs) : 0;
+}
+
+# endif
+#endif
+
+
+local int recmatch(p, s, cs)
+ZCONST char *p; /* sh pattern to match */
+ZCONST char *s; /* string to match it to */
+int cs; /* flag: force case-sensitive matching */
+/* Recursively compare the sh pattern p with the string s and return 1 if
+ they match, and 0 or 2 if they don't or if there is a syntax error in the
+ pattern. This routine recurses on itself no deeper than the number of
+ characters in the pattern. */
+{
+ int c; /* pattern char or start of range in [-] loop */
+ /* Get first character, the pattern for new recmatch calls follows */
+
+ /* This fix provided by akt@m5.dion.ne.jp for Japanese.
+ See 21 July 2006 mail.
+ It only applies when p is pointing to a doublebyte character and
+ things like / and wildcards are not doublebyte. This probably
+ should not be needed. */
+
+#ifdef _MBCS
+ if (CLEN(p) == 2) {
+ if (CLEN(s) == 2) {
+ return (*p == *s && *(p+1) == *(s+1)) ?
+ recmatch(p + 2, s + 2, cs) : 0;
+ } else {
+ return 0;
+ }
+ }
+#endif /* ?_MBCS */
+
+ c = *POSTINCSTR(p);
+
+ /* If that was the end of the pattern, match if string empty too */
+ if (c == 0)
+ return *s == 0;
+
+ /* '?' (or '%' or '#') matches any character (but not an empty string) */
+ if (c == WILDCHR_SINGLE) {
+ if (wild_stop_at_dir)
+ return (*s && *s != DIRSEP_CHR) ? recmatch(p, s + CLEN(s), cs) : 0;
+ else
+ return *s ? recmatch(p, s + CLEN(s), cs) : 0;
+ }
+
+ /* WILDCHR_MULTI ('*') matches any number of characters, including zero */
+#ifdef AMIGA
+ if (!no_wild && c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */
+ c = WILDCHR_MULTI, p++;
+#endif /* AMIGA */
+ if (!no_wild && c == WILDCHR_MULTI)
+ {
+ if (wild_stop_at_dir) {
+ /* Check for an immediately following WILDCHR_MULTI */
+# ifdef AMIGA
+ if ((c = p[0]) == '#' && p[1] == '?') /* "#?" is Amiga-ese for "*" */
+ c = WILDCHR_MULTI, p++;
+ if (c != WILDCHR_MULTI) {
+# else /* !AMIGA */
+ if (*p != WILDCHR_MULTI) {
+# endif /* ?AMIGA */
+ /* Single WILDCHR_MULTI ('*'): this doesn't match slashes */
+ for (; *s && *s != DIRSEP_CHR; INCSTR(s))
+ if ((c = recmatch(p, s, cs)) != 0)
+ return c;
+ /* end of pattern: matched if at end of string, else continue */
+ if (*p == 0)
+ return (*s == 0);
+ /* continue to match if at DIRSEP_CHR in pattern, else give up */
+ return (*p == DIRSEP_CHR || (*p == '\\' && p[1] == DIRSEP_CHR))
+ ? recmatch(p, s, cs) : 2;
+ }
+ /* Two consecutive WILDCHR_MULTI ("**"): this matches DIRSEP_CHR ('/') */
+ p++; /* move p past the second WILDCHR_MULTI */
+ /* continue with the normal non-WILD_STOP_AT_DIR code */
+ } /* wild_stop_at_dir */
+
+ /* Not wild_stop_at_dir */
+ if (*p == 0)
+ return 1;
+ if (!isshexp((char *)p))
+ {
+ /* optimization for rest of pattern being a literal string */
+
+ /* optimization to handle patterns like *.txt */
+ /* if the first char in the pattern is '*' and there */
+ /* are no other shell expression chars, i.e. a literal string */
+ /* then just compare the literal string at the end */
+
+ ZCONST char *srest;
+
+ srest = s + (strlen(s) - strlen(p));
+ if (srest - s < 0)
+ /* remaining literal string from pattern is longer than rest of
+ test string, there can't be a match
+ */
+ return 0;
+ else
+ /* compare the remaining literal pattern string with the last bytes
+ of the test string to check for a match */
+#ifdef _MBCS
+ {
+ ZCONST char *q = s;
+
+ /* MBCS-aware code must not scan backwards into a string from
+ * the end.
+ * So, we have to move forward by character from our well-known
+ * character position s in the test string until we have advanced
+ * to the srest position.
+ */
+ while (q < srest)
+ INCSTR(q);
+ /* In case the byte *srest is a trailing byte of a multibyte
+ * character, we have actually advanced past the position (srest).
+ * For this case, the match has failed!
+ */
+ if (q != srest)
+ return 0;
+ return ((cs ? strcmp(p, q) : namecmp(p, q)) == 0);
+ }
+#else /* !_MBCS */
+ return ((cs ? strcmp(p, srest) : namecmp(p, srest)) == 0);
+#endif /* ?_MBCS */
+ }
+ else
+ {
+ /* pattern contains more wildcards, continue with recursion... */
+ for (; *s; INCSTR(s))
+ if ((c = recmatch(p, s, cs)) != 0)
+ return c;
+ return 2; /* 2 means give up--shmatch will return false */
+ }
+ }
+
+#ifndef VMS /* No bracket matching in VMS */
+ /* Parse and process the list of characters and ranges in brackets */
+ if (!no_wild && allow_regex && c == '[')
+ {
+ int e; /* flag true if next char to be taken literally */
+ ZCONST char *q; /* pointer to end of [-] group */
+ int r; /* flag true to match anything but the range */
+
+ if (*s == 0) /* need a character to match */
+ return 0;
+ p += (r = (*p == '!' || *p == '^')); /* see if reverse */
+ for (q = p, e = 0; *q; q++) /* find closing bracket */
+ if (e)
+ e = 0;
+ else
+ if (*q == '\\')
+ e = 1;
+ else if (*q == ']')
+ break;
+ if (*q != ']') /* nothing matches if bad syntax */
+ return 0;
+ for (c = 0, e = *p == '-'; p < q; p++) /* go through the list */
+ {
+ if (e == 0 && *p == '\\') /* set escape flag if \ */
+ e = 1;
+ else if (e == 0 && *p == '-') /* set start of range if - */
+ c = *(p-1);
+ else
+ {
+ uch cc = (cs ? (uch)*s : case_map((uch)*s));
+ uch uc = (uch) c;
+ if (*(p+1) != '-')
+ for (uc = uc ? uc : (uch)*p; uc <= (uch)*p; uc++)
+ /* compare range */
+ if ((cs ? uc : case_map(uc)) == cc)
+ return r ? 0 : recmatch(q + CLEN(q), s + CLEN(s), cs);
+ c = e = 0; /* clear range, escape flags */
+ }
+ }
+ return r ? recmatch(q + CLEN(q), s + CLEN(s), cs) : 0;
+ /* bracket match failed */
+ }
+#endif /* !VMS */
+
+ /* If escape ('\'), just compare next character */
+ if (!no_wild && c == '\\')
+ if ((c = *p++) == '\0') /* if \ at end, then syntax error */
+ return 0;
+
+#ifdef VMS
+ /* 2005-11-06 SMS.
+ Handle "..." wildcard in p with "." or "]" in s.
+ */
+ if ((c == '.') && (*p == '.') && (*(p+ CLEN( p)) == '.') &&
+ ((*s == '.') || (*s == ']')))
+ {
+ /* Match "...]" with "]". Continue after "]" in both. */
+ if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+ return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
+
+ /* Else, look for a reduced match in s, until "]" in or end of s. */
+ for (; *s && (*s != ']'); INCSTR(s))
+ if (*s == '.')
+ /* If reduced match, then continue after "..." in p, "." in s. */
+ if ((c = recmatch( (p+ CLEN( p)), s, cs)) != 0)
+ return (int)c;
+
+ /* Match "...]" with "]". Continue after "]" in both. */
+ if ((*(p+ 2* CLEN( p)) == ']') && (*s == ']'))
+ return recmatch( (p+ 3* CLEN( p)), (s+ CLEN( s)), cs);
+
+ /* No reduced match. Quit. */
+ return 2;
+ }
+
+#endif /* def VMS */
+
+ /* Just a character--compare it */
+ return (cs ? c == *s : case_map((uch)c) == case_map((uch)*s)) ?
+ recmatch(p, s + CLEN(s), cs) : 0;
+}
+
+
+int shmatch(p, s, cs)
+ZCONST char *p; /* sh pattern to match */
+ZCONST char *s; /* string to match it to */
+int cs; /* force case-sensitive match if TRUE */
+/* Compare the sh pattern p with the string s and return true if they match,
+ false if they don't or if there is a syntax error in the pattern. */
+{
+ return recmatch(p, s, cs) == 1;
+}
+
+
+#if defined(DOS) || defined(WIN32)
+
+#ifdef UNICODE_SUPPORT
+
+int dosmatchw(pw, sw, cs)
+ZCONST wchar_t *pw; /* dos pattern to match */
+ZCONST wchar_t *sw; /* string to match it to */
+int cs; /* force case-sensitive match if TRUE */
+/* Treat filenames without periods as having an implicit trailing period */
+{
+ wchar_t *sw1; /* revised string to match */
+ int r; /* result */
+
+ if (wcschr(pw, (wchar_t)'.') && !wcschr(sw, (wchar_t)'.') &&
+ ((sw1 = (wchar_t *)malloc((wcslen(sw) + 2) * sizeof(wchar_t))) != NULL))
+ {
+ wcscpy(sw1, sw);
+ wcscat(sw1, L".");
+ }
+ else
+ {
+ /* will usually be OK */
+ sw1 = (wchar_t *)sw;
+ }
+
+ r = recmatchw(pw, sw1, cs) == 1;
+ if (sw != sw1)
+ free((zvoid *)sw1);
+ return r == 1;
+}
+
+#endif
+
+/* XXX also suitable for OS2? Atari? Human68K? TOPS-20?? */
+
+int dosmatch(p, s, cs)
+ZCONST char *p; /* dos pattern to match */
+ZCONST char *s; /* string to match it to */
+int cs; /* force case-sensitive match if TRUE */
+/* Treat filenames without periods as having an implicit trailing period */
+{
+ char *s1; /* revised string to match */
+ int r; /* result */
+
+ if (strchr(p, '.') && !strchr(s, '.') &&
+ ((s1 = malloc(strlen(s) + 2)) != NULL))
+ {
+ strcpy(s1, s);
+ strcat(s1, ".");
+ }
+ else
+ {
+ /* will usually be OK */
+ s1 = (char *)s;
+ }
+
+ r = recmatch(p, s1, cs) == 1;
+ if (s != s1)
+ free((zvoid *)s1);
+ return r == 1;
+}
+
+#endif /* DOS || WIN32 */
+
+zvoid far **search(b, a, n, cmp)
+ZCONST zvoid *b; /* pointer to value to search for */
+ZCONST zvoid far **a; /* table of pointers to values, sorted */
+extent n; /* number of pointers in a[] */
+int (*cmp) OF((ZCONST zvoid *, ZCONST zvoid far *)); /* comparison function */
+
+/* Search for b in the pointer list a[0..n-1] using the compare function
+ cmp(b, c) where c is an element of a[i] and cmp() returns negative if
+ *b < *c, zero if *b == *c, or positive if *b > *c. If *b is found,
+ search returns a pointer to the entry in a[], else search() returns
+ NULL. The nature and size of *b and *c (they can be different) are
+ left up to the cmp() function. A binary search is used, and it is
+ assumed that the list is sorted in ascending order. */
+{
+ ZCONST zvoid far **i; /* pointer to midpoint of current range */
+ ZCONST zvoid far **l; /* pointer to lower end of current range */
+ int r; /* result of (*cmp)() call */
+ ZCONST zvoid far **u; /* pointer to upper end of current range */
+
+ l = (ZCONST zvoid far **)a; u = l + (n-1);
+ while (u >= l) {
+ i = l + ((unsigned)(u - l) >> 1);
+ if ((r = (*cmp)(b, (ZCONST char far *)*(struct zlist far **)i)) < 0)
+ u = i - 1;
+ else if (r > 0)
+ l = i + 1;
+ else
+ return (zvoid far **)i;
+ }
+ return NULL; /* If b were in list, it would belong at l */
+}
+
+#endif /* !UTIL */
+
+#ifdef MSDOS16
+
+local unsigned ident(unsigned chr)
+{
+ return chr; /* in al */
+}
+
+void init_upper()
+{
+ static struct country {
+ uch ignore[18];
+ int (far *casemap)(int);
+ uch filler[16];
+ } country_info;
+
+ struct country far *info = &country_info;
+ union REGS regs;
+ struct SREGS sregs;
+ unsigned int c;
+
+ regs.x.ax = 0x3800; /* get country info */
+ regs.x.dx = FP_OFF(info);
+ sregs.ds = FP_SEG(info);
+ intdosx(&regs, &regs, &sregs);
+ for (c = 0; c < 128; c++) {
+ upper[c] = (uch) toupper(c);
+ lower[c] = (uch) c;
+ }
+ for (; c < sizeof(upper); c++) {
+ upper[c] = (uch) (*country_info.casemap)(ident(c));
+ /* ident() required because casemap takes its parameter in al */
+ lower[c] = (uch) c;
+ }
+ for (c = 0; c < sizeof(upper); c++ ) {
+ unsigned int u = upper[c];
+ if (u != c && lower[u] == (uch) u) {
+ lower[u] = (uch)c;
+ }
+ }
+ for (c = 'A'; c <= 'Z'; c++) {
+ lower[c] = (uch) (c - 'A' + 'a');
+ }
+}
+#else /* !MSDOS16 */
+# ifndef OS2
+
+void init_upper()
+{
+ unsigned int c;
+#if defined(ATARI) || defined(CMS_MVS)
+#include <ctype.h>
+/* this should be valid for all other platforms too. (HD 11/11/95) */
+ for (c = 0; c< sizeof(upper); c++) {
+ upper[c] = islower(c) ? toupper(c) : c;
+ lower[c] = isupper(c) ? tolower(c) : c;
+ }
+#else
+ for (c = 0; c < sizeof(upper); c++) upper[c] = lower[c] = (uch)c;
+ for (c = 'a'; c <= 'z'; c++) upper[c] = (uch)(c - 'a' + 'A');
+ for (c = 'A'; c <= 'Z'; c++) lower[c] = (uch)(c - 'A' + 'a');
+#endif
+}
+# endif /* !OS2 */
+
+#endif /* ?MSDOS16 */
+
+int namecmp(string1, string2)
+ ZCONST char *string1, *string2;
+/* Compare the two strings ignoring case, and correctly taking into
+ * account national language characters. For operating systems with
+ * case sensitive file names, this function is equivalent to strcmp.
+ */
+{
+ int d;
+
+ for (;;)
+ {
+ d = (int) (uch) case_map(*string1)
+ - (int) (uch) case_map(*string2);
+
+ if (d || *string1 == 0 || *string2 == 0)
+ return d;
+
+ string1++;
+ string2++;
+ }
+}
+
+#ifdef EBCDIC
+char *strtoasc(char *str1, ZCONST char *str2)
+{
+ char *old;
+ old = str1;
+ while (*str1++ = (char)ascii[(uch)(*str2++)]);
+ return old;
+}
+
+char *strtoebc(char *str1, ZCONST char *str2)
+{
+ char *old;
+ old = str1;
+ while (*str1++ = (char)ebcdic[(uch)(*str2++)]);
+ return old;
+}
+
+char *memtoasc(char *mem1, ZCONST char *mem2, unsigned len)
+{
+ char *old;
+ old = mem1;
+ while (len--)
+ *mem1++ = (char)ascii[(uch)(*mem2++)];
+ return old;
+}
+
+char *memtoebc(char *mem1, ZCONST char *mem2, unsigned len)
+{
+ char *old;
+ old = mem1;
+ while (len--)
+ *mem1++ = (char)ebcdic[(uch)(*mem2++)];
+ return old;
+}
+#endif /* EBCDIC */
+
+#ifdef IZ_ISO2OEM_ARRAY
+char *str_iso_to_oem(dst, src)
+ ZCONST char *src;
+ char *dst;
+{
+ char *dest_start = dst;
+ while (*dst++ = (char)iso2oem[(uch)(*src++)]);
+ return dest_start;
+}
+#endif
+
+#ifdef IZ_OEM2ISO_ARRAY
+char *str_oem_to_iso(dst, src)
+ ZCONST char *src;
+ char *dst;
+{
+ char *dest_start = dst;
+ while (*dst++ = (char)oem2iso[(uch)(*src++)]);
+ return dest_start;
+}
+#endif
+
+
+
+/* DBCS support for Info-ZIP's zip (mainly for japanese (-: )
+ * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
+ * This code is public domain! Date: 1998/12/20
+ */
+#ifdef _MBCS
+
+char *___tmp_ptr;
+
+int lastchar(ptr)
+ ZCONST char *ptr;
+{
+ ZCONST char *oldptr = ptr;
+ while(*ptr != '\0'){
+ oldptr = ptr;
+ INCSTR(ptr);
+ }
+ return (int)(unsigned)*oldptr;
+}
+
+unsigned char *zmbschr(str, c)
+ ZCONST unsigned char *str;
+ unsigned int c;
+{
+ while(*str != '\0'){
+ if (*str == c) {return (unsigned char *)str;}
+ INCSTR(str);
+ }
+ return NULL;
+}
+
+unsigned char *zmbsrchr(str, c)
+ ZCONST unsigned char *str;
+ unsigned int c;
+{
+ unsigned char *match = NULL;
+ while(*str != '\0'){
+ if (*str == c) {match = (unsigned char*)str;}
+ INCSTR(str);
+ }
+ return match;
+}
+#endif /* _MBCS */
+
+
+
+#ifndef UTIL
+
+/*****************************************************************
+ | envargs - add default options from environment to command line
+ |----------------------------------------------------------------
+ | Author: Bill Davidsen, original 10/13/91, revised 23 Oct 1991.
+ | This program is in the public domain.
+ |----------------------------------------------------------------
+ | Minor program notes:
+ | 1. Yes, the indirection is a tad complex
+ | 2. Parenthesis were added where not needed in some cases
+ | to make the action of the code less obscure.
+ ****************************************************************/
+
+void envargs(Pargc, Pargv, envstr, envstr2)
+ int *Pargc;
+ char ***Pargv;
+ char *envstr;
+ char *envstr2;
+{
+ char *envptr; /* value returned by getenv */
+ char *bufptr; /* copy of env info */
+ int argc; /* internal arg count */
+ register int ch; /* spare temp value */
+ char **argv; /* internal arg vector */
+ char **argvect; /* copy of vector address */
+
+ /* see if anything in the environment */
+ envptr = getenv(envstr);
+ if (envptr != NULL) /* usual var */
+ while (isspace((uch)*envptr)) /* we must discard leading spaces */
+ envptr++;
+ if (envptr == NULL || *envptr == '\0')
+ if ((envptr = getenv(envstr2)) != NULL) /* alternate */
+ while (isspace((uch)*envptr))
+ envptr++;
+ if (envptr == NULL || *envptr == '\0')
+ return;
+
+ /* count the args so we can allocate room for them */
+ argc = count_args(envptr);
+ bufptr = malloc(1 + strlen(envptr));
+ if (bufptr == NULL)
+ ziperr(ZE_MEM, "Can't get memory for arguments");
+ strcpy(bufptr, envptr);
+
+ /* allocate a vector large enough for all args */
+ argv = (char **)malloc((argc + *Pargc + 1) * sizeof(char *));
+ if (argv == NULL) {
+ free(bufptr);
+ ziperr(ZE_MEM, "Can't get memory for arguments");
+ }
+ argvect = argv;
+
+ /* copy the program name first, that's always true */
+ *(argv++) = *((*Pargv)++);
+
+ /* copy the environment args first, may be changed */
+ do {
+#if defined(AMIGA) || defined(UNIX)
+ if (*bufptr == '"') {
+ char *argstart = ++bufptr;
+ *(argv++) = argstart;
+ for (ch = *bufptr; ch != '\0' && ch != '\"';
+ ch = *PREINCSTR(bufptr))
+ if (ch == '\\' && bufptr[1] != '\0')
+ ++bufptr; /* skip to char after backslash */
+ if (ch != '\0') /* overwrite trailing '"' */
+ *(bufptr++) = '\0';
+
+ /* remove escape characters */
+ while ((argstart = MBSCHR(argstart, '\\')) != NULL) {
+ strcpy(argstart, argstart + 1);
+ if (*argstart)
+ ++argstart;
+ }
+ } else {
+ *(argv++) = bufptr;
+ while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr);
+ if (ch != '\0') *(bufptr++) = '\0';
+ }
+#else
+# ifdef WIN32
+ /* We do not support backslash-quoting of quotes in quoted */
+ /* strings under Win32, because backslashes are directory */
+ /* separators and double quotes are illegal in filenames. */
+ if (*bufptr == '"') {
+ *(argv++) = ++bufptr;
+ while ((ch = *bufptr) != '\0' && ch != '\"') INCSTR(bufptr);
+ if (ch != '\0') *(bufptr++) = '\0';
+ } else {
+ *(argv++) = bufptr;
+ while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr);
+ if (ch != '\0') *(bufptr++) = '\0';
+ }
+# else
+ *(argv++) = bufptr;
+ while ((ch = *bufptr) != '\0' && !isspace((uch)ch)) INCSTR(bufptr);
+ if (ch != '\0') *(bufptr++) = '\0';
+# endif
+#endif /* ?(AMIGA || UNIX) */
+ while ((ch = *bufptr) != '\0' && isspace((uch)ch)) INCSTR(bufptr);
+ } while (ch);
+
+ /* now save old argc and copy in the old args */
+ argc += *Pargc;
+ while (--(*Pargc)) *(argv++) = *((*Pargv)++);
+
+ /* finally, add a NULL after the last arg, like UNIX */
+ *argv = NULL;
+
+ /* save the values and return */
+ *Pargv = argvect;
+ *Pargc = argc;
+}
+
+local int count_args(s)
+char *s;
+{
+ int count = 0;
+ char ch;
+
+ do {
+ /* count and skip args */
+ ++count;
+#if defined(AMIGA) || defined(UNIX)
+ if (*s == '\"') {
+ for (ch = *PREINCSTR(s); ch != '\0' && ch != '\"';
+ ch = *PREINCSTR(s))
+ if (ch == '\\' && s[1] != '\0')
+ INCSTR(s);
+ if (*s) INCSTR(s); /* trailing quote */
+ } else
+ while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s);
+#else
+# ifdef WIN32
+ if (*s == '\"') {
+ ++s; /* leading quote */
+ while ((ch = *s) != '\0' && ch != '\"') INCSTR(s);
+ if (*s) INCSTR(s); /* trailing quote */
+ } else
+ while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s);
+# else
+ while ((ch = *s) != '\0' && !isspace((uch)ch)) INCSTR(s);
+# endif
+#endif /* ?(AMIGA || UNIX) */
+ while ((ch = *s) != '\0' && isspace((uch)ch)) INCSTR(s);
+ } while (ch);
+
+ return(count);
+}
+
+
+
+/* Extended argument processing -- by Rich Wales
+ * This function currently deals only with the MKS shell, but could be
+ * extended later to understand other conventions.
+ *
+ * void expand_args(int *argcp, char ***argvp)
+ *
+ * Substitutes the extended command line argument list produced by
+ * the MKS Korn Shell in place of the command line info from DOS.
+ *
+ * The MKS shell gets around DOS's 128-byte limit on the length of
+ * a command line by passing the "real" command line in the envi-
+ * ronment. The "real" arguments are flagged by prepending a tilde
+ * (~) to each one.
+ *
+ * This "expand_args" routine creates a new argument list by scanning
+ * the environment from the beginning, looking for strings begin-
+ * ning with a tilde character. The new list replaces the original
+ * "argv" (pointed to by "argvp"), and the number of arguments
+ * in the new list replaces the original "argc" (pointed to by
+ * "argcp").
+ */
+void expand_args(argcp, argvp)
+ int *argcp;
+ char ***argvp;
+{
+#ifdef DOS
+
+/* Do NEVER include (re)definiton of `environ' variable with any version
+ of MSC or BORLAND/Turbo C. These compilers supply an incompatible
+ definition in <stdlib.h>. */
+#if defined(__GO32__) || defined(__EMX__)
+ extern char **environ; /* environment */
+#endif /* __GO32__ || __EMX__ */
+ char **envp; /* pointer into environment */
+ char **newargv; /* new argument list */
+ char **argp; /* pointer into new arg list */
+ int newargc; /* new argument count */
+
+ /* sanity check */
+ if (environ == NULL
+ || argcp == NULL
+ || argvp == NULL || *argvp == NULL)
+ return;
+ /* find out how many environment arguments there are */
+ for (envp = environ, newargc = 0;
+ *envp != NULL && (*envp)[0] == '~';
+ envp++, newargc++) ;
+ if (newargc == 0)
+ return; /* no environment arguments */
+ /* set up new argument list */
+ newargv = (char **) malloc(sizeof(char **) * (newargc+1));
+ if (newargv == NULL)
+ return; /* malloc failed */
+ for (argp = newargv, envp = environ;
+ *envp != NULL && (*envp)[0] == '~';
+ *argp++ = &(*envp++)[1]) ;
+ *argp = NULL; /* null-terminate the list */
+ /* substitute new argument list in place of old one */
+ *argcp = newargc;
+ *argvp = newargv;
+#else /* !DOS */
+ if (argcp || argvp) return;
+#endif /* ?DOS */
+}
+
+
+/* Fast routine for detection of plain text
+ * (ASCII or an ASCII-compatible extension such as ISO-8859, UTF-8, etc.)
+ * Author: Cosmin Truta.
+ * See "proginfo/txtvsbin.txt" for more information.
+ *
+ * This function returns the same result as set_file_type() in "trees.c".
+ * Unlike in set_file_type(), however, the speed depends on the buffer size,
+ * so the optimal implementation is different.
+ */
+int is_text_buf(buf_ptr, buf_size)
+ ZCONST char *buf_ptr;
+ unsigned buf_size;
+{
+ int result = 0;
+ unsigned i;
+ unsigned char c;
+
+ for (i = 0; i < buf_size; ++i)
+ {
+ c = (unsigned char)buf_ptr[i];
+ if (c >= 32) /* speed up the loop by checking this first */
+ result = 1; /* white-listed character found; keep looping */
+ else /* speed up the loop by inlining the following check */
+ if ((c <= 6) || (c >= 14 && c <= 25) || (c >= 28 && c <= 31))
+ return 0; /* black-listed character found; stop */
+ }
+
+ return result;
+}
+
+#endif /* UTIL */
+
+
+#ifdef DEBUGNAMES
+#undef free
+int Free(x)
+void *x;
+{
+ if (x == (void *) 0xdeadbeef)
+ exit(-1);
+ free(x);
+ return 0;
+}
+
+int printnames()
+{
+ struct zlist far *z;
+
+ for (z = zfiles; z != NULL; z = z->nxt)
+ fprintf(mesg, "%s %s %s %p %p %p %08x %08x %08x\n",
+ z->name, z->zname, z->iname,
+ z->name, z->zname, z->iname,
+ *((int *) z->name), *((int *) z->zname),
+ *((int *) z->iname));
+ return 0;
+}
+
+#endif /* DEBUGNAMES */
+
+
+/* Below is used to format zoff_t values, which can be either long or long long
+ depending on if LARGE FILES are supported. Function provided by SMS.
+ 10/17/04 EG */
+
+/* 2004-12-01 SMS.
+ * Brought in fancy fzofft() from UnZip.
+ */
+
+/* This implementation assumes that no more than FZOFF_NUM values will be
+ needed in any printf using it. */
+
+/* zip_fzofft(): Format a zoff_t value in a cylindrical buffer set.
+ This version renamed from fzofft because of name conflict in unzip
+ when combined in WiZ. */
+
+/* 2004-12-19 SMS.
+ * I still claim than the smart move would have been to disable one or
+ * the other instance with #if for Wiz. But fine. We'll change the
+ * name.
+ */
+
+/* This is likely not thread safe. Needs to be done without static storage.
+ 12/29/04 EG */
+
+/* zip_fzofft(): Format a zoff_t value in a cylindrical buffer set. */
+
+#define FZOFFT_NUM 4 /* Number of chambers. */
+#define FZOFFT_LEN 24 /* Number of characters/chamber. */
+
+
+/* Format a zoff_t value in a cylindrical buffer set. */
+
+char *zip_fzofft( val, pre, post)
+ zoff_t val;
+ char *pre;
+ char *post;
+{
+ /* Storage cylinder. */
+ static char fzofft_buf[ FZOFFT_NUM][ FZOFFT_LEN];
+ static int fzofft_index = 0;
+
+ /* Temporary format string storage. */
+ static char fmt[ 16] = "%";
+
+ /* Assemble the format string. */
+ fmt[ 1] = '\0'; /* Start after initial "%". */
+ if (pre == FZOFFT_HEX_WID) /* Special hex width. */
+ {
+ strcat( fmt, FZOFFT_HEX_WID_VALUE);
+ }
+ else if (pre == FZOFFT_HEX_DOT_WID) /* Special hex ".width". */
+ {
+ strcat( fmt, ".");
+ strcat( fmt, FZOFFT_HEX_WID_VALUE);
+ }
+ else if (pre != NULL) /* Caller's prefix (width). */
+ {
+ strcat( fmt, pre);
+ }
+
+ strcat( fmt, FZOFFT_FMT); /* Long or long-long or whatever. */
+
+ if (post == NULL)
+ strcat( fmt, "d"); /* Default radix = decimal. */
+ else
+ strcat( fmt, post); /* Caller's radix. */
+
+ /* Advance the cylinder. */
+ fzofft_index = (fzofft_index+ 1)% FZOFFT_NUM;
+
+ /* Write into the current chamber. */
+ sprintf( fzofft_buf[ fzofft_index], fmt, val);
+
+ /* Return a pointer to this chamber. */
+ return fzofft_buf[ fzofft_index];
+}
+
+
+/* Format a uzoff_t value in a cylindrical buffer set. */
+/* Added to support uzoff_t type. 12/29/04 */
+
+char *zip_fuzofft( val, pre, post)
+ uzoff_t val;
+ char *pre;
+ char *post;
+{
+ /* Storage cylinder. */
+ static char fuzofft_buf[ FZOFFT_NUM][ FZOFFT_LEN];
+ static int fuzofft_index = 0;
+
+ /* Temporary format string storage. */
+ static char fmt[ 16] = "%";
+
+ /* Assemble the format string. */
+ fmt[ 1] = '\0'; /* Start after initial "%". */
+ if (pre == FZOFFT_HEX_WID) /* Special hex width. */
+ {
+ strcat( fmt, FZOFFT_HEX_WID_VALUE);
+ }
+ else if (pre == FZOFFT_HEX_DOT_WID) /* Special hex ".width". */
+ {
+ strcat( fmt, ".");
+ strcat( fmt, FZOFFT_HEX_WID_VALUE);
+ }
+ else if (pre != NULL) /* Caller's prefix (width). */
+ {
+ strcat( fmt, pre);
+ }
+
+ strcat( fmt, FZOFFT_FMT); /* Long or long-long or whatever. */
+
+ if (post == NULL)
+ strcat( fmt, "u"); /* Default radix = decimal. */
+ else
+ strcat( fmt, post); /* Caller's radix. */
+
+ /* Advance the cylinder. */
+ fuzofft_index = (fuzofft_index+ 1)% FZOFFT_NUM;
+
+ /* Write into the current chamber. */
+ sprintf( fuzofft_buf[ fuzofft_index], fmt, val);
+
+ /* Return a pointer to this chamber. */
+ return fuzofft_buf[ fuzofft_index];
+}
+
+
+/* Display number to mesg stream
+ 5/15/05 EG */
+
+int DisplayNumString(file, i)
+ FILE *file;
+ uzoff_t i;
+{
+ char tempstrg[100];
+ int j;
+ char *s = tempstrg;
+
+ WriteNumString(i, tempstrg);
+ /* skip spaces */
+ for (j = 0; j < 3; j++) {
+ if (*s != ' ') break;
+ s++;
+ }
+ fprintf(file, "%s", s);
+
+ return 0;
+}
+
+/* Read numbers with trailing size multiplier (like 10M) and return number.
+ 10/30/04 EG */
+
+uzoff_t ReadNumString( numstring )
+ char *numstring;
+{
+ zoff_t num = 0;
+ char multchar = ' ';
+ int i;
+ uzoff_t mult = 1;
+
+ /* check if valid number (currently no negatives) */
+ if (numstring == NULL) {
+ zipwarn("Unable to read empty number in ReadNumString", "");
+ return (uzoff_t)-1;
+ }
+ if (numstring[0] < '0' || numstring[0] > '9') {
+ zipwarn("Unable to read number (must start with digit): ", numstring);
+ return (uzoff_t)-1;
+ }
+ if (strlen(numstring) > 8) {
+ zipwarn("Number too long to read (8 characters max): ", numstring);
+ return (uzoff_t)-1;
+ }
+
+ /* get the number part */
+ num = atoi(numstring);
+
+ /* find trailing multiplier */
+ for (i = 0; numstring[i] && isdigit(numstring[i]); i++) ;
+
+ /* return if no multiplier */
+ if (numstring[i] == '\0') {
+ return (uzoff_t)num;
+ }
+
+ /* nothing follows multiplier */
+ if (numstring[i + 1]) {
+ return (uzoff_t)-1;
+ }
+
+ /* get multiplier */
+ multchar = toupper(numstring[i]);
+
+ if (multchar == 'K') {
+ mult <<= 10;
+ } else if (multchar == 'M') {
+ mult <<= 20;
+ } else if (multchar == 'G') {
+ mult <<= 30;
+#ifdef LARGE_FILE_SUPPORT
+ } else if (multchar == 'T') {
+ mult <<= 40;
+#endif
+ } else {
+ return (uzoff_t)-1;
+ }
+
+ return (uzoff_t)num * mult;
+}
+
+
+/* Write the number as a string with a multiplier (like 10M) to outstring.
+ Always writes no more than 3 digits followed maybe by a multiplier and
+ returns the characters written or -1 if error.
+ 10/30/04 EG */
+
+int WriteNumString( num, outstring )
+ uzoff_t num;
+ char *outstring;
+{
+ int mult;
+ int written = 0;
+ int i;
+ int j;
+ char digits[4];
+ int dig;
+
+ *outstring = '\0';
+
+ /* shift number 1 K until less than 10000 */
+ for (mult = 0; num >= 10240; mult++) {
+ num >>= 10;
+ }
+
+ /* write digits as " 0" */
+ for (i = 1; i < 4; i++) {
+ digits[i] = ' ';
+ }
+ digits[0] = '0';
+
+ if (num >= 1000) {
+ i = 3;
+ num *= 10;
+ num >>= 10;
+ mult++;
+ digits[0] = (char) (num % 10) + '0';
+ digits[1] = '.';
+ digits[2] = (char) (num / 10) + '0';
+ } else {
+ for (i = 0; num; i++) {
+ dig = (int) (num % 10);
+ num /= 10;
+ digits[i] = dig + '0';
+ }
+ }
+ if (i == 0) i = 1;
+ for (j = i; j > 0; j--) {
+ *outstring = digits[j - 1];
+ outstring++;
+ written++;
+ }
+
+ /* output multiplier */
+ if (mult == 0) {
+ } else if (mult == 1) {
+ *outstring = 'K';
+ outstring++;
+ written++;
+ } else if (mult == 2) {
+ *outstring = 'M';
+ outstring++;
+ written++;
+ } else if (mult == 3) {
+ *outstring = 'G';
+ outstring++;
+ written++;
+ } else if (mult == 4) {
+ *outstring = 'T';
+ outstring++;
+ written++;
+ } else {
+ *outstring = '?';
+ outstring++;
+ written++;
+ }
+
+ *outstring = '\0';
+
+ return written;
+}
+
+
+#if 0 /* not used anywhere, should get removed by next release... */
+
+/* Apply the Adler-16 checksum to a set of bytes.
+ * Use this function as you would use crc32():
+ * - First call this function by passing a NULL pointer instead of buf
+ * OR initialize the checksum register with ADLERVAL_INITIAL.
+ * - Iteratively call this function for each buffer fragment.
+ * This function returns the updated checksum.
+ *
+ * IN assertion: chksum is a valid Adler-16 checksum:
+ * (chksum & 0xffU) < ADLER16_BASE && ((chksum >> 8) & 0xffU) < ADLER16_BASE
+ *
+ * Author: Cosmin Truta.
+ * See "proginfo/adler16.txt" for more information.
+ */
+
+#define ADLER16_BASE 251 /* The largest prime smaller than 256 */
+
+unsigned int adler16(chksum, buf, len)
+ unsigned int chksum;
+ ZCONST uch *buf;
+ extent len;
+{
+ unsigned int sum1 = chksum & 0xff;
+ unsigned int sum2 = (chksum >> 8) & 0xff;
+ extent i;
+
+ Assert((sum1 < ADLER16_BASE) && (sum2 < ADLER16_BASE),
+ "adler16: invalid checksum");
+
+ if (buf == NULL)
+ return 1;
+
+ for (i = 0; i < len; ++i)
+ {
+ sum1 += buf[i];
+ if (sum1 >= ADLER16_BASE) /* this is faster than modulo ADLER16_BASE */
+ sum1 -= ADLER16_BASE;
+ sum2 += sum1;
+ if (sum2 >= ADLER16_BASE) /* ditto */
+ sum2 -= ADLER16_BASE;
+ }
+
+ return (sum2 << 8) | sum1;
+}
+
+#endif /* 0, not used anywhere */
+
+
+/* returns true if abbrev is abbreviation for matchstring */
+int abbrevmatch (matchstring, abbrev, case_sensitive, minmatch)
+ char *matchstring;
+ char *abbrev;
+ int case_sensitive;
+ int minmatch;
+{
+ int cnt = 0;
+ char *m;
+ char *a;
+
+ m = matchstring;
+ a = abbrev;
+
+ for (; *m && *a; m++, a++) {
+ cnt++;
+ if (case_sensitive) {
+ if (*m != *a) {
+ /* mismatch */
+ return 0;
+ }
+ } else {
+ if (toupper(*m) != toupper(*a)) {
+ /* mismatch */
+ return 0;
+ }
+ }
+ }
+ if (cnt < minmatch) {
+ /* not big enough string */
+ return 0;
+ }
+ if (*a != '\0') {
+ /* abbreviation longer than match string */
+ return 0;
+ }
+ /* either abbreviation or match */
+ return 1;
+}
diff --git a/vms/NOTES.TXT b/vms/NOTES.TXT
new file mode 100644
index 0000000..4f94ec3
--- /dev/null
+++ b/vms/NOTES.TXT
@@ -0,0 +1,382 @@
+ VMS Notes for Info-ZIP Zip 3.0 and UnZip 6.0
+ ============================================
+
+ This document describes some VMS-specific behavior and implementation
+details of the Info-ZIP Zip and UnZip programs.
+
+ Last modified: 2008-04-10.
+
+
+ Command-line Case
+ -----------------
+
+ Zip and UnZip now include code which can preserve the case of
+command-line parameters and options, which obviates quoting upper-case
+options like "-V" or "-Z". This works on non-VAX systems with a
+sufficiently recent C RTL, and SET PROCESS /PARSE_STYLE = EXTENDED.
+(Sufficiently recent here means __CRTL_VER >= 70301000, which includes
+VMS V7.3-1 with a C Run Time Library ECO, or V7.3-2 or newer.) This
+code uses the decc$feature_set_value() function to enable the
+DECC$ARGV_PARSE_STYLE feature. There is a small range of C RTL versions
+where this function is unavailable, but where manually setting the
+logical name DECC$ARGV_PARSE_STYLE to "ENABLE" will work. HELP CRTL
+leads to some additional information on these features.
+
+
+ File Name Case (ODS5)
+ ---------------------
+
+ In general, Zip 3.0 and UnZip 6.0 should handle file name case (and
+extended file names) in reasonable ways on ODS5 disks.
+
+ Zip offers a variety of "-C" (/PRESERVE_CASE) options to control how
+case is handled when adding files to an archive. The default settings
+("-C2-", /PRESERVE_CASE = NOODS2, down-case ODS2 file names; "-C5",
+/PRESERVE_CASE = ODS5, preserve case of ODS5 file names) should be
+consistent with previous Zip versions for files on ODS2 disks, and
+reasonable for files on ODS5 disks.
+
+ UnZip should preserve case when it extracts to an ODS5 destination
+disk (unless "-2" (/ODS2) is specified). (Note that previous UnZip
+versions, including version 5.52, did not properly preserve case for
+directories, which were always up-cased.)
+
+ The Zip and UnZip builders should work properly on ODS2 and ODS5
+disks, with old (pre-ODS5) and new (case-conscious) versions of MMS (or
+MMK). All testing was done with SET PROCESS /CASE_LOOKUP = BLIND.
+Various problems may be expected with /CASE_LOOKUP = SENSITIVE.
+
+ For consistency, the builders should always create product files
+(.OBJ, .EXE, .HLB, and so on) with upper-case names, whether the build
+is done on an ODS2 or ODS5 disk. Note, however, that in a world with
+both ODS2 and ODS5 disks, and old and new Zip and UnZip versions, it's
+possible to encounter lower-case product file names. For example, a VMS
+binary kit could be created on an ODS2 disk, and a Zip archive created
+from that (using Zip 2.x, or Zip 3.x with default settings). Such a Zip
+archive would contain down-cased names for those product files, and
+those lower-case names would then normally be preserved when UnZip was
+used to extract that archive onto an ODS5 destination. Normally, things
+will work regardless of such case changes, but there may be some
+untested combinations of unexpected name cases and quirky MMS (or MMK)
+behavior, where something goes wrong. Complaints are always welcome,
+but it may not be possible to get everything to work as expected with
+every version of VMS, MMS (or MMK), Zip, and UnZip, on every file
+system.
+
+ It might help matters if _all_ VMS binary kits were produced on ODS5
+disks, and packaged using (case-preserving) Zip version 3.x, but this
+would certainly be different from the way things have been done before,
+and maintaining control over this process is essentially impossible.
+
+
+ Symbolic Links (ODS5)
+ ---------------------
+
+ VMS V8.3 offers support for symbolic links (symlinks) on ODS5 disks.
+In previous Zip and UnZip versions, the generic code for symlinks was
+disabled, and there was no VMS-specific code for symlinks. Now, by
+default, Zip and UnZip attempt to support symlinks wherever the C
+headers and C run-time library include the functions needed for symlink
+support. This means non-VAX systems with __CRTL_VER >= 70301000, so
+this includes VMS V7.3-1 and up, and thus symlink-capable Zip and UnZip
+programs may be built on systems which do not themselves offer symlink
+support. (Various run-time failures may be expected if symlinks are
+encountered on pre-V8.3 systems, either in a file system or in a Zip
+archive.)
+
+ Symlink support can be disabled at build-time, if desired, by
+defining the C macro NO_SYMLINKS. (See comments in the builder
+regarding LOCAL_UNZIP or LOCAL_ZIP, as appropriate.) For example, using
+MMS to build UnZip:
+
+ MMS /DESCRIP = [.VMS] /MACRO = ("LOCAL_UNZIP=NO_SYMLINKS=1")
+
+or, using the command procedure to build Zip:
+
+ LOCAL_ZIP == "NO_SYMLINKS=1"
+ @ [.VMS]BUILD_ZIP.COM
+ DELETE /SYMBOL /GLOBAL LOCAL_ZIP
+
+ The Zip "-v" (/VERBOSE) report should include SYMLINK_SUPPORT in its
+list of "Zip special compilation options" if Zip was built with symlink
+support. Currently, UnZip is less convenient, but searching the UnZip
+executable (or EXTRACT.OBJ) for "symlink" should fail if symlink support
+is missing (or succeed if it's present):
+
+ $ SEARCH /NOOUTPUT UNZIP.EXE SYMLINK ! No symlink support.
+ %SEARCH-I-NOMATCHES, no strings matched
+or:
+ $ SEARCH /NOOUTPUT EXTRACT.OBJ SYMLINK ! Symlink support.
+ $ SHOW SYMBOL $STATUS
+ $STATUS == "%X00000001"
+
+
+ File I/O Performance
+ --------------------
+
+ When compiled using DEC/Compaq/HP C (not GNU C or VAX C), the Zip and
+UnZip file I/O code now includes access callback functions which are
+used to try to set some RMS parameters to non-default values, with the
+intention of improving file I/O speed. This affects reading an archive
+file in UnZip and writing one in Zip. (Reading and writing the
+individual data files are handled in more exotic ways, making these
+parameters less important for them.)
+
+ Currently, the built-in default parameters enable read-ahead and
+write-behind, using a multi-buffer count of 2, and a multi-block count
+of 127 (the maximum). For writing the archive, the default extend
+quantity is 16384 blocks (8MB), with truncation enabled. This
+combination is believed to be, at worst, fairly harmless for most
+situations, and, in most cases, to provide a substantial speed
+improvement, especially with large archives.
+
+ This code allows SET RMS_DEFAULT parameters to override the built-in
+default values. On some old VMS versions, sys$getjpi() can not provide
+the SET RMS_DEFAULT values, and in this situation, the callback function
+will not try to use its improved parameter values. Users on such old
+VMS versions who seek improved I/O speed may wish to bypass this check,
+which requires changing the code in the get_rms_defaults() function in
+[.VMS]VMS.C. The "-vv" (/VERBOSE = MORE) option on both programs
+enables diagnostic messages which show the operation of the callback
+function. A message showing a failure status from sys$getjpi()
+indicates this problem.
+
+ Sample results (UnZip shown, Zip similar):
+
+ VMS VAX V5.4, VAX C. Callback code disabled, no messages:
+ WIMP $ unzip -tvv TESTMAKE.ZIP
+ Archive: SYS$SYSDEVICE:[UTILITY.SOURCE.ZIP.UNZIP60C]TESTMAKE.ZIP;1
+ [...]
+
+ VMS VAX V5.5-2, DEC C. SYS$GETJPI() fails (%SYSTEM-F-BADPARAM):
+ WEAK $ unzip -tvv TESTMAKE.ZIP
+ Get RMS defaults. getjpi sts = %x00000014.
+ Archive: DUA1:[UTILITY.SOURCE.ZIP.UNZIP60C]TESTMAKE.ZIP;1
+ [...]
+
+ VMS VAX V7.3, DEC/Compaq C. Callback code works:
+ WUSS $ unzip -tvv TESTMAKE.ZIP
+ Get RMS defaults. getjpi sts = %x00000001.
+ Default: deq = 0, mbc = 0, mbf = 0.
+ Open callback. ID = 1, deq = 16384, mbc = 127, mbf = 2.
+ Archive: ALP$DKA0:[UTILITY.SOURCE.ZIP.UNZIP60C]TESTMAKE.ZIP;1
+ [...]
+
+ VMSV5.5-2 is too old. V7.3 is new enough. Anyone with more precise
+information is invited to contribute it.
+
+ Users who find other parameter sets more beneficial, or who find
+particular problems with this set are welcome to comment.
+
+ In this version, as in previous versions, when UnZip expands a -V
+archive, it allocates the entire extent of a data file before writing
+any of its data. In some previous versions, this could cause the
+destination disk to be locked for a considerable time (minutes), if
+highwater marking was enabled on that disk. Now, the FAB SQO
+("sequential access only") flag (or equivalent) is set, which prevents
+this troublesome disk locking.
+
+ In some previous versions, when UnZip expanded a non-V archive, it
+did no pre-allocation, and used the default extension quantity. This
+could slow file creation significantly for large files. Now, space for
+extracted files is pre-allocated, and the same SQO ("sequential access
+only") flag is set, as with a -V archive.
+
+
+ Changes to the "-V" (/VMS) Option
+ ---------------------------------
+
+ The intent of the "-V" (/VMS) option was to store VMS file attributes
+in a Zip archive, allowing UnZip to extract an exact copy of a file on a
+VMS system, including all its VMS attributes.
+
+ In Zip before version 2.31, using the "-V" (/VMS) option created an
+archive which usually contained data from beyond the EOF (End-of-File)
+marker in a data file, but generally not all the disk blocks allocated
+for the file. When extracted on a VMS system, the result was usually
+acceptable (because the data from beyond the EOF marker were usually
+ignored). However, when extracted on a non-VMS system, the resulting
+file was usually corrupted by being NUL-padded to the next larger 16KB
+multiple in size.
+
+ Now (Zip 2.31 and later), with "-V" (/VMS), Zip truncates a data file
+at EOF, and portable-format files (Stream_LF, fixed-512) should be
+extracted properly on a non-VMS system. On a VMS system, well-formed
+files (that is, those with no valid data beyond EOF) should also be
+restored correctly.
+
+ With the new "-VV" (/VMS = ALL) option, the archive includes all
+allocated blocks for the file (including those beyond EOF). When
+extracted on a VMS system, the original file should be reproduced with
+as much fidelity as possible, but on a non-VMS system, most files will
+be seen as corrupt because of the data from beyond EOF.
+
+
+ Changes to Program Exit Status Values
+ -------------------------------------
+
+ Zip and UnZip exit with 32-bit VMS status values which are formed
+from their internal OS-independent status values. In previous program
+versions, this was done by converting the internal success code (0) into
+%x00000001 (SS$_NORMAL), and converting the other internal warning and
+error codes using an artificial control/facility code, 0x7FFF (which
+includes some reserved bits), and a severity value which was determined
+according to rules specified in the VMS-specific exit function.
+Curiously, the internal status codes were left-shifted by 4 bits instead
+of 3, so all the resulting VMS message codes (bits 13:3) were even.
+
+ Zip and UnZip now have facility names and codes assigned by HP
+(UnZip: IZ_UNZIP, 1954; Zip: IZ_ZIP, 1955). Now, by default, the
+programs exit with standard 32-bit VMS status values which differ from
+the old ones in several ways: The official facility code is used, and
+the facility-specific bit is set. (For compatibility with older
+versions, the internal status codes are still left-shifted by 4 bits.
+This also makes it easier to extract the internal status code from a
+hexadecimal representation of the VMS status code.) The builders also
+create non-executable message files (UNZIP_MSG.EXE and ZIP_MSG.EXE) so
+that, after a suitable SET MESSAGE command, the program messages will be
+available from DCL. For example:
+
+ $ SET MESSAGE dev:[dir]ZIP_MSG.EXE
+ $ ZIP FRED.ZIP no_such_file
+ zip warning: name not matched: no_such_file
+
+ zip error: Nothing to do!
+ (dev:[dir]FRED.ZIP;)
+
+ ALP $ WRITE SYS$OUTPUT F$MESSAGE( $STATUS)
+ %IZ_ZIP-W-NONE, Nothing to do
+
+The message files may be copied into SYS$MESSAGE to make them generally
+available, although this could cause some confusion if multiple versions
+of the programs are used on the system, and their error message source
+files differ. Each different destination directory will get its own
+UNZIP_MSG.EXE or ZIP_MSG.EXE ([.ALPHA], [.ALPHAL], [.VAX], and so on),
+but all of the same-architecture files are equivalent to each other.
+That is, on an Alpha system, any of the [.ALPHA*]ZIP_MSG.EXE files could
+be used; on an IA64 system, any of the [.IA64*]ZIP_MSG.EXE files could
+be used; and on a VAX system, any of the [.VAX*]ZIP_MSG.EXE files could
+be used. (Similar for UNZIP_MSG.EXE, of course.)
+
+ If desired, the programs may be built to use the old exit status values
+by defining a C macro with the old facility value:
+"CTL_FAC_IZ_UNZIP=0x7FFF" (UnZip) or "CTL_FAC_IZ_ZIP=0x7FFF" (Zip).
+(See comments in the builder regarding LOCAL_UNZIP or LOCAL_ZIP, as
+appropriate.) This will maintain compatibility with older program
+versions, but will make the programs incompatible with the new error
+message files.
+
+
+ VMS File Attribute Schemes
+ --------------------------
+
+ Zip's "-V" (/VMS) option causes VMS file attributes to be stored in
+an archive. Since Zip version 2.2 (released in 1996), Zip has, by
+default, stored VMS file attributes using a scheme ("PK") which is
+compatible with the one used by PKWARE in their PKZIP product. Before
+that, a different scheme ("IM") was used. UnZip versions before 5.2
+support only the older IM scheme, but since UnZip version 5.2, both
+schemes have been supported by UnZip.
+
+ The IM scheme has not been well tested recently, but it is still
+available. Some problems were seen when the IM scheme was used with
+symbolic links on VMS V8.3. Details on how build Zip to use the IM
+scheme instead of the PK scheme are included in comments in the main
+builder files. Look for VMS_IM_EXTRA in [.VMS]BUILD_ZIP.COM or IM in
+[.VMS]DESCRIP.MMS.
+
+ The "special compilation options" section of a "zip -v" ("zip
+/verbose") report should show either VMS_PK_EXTRA or VMS_IM_EXTRA,
+according to how Zip was built.
+
+
+ UTC Date-Times
+ --------------
+
+ Zip archives traditionally include local (MS-DOS compatible)
+date-time information for files. Since Zip version 2.1, it has also
+been possible to store UTC date-time information in the archive, and
+since UnZip version 5.2, UnZip has been able to use this UTC date-time
+information when extracting files.
+
+ On VMS, support in the C run-time environment for UTC became
+available with VMS V7.0. UTC support in Zip and UnZip is automatically
+enabled at compile time, if it is available on the system where the code
+is compiled (__CRTL_VER >= 70000000). It may be disabled at compile
+time by defining the C macro NO_EF_UT_TIME. Details on how build Zip
+and UnZip with additional C macros defined are included in comments in
+the main builder files. Look for LOCAL_[UN]ZIP in
+[.VMS]BUILD_[UN]ZIP.COM or in [.VMS]DESCRIP.MMS. For example, using MMS
+to build UnZip:
+
+ MMS /DESCRIP = [.VMS] /MACRO = ("LOCAL_UNZIP=NO_EF_UT_TIME=1")
+
+or, using the command procedure to build Zip:
+
+ LOCAL_ZIP == "NO_EF_UT_TIME=1"
+ @ [.VMS]BUILD_ZIP.COM
+ DELETE /SYMBOL /GLOBAL LOCAL_ZIP
+
+ The "special compilation options" section of a "zip -v" ("zip
+/verbose") or "unzip -v" ("unzip /verbose") report should show
+USE_EF_UT_TIME if the program was built with UTC support.
+
+
+ Building with the LIST option using MMK or MMS
+ ----------------------------------------------
+
+ Currently, building with MMK or MMS using the LIST option (as in
+"/MACRO = LIST=1") may cause a failure for some old versions of the DEC
+C compiler. The LIST option currently adds "/show = (all, nomessages)"
+to the CC command line, and some old DEC C compilers do not support the
+"nomessages" keyword. When VAX C is used, this keyword is omitted, but
+the builder does not distinguish between the various DEC/Compaq/HP C
+versions. The work-arounds are to use BUILD_[UN]ZIP.COM, or edit
+[.VMS]DESCRIP_SRC.MMS to remove the troublesome keyword.
+
+
+ GNU C
+ -----
+
+ Zip and UnZip have been built using GNU C (VAX) version 2.3, mostly
+for fun, but serious users are encouraged to report any interest in
+continuing this activity. The GNU C 2.3 header files were missing some
+things, including definitions of SEEK_CUR, SEEK_END, and SEEK_SET. The
+VMS-specific code now expects to find unixio.h and unixlib.h, which were
+absent from the GNU C 2.3 distribution.
+
+ To work around these difficulties, the Zip and UnZip kits include
+some emergency replacement unixio.h and unixlib.h files which appear to
+work for these programs, at least. To install them, use commands like
+the following:
+
+ COPY [.VMS]UNIXIO_GCC.H GNU_CC_INCLUDE:[000000]UNIXIO.H
+ COPY [.VMS]UNIXLIB_GCC.H GNU_CC_INCLUDE:[000000]UNIXLIB.H
+ SET PROTECTION W:RE GNU_CC_INCLUDE:[000000]UNIXIO.H, UNIXLIB.H
+
+ There may be an error in the GNU C header file ATRDEF.H which can
+cause Zip to fail, when making a "-V" archive, with a spurious "could
+not open for reading" error message, followed by more bad behavior. It
+probably also causes trouble of some kind in UnZip. To check the
+questionable macro definition, use a command like the following:
+
+ SEARCH GNU_CC_INCLUDE:[000000]ATRDEF.H ATR$S_JOURNAL
+
+This should show something equivalent to this:
+
+ #define ATR$S_JOURNAL 0x001
+
+If you see "0x002" (or equivalent) instead of "0x001" (or equivalent),
+then this value must be corrected in the file before building Zip or
+UnZip.
+
+ You may also see several warnings from the compiler caused by other
+defects in the GNU C header files, such as:
+
+<various>: warning: passing arg 4 of `qsort' from incompatible pointer type
+
+[...]rab.h:134: warning: unnamed struct/union that defines no instances
+[...]rab.h:143: warning: unnamed struct/union that defines no instances
+
+These warnings appear to be harmless.
+
diff --git a/vms/VMS_ZIP.RNH b/vms/VMS_ZIP.RNH
new file mode 100644
index 0000000..183ceea
--- /dev/null
+++ b/vms/VMS_ZIP.RNH
@@ -0,0 +1,1467 @@
+.!
+.! File: ZIP.RNH
+.!
+.! Author: Hunter Goatley
+.!
+.! Date: October 22, 1991
+.!
+.! Description:
+.!
+.! RUNOFF source file for portable ZIP on-line help for VMS.
+.! Adapted from MANUAL, distributed with ZIP.
+.!
+.! To build: $ RUNOFF ZIP.RNH
+.! $ LIBR/HELP/INSERT libr ZIP
+.!
+.! Modification history:
+.!
+.! Hunter Goatley 22-OCT-1991 20:45
+.! Genesis.
+.! Jean-loup Gailly 25 March 92
+.! Adaptation to zip 1.6.
+.! Igor Mandrichenko 9-JUN-1992
+.! Added explanation of -V option.
+.! Jean-loup Gailly 14 June 92
+.! Adaptation to zip 1.8.
+.! Jean-loup Gailly 20 Aug 92
+.! Adaptation to zip 1.9.
+.! Jean-loup Gailly 31 Aug 93
+.! Adaptation to zip 2.0.
+.! Christian Spieler 20 Sep 93
+.! Adaptation to zip 2.0 and OpenVMS completed.
+.! Christian Spieler 05 Dec 95
+.! Adaptation to zip 2.1, new options.
+.! Christian Spieler 20 Jan 96
+.! Changed -L and -v descriptions.
+.! Christian Spieler 11 Feb 96
+.! Added -X option.
+.! Onno van der Linden,
+.! Christian Spieler 13 Mar 96
+.! Removed -ee option.
+.! Christian Spieler 09 Feb 96
+.! Updated copyright notice, Zip version.
+.! Christian Spieler 21 Jul 97
+.! Added -P, -R, -i@, -x@ and -tt options, modified for Zip 2.2.
+.! Christian Spieler 14 Oct 97
+.! unified spelling of "Info-ZIP", final cleanups for 2.2.
+.! Steven Schweda 10 May 2007
+.! General update for version 3.0.
+.! Ed Gordon 12 May 2007
+.! Minor updates for version 3.0.
+.!
+.noflags
+.lm4 .rm72
+.indent -4
+1 ZIP
+.br
+Zip is a compression and file packaging utility for several operating
+systems, including UNIX, VMS, MSDOS, OS/2, Windows 9x/NT/XP, Minix, Atari,
+Macintosh, Amiga, and Acorn RISC OS. It is analogous to a combination of
+tar and compress and is compatible with PKZIP (Phil Katz's ZIP) for
+MSDOS systems.
+.sk
+Zip is useful for packaging a set of files for distribution, for
+archiving files, and for saving disk space by temporarily compressing
+unused files or directories. A companion program, UnZip, unpacks Zip
+archives.
+.sk
+For brief help on Zip or UnZip, run the program without specifying any
+parameters on the command line.
+.sk
+This description covers the Zip program which uses a UNIX-style command
+line. A separate program is available which provides a VMS-style CLI
+command line, and it has its own documentation. Refer to the Zip
+installation instructions for details.
+.sk
+Format
+.sk;.lm+2;.literal
+ZIP [-options] archive inpath inpath ...
+.end literal;.lm-2
+.!------------------------------------------------------------------------------
+.indent -4
+2 Basic_Usage
+.br
+Format
+.sk;.lm+2;.literal
+ZIP [-options] archive inpath inpath ...
+.end literal;.lm-2
+.sk
+The default action of Zip is to add or replace entries in "archive" from
+the list of "inpath" file specifications, which can include directories
+and file names with VMS-style wildcards, or the special name -@ to read
+file specifications from SYS$INPUT (stdin).
+.sk
+With SET PROCESS /PARSE_STYLE = EXTENDED (available on recent non-VAX
+systems), Zip preserves the case of the command line. Otherwise, mixed-
+or upper-case options and arguments must be quoted. For example,
+"-V". Examples in this document generally do not show this quotation,
+so VAX and /PARSE_STYLE = TRADITIONAL users (that is, troglodytes) will
+need to add quotation where needed when working with these examples.
+.sk
+General
+.sk
+Zip reads one or more files, compresses the data (normally), and stores
+the compressed information into a single Zip archive file, along with
+information about each file (name, path, date and time of last
+modification, protection, and check information to verify file
+integrity). On a VMS system, Zip can also save VMS/RMS file attributes,
+allowing UnZip to restore the files without loss of important file
+attributes. Zip can pack an entire directory structure into a Zip
+archive with a single command.
+.sk
+Compression
+.sk
+Compression ratios of 2:1 to 3:1 are common for text files. Zip has one
+standard compression method ("deflate") and can also store files without
+compression. Zip (and UnZip) may be built with optional support for the
+bzip2 compression method. Then, the user may select bzip2 compression
+instead of the default "deflate" method. Zip automatically chooses
+simple storage over compression for a file, if the specified compression
+method does not actually compress the data in that file.
+.sk
+Compatibility
+.sk
+Zip and UnZip can work with archives produced by PKZIP (supporting most
+PKZIP features up to PKZIP version 4.6), and PKZIP and PKUNZIP can work
+with archives produced by Zip (with some exceptions, notably streamed
+archives, but recent changes in the .ZIP file standard may facilitate
+better compatibility). Zip version 3.0 is compatible with PKZIP 2.04
+and also supports the Zip64 extensions of PKZIP 4.5 which allows
+archives as well as files to exceed the previous 2 GB limit (4 GB in
+some cases). Zip also supports bzip2 compression if the bzip2 library
+is included when Zip is built. Note that PKUNZIP 1.10 cannot extract
+files produced by PKZIP 2.04 or Zip 3.0. You must use PKUNZIP 2.04g or
+UnZip 5.0p1 (or later versions) to extract them.
+.sk
+Large Archives and Zip64
+.sk
+Where the operating system and C run-time support allow, Zip 3.0 and
+UnZip 6.0 (and later versions) support large files (input and archive),
+using the Zip64 extensions to the original .ZIP file format. On VMS,
+this genarally means non-VAX systems with VMS V7.2 or later (perhaps
+requiring a C RTL ECO before VMS V7.3-2).
+.sk
+Zip automatically uses the Zip64 extensions when a file larger than 2 GB
+is added to an archive, an archive containing a Zip64 entry is updated
+(if the resulting archive still needs Zip64), the size of the archive
+will exceed 4 GB, or when the number of entries in the archive will
+exceed about 64K. Zip64 is also used for archives streamed to a
+non-seekable output device. You must use a 4.5 compatible UnZip to
+extract files using the Zip64 extensions such as UnZip 6.0 or later.
+.sk
+In addition, streamed archives, entries encrypted with standard
+encryption, or split archives created with the pause option may not be
+compatible with PKZIP as data descriptors are used, and PKZIP at the
+time of this writing does not support data descriptors (but recent
+changes in the PKWare published .ZIP file standard now include some
+support for the data descriptor format Zip uses).
+.!------------------------------------------------------------------------------
+.indent -4
+2 More_Usage
+.br
+Here is a very simple example of Zip use:
+.sk;.indent 10;
+$ zip stuff.zip *.*
+.sk
+This will create the Zip archive "stuff.zip" (assuming it does not
+already exist) and put all the (non-directory) files (";0") from the
+current default directory into "stuff.zip" in a compressed form. The
+archive is opened using a default file specification of
+"SYS$DISK:[].zip", so specifying "stuff" as the archive name would also
+create (or use an existing) "stuff.zip", but specifying "stuff.other"
+would give you that name. In general, Zip doesn't care about the type
+in the file specification, but for split archives (archives split over
+multiple files), the user should normally specify a type-less name,
+because Zip will normally generate sequentially numbered types ".z01",
+".z02", and so on for the early splits, and then the required ".zip" for
+the last split. These file types are required by the Zip standard for
+split archives.
+.sk
+Standard VMS wildcard expansion ($SEARCH) is used to interpret the
+"inpath" file and directory specifications, like the "*.*" in this
+example.
+.sk
+On VMS, the most natural way to archive an entire directory tree is to
+use a directory-depth wildcard ("[...]"). For example:
+.sk;.indent 10
+zip foo [...]*.*
+.sk
+This will create the file "foo.zip" containing all the files (";0") and
+directories in and below the current default directory. A more
+UNIX-like way to do this would be to use the -r (--recurse-paths)
+option:
+.sk;.indent 10
+$ zip -r foo *.*
+.sk
+Zip avoids including its own output files when selecting files to
+include in the archive, so it should be safe, as in this case, to create
+the archive in the same drectory as the input files.
+.sk
+One or more specific files, directories, or subdirectories may also be
+specified:
+.lm +10;.literal
+zip foo.zip readme.txt [www...]*.* [.ftp...]*.* -
+ [.src]*.h [.src]*.c
+.end literal;.lm -10
+.sk
+For security reasons, paths in Zip archives are always stored as
+relative paths, so some care is needed when creating an archive so that
+it will create the intended directory structure when UnZip is used to
+unpack it.
+.sk
+To use -r with a specific directory, the name of the directory file
+itself must be specified:
+.sk;.indent 10
+zip -r foo.zip [000000]www.dir ftp.dir
+.sk
+You may want to make an archive that contains the files in [.foo], but not
+record the directory name, "foo". You can use the -j (junk path) option
+to leave off the path:
+.sk;.indent 10
+$ zip -j foo [.foo]*.*
+.sk
+If you are short on disk space, you might not have enough room to hold
+both the original directory and the corresponding compressed Zip
+archive. In this case, you can create the archive in steps, and use the
+-m option. For example, if [.foo] contains the subdirectories [.tom],
+[.dick], and [.harry], you could:
+.sk
+.lm +10;.literal
+zip -m foo [.foo.tom...]*.*
+zip -m foo [.foo.dick...]*.*
+zip -m foo [.foo.harry...]*.*
+.end literal;.lm -10
+.sk
+The first command would create foo.zip, and the next two would add to
+it. The -m option means "move", and it will cause Zip to delete all
+files added to the archive after making or updating foo.zip. No
+deletions will be done until the Zip operation has completed with no
+errors. This option is obviously dangerous and should be used with
+care, but it does reduce the need for free disk space. When -m is
+used, the -T option is recommended and will test the resulting archive
+before deleting the input files.
+.sk
+If a file specification list is too long to fit conveniently on the Zip
+command line, the -@ option can be used to cause Zip to read a list of
+file specifications from SYS$INPUT (stdin). If a DCL command procedure
+is used, the names can be specified in the procedure:
+.sk;
+.lm +10;.literal
+$ zip foo -@
+$ deck
+file_spec_1
+file_spec_2
+file_spec_3
+$ eod
+.end literal;.lm -10
+.sk
+The file specifications can also be put into a separate file, and fed
+into Zip by explicitly defining SYS$INPUT, or by using PIPE. For
+example, with the list in foo.zfl:
+.sk;
+.lm +10;.literal
+$ define /user_mode sys$input foo.zfl
+$ zip foo -@
+.end literal;.lm -10;
+or:
+.lm +10;.literal
+$ pipe type foo.zfl | zip foo -@
+.end literal;.lm -10
+.sk
+If Zip is not able to read a file, it issues a warning but continues.
+See the -MM option for more on how Zip handles patterns that are not
+matched and files that are not readable. If some files were skipped, a
+warning is issued at the end of the Zip operation noting how many files
+were read and how many skipped.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Comments
+.br
+One-line comments may be included in the archive for each file added,
+using the -c (--entry-comments) option. File operations (adding,
+updating) are done first, and the user is then prompted for a one-line
+comment for each file added or updated. Enter the comment followed by
+<Return>, or just <Return> for no comment.
+.sk
+A single multi-line comment may be included for the archive as a whole,
+using the -z (--archive-comment) option. UnZip (including UnZip SFX)
+will display this comment when it expands the archive. The comment is
+read from SYS$INPUT (stdin), and is terminated by the usual end-of-file
+character, CTRL/Z. As usual, in a DCL command procedure, these data can
+be included in-line in the procedure, or a user may DEFINE SYS$INPUT to
+a file to get the comment from that file. Where supported, the DCL PIPE
+command can also be used to redirect SYS$INPUT from a file.
+.sk
+Note that -z (--archive-comment) and -@ (read file specifications from
+SYS$INPUT (stdin)) can't be used together (successfully).
+.!------------------------------------------------------------------------------
+.indent -4
+2 Compression
+.br
+Zip can archive files with or without compression. The standard
+compression method ("deflate") is compatible with all UnZip versions
+(except really old ones that only understand the "store" method).
+Current Zip and UnZip versions may be built with optional support for
+the bzip2 compression method. (The bzip2 method can compress better,
+especially when compressing smaller files, but uses more CPU time, and
+requires an UnZip which includes the optional bzip2 support. See the
+installation instructions for details on adding bzip2 compression
+support at build time.)
+.sk
+Numeric compression level options control the effort put into data
+compression, with -1 being the fastest, and -9 giving the most
+compression.
+.sk
+Compression control options:
+.sk;.lm +10;.literal
+-Z mthd use compress method "mthd",
+--compression-method mthd "bzip2" or "deflate" (default)
+
+-0 (--store) no compression
+-1 (--compress-1) compression level 1
+-2 (--compress-2) compression level 2
+-3 (--compress-3) compression level 3
+-4 (--compress-4) compression level 4
+-5 (--compress-5) compression level 5
+-6 (--compress-6) compression level 6
+-7 (--compress-7) compression level 7
+-8 (--compress-8) compression level 8
+-9 (--compress-9) compression level 9
+.end literal;.lm -10
+.sk
+Normally, a file which is already compressed will not be compressed much
+further (if at all) by Zip, and trying to do it can waste considerable
+CPU time. Zip can suppress compression on files with particular types,
+specified as a colon- or semi-colon-separated list of file types:
+.sk;.indent 10
+-n type1[:type2[...]] (--suffixes type1[:type2[...]])
+.sk
+For example:
+.sk;.indent 10
+zip -n .bz2:.gz:.jpeg:.jpg:.mp3:.zip foo [.foo]*.*
+.sk
+will put everything (";0") from [.foo] into foo.zip, but will store any
+files that end in .bz2, .gz, .jpeg, .jpg, .mp3, or .zip, without trying
+to compress them.
+.sk
+The default type list is .Z:.zip:.zoo:.arc:.lzh:.arj, and the comparison
+is case-insensitive.
+.sk
+-9 (--compress-9) will override -n (--suffixes), causing compression to
+be attempted for all files.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Encryption
+.br
+Zip offers optional encryption, using a method which by modern standards
+is generally considered to be weak.
+.sk;.literal
+-e --encrypt
+.end literal;.br
+Encrypt new or updated archive entries using a password which is
+supplied by the user interactively on the terminal in response to a
+prompt. (The password will not be echoed.) If SYS$COMMAND is not a
+terminal, Zip will exit with an error. The password is verified before
+being accepted.
+.sk;.literal
+-P password --password password
+.end literal;.br
+Use "password" to encrypt new or updated archive entries (if any).
+USING -P IS INSECURE! Many multi-user operating systems provide ways
+for any user (or a privileged user) to see the current command line of
+any other user. Even on more secure systems, there is always the threat
+of over-the-shoulder peeking. Storing the plaintext password as part of
+a command line in a command procedure is even less secure. Whenever
+possible, use the non-echoing, interactive password entry method.
+.sk
+Because standard Zip encryption is weak, where security is truly
+important, use a strong encryption program, such as Pretty Good Privacy
+(PGP) or GNU Privacy Guard (GnuPG), on an archive instead of standard
+Zip encryption. A stronger encryption method, such as AES, is planned
+for Zip 3.1.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Exit_Status
+.br
+On VMS, Zip's UNIX-style exit values are mapped into VMS-style status
+codes with facility code 1955 = %x7A3, and with the inhibit-message
+(%x10000000) and facility-specific (%x00008000) bits set:
+.sk
+.literal
+ %x17A38001 normal exit
+ %x17A38000+ 16* Zip_error_code warnings
+ %x17A38002+ 16* Zip_error_code normal errors
+ %x17A38004+ 16* Zip_error_code fatal errors
+.end literal
+.sk
+Note that multiplying the UNIX-style Zip error code by 16 places it
+conveniently in the hexadecimal representation of the VMS exit code,
+"__" in %x17A38__s, where "s" is the severity code. For example, a
+truncated archive might cause Zip error code 2, which would be
+transformed into the VMS exit status %x17A38024.
+.sk
+The Zip VMS exit codes include severity values which approximate those
+defined by PKWARE, as shown in the following table:
+.literal
+
+ VMS Zip err
+ severity code Error description
+ ----------+---------+----------------------------------------------
+ Success 0 Normal; no errors or warnings detected.
+ Fatal 2 Unexpected end of archive.
+ Error 3 A generic error in the archive format was
+ detected. Processing may have completed
+ successfully anyway; some broken archives
+ created by other archivers have simple work-
+ arounds.
+ Fatal 4 Zip was unable to allocate memory for one or
+ more buffers during program initialization.
+ Fatal 5 A severe error in the archive format was
+ detected. Processing probably failed imme-
+ diately.
+ Error 6 Entry too large to be split with zipsplit.
+ Error 7 Invalid comment format.
+ Fatal 8 Zip -T failed or out of memory.
+ Error 9 The user aborted zip prematurely with con-
+ trol-C (or equivalent).
+ Fatal 10 Zip encountered an error while using a temp
+ file.
+ Fatal 11 Read or seek error.
+ Warning 12 Zip has nothing to do.
+ Error 13 Missing or empty zip file.
+ Fatal 14 Error writing to a file.
+ Fatal 15 Zip was unable to create a file to write to.
+ Error 16 Bad command line parameters.
+ Error 18 Zip could not open a specified file to read.
+ Fatal 19 Zip was built with options not supported on
+ this system
+ Fatal 20 Attempt to read unsupported Zip64 archive
+.end literal
+.!------------------------------------------------------------------------------
+.indent -4
+2 Extra_Fields
+.br
+The .ZIP file format allows some extra data to be stored with a file in
+the archive. For example, where local time zone information is
+available, Zip can store UTC date-time data for files. (Look for
+USE_EF_UT_TIME in a "zip -v" report.) On VMS, with -V or -VV, Zip will
+also store VMS-specific file attributes. These data are packaged as
+"extra fields" in the archive. Some extra fields are specific to a
+particular operating system (like VMS file attributes). Large files
+(bigger than 4GB) on any OS require an extra field to hold their 64-bit
+size data. Depending on the capabilities of the UnZip program used to
+expand the archive, these extra fields may be used or ignored when files
+are extracted from the archive.
+.sk
+Some extra fields, like UTC date-times or VMS file attributes, are
+optional. Others, like the Zip64 extra field which holds 64-bit sizes
+for a large file, are required.
+.sk
+The -X (--strip-extra) option suppresses the saving of any optional
+extra fields in the archive. (Thus, -X conflicts with -V or -VV.)
+.!------------------------------------------------------------------------------
+.indent -4
+2 Environment
+.br
+A user can specify default command-line options and arguments by
+defining an "environment variable" (that is, a logical name or DCL
+symbol), "ZIP_OPTS" or "ZIPOPT", to specify them. If both "ZIP_OPTS" and
+"ZIPOPT" are specified, the definition of "ZIPOPT" prevails.
+.sk
+The C RTL function getenv() is used to sense these variables, so its
+behavior determines what happens if both a logical name and a symbol are
+defined. As of VMS V7.3, a logical name supercedes a symbol.
+.sk
+The "zip -v" report should show the perceived settings of these
+variables.
+.!------------------------------------------------------------------------------
+.indent -4
+2 File_Names
+.br
+Zip deals with file names in the system file system and with file names
+in Zip archives. File names in a Zip archive are stored in a UNIX-like
+path-name format. For example, a VMS file specification like this:
+.sk;.indent 10
+[.zip30.vms]descrip.mms
+.sk
+could appear in a Zip archive as:
+.sk;.indent 10
+zip30/vms/descrip.mms
+.sk
+For security reasons, paths in Zip archives are always stored as
+relative paths, so an absolute VMS directory specification will be
+transformed to a relative path in the archive (that is, no leading "/").
+For example, the following absolute directory specification would give
+the same archive path as the previous (relative) example:
+.sk;.indent 10
+[zip30.vms]descrip.mms
+.sk
+Also, device names are dropped, so the following file specification
+would also give the same archive path:
+.sk;.indent 10
+sys$sysdevice:[zip30.vms]descrip.mms
+.sk
+If an archive is intended for use with PKUNZIP under MSDOS, then the -k
+(for "Katz", --DOS-names) option should be used to attempt to adjust the
+names and paths to conform to MSDOS character-set and length
+limitations, to store only the MSDOS file attributes (just the
+owner:write attribute from VMS), and to mark the entry as made under
+MSDOS (even though it wasn't).
+.sk
+Note that file specifications in the file system must be specified using
+VMS notation, but file names in an archive must be specified using the
+UNIX-like notation used in the archive. For example, where a BACKUP
+command might look like this:
+.sk.indent 10
+$ back [.zip30...]*.* /excl = [...vms]*.c stuff.bck /save
+.sk
+a corresponding Zip command might look like this:
+.sk;.indent 10;
+$ zip stuff.zip [.zip30...]*.* -x */vms/*.c
+.sk
+because the files to be added to the Zip archive are specified using VMS
+file specifications, but the -x (--exclude) option excludes names based
+on their archive path/file names. Options dealing with archive names
+include -R (--recurse-patterns), -d (--delete), -i (--include), -x
+(--exclude), and -U (--copy-entries).
+.sk
+Note: By default, on VMS, archive name pattern matching (-R, -d, -i, -x,
+and -U) is case sensitive, even when the file system is not case
+sensitive (or even case preserving). This allows accurate matching of
+mixed-case names in an archive which may have been created on a system
+with a case sensitive file system, but it can involve extra effort on
+VMS, where it may be necessary to use unnatural case names (or the same
+names in multiple cases, like "*.obj *.OBJ") for this kind of pattern
+matching to give the desired behavior. If completely case-blind pattern
+matching behavior is desired, specify the -ic (--ignore-case) option.
+.!------------------------------------------------------------------------------
+.indent -4
+3 Case
+.br
+For better compatibility with UNIX-like systems, Zip, by default,
+down-cases ODS2 file names. For example, the following file on an ODS2
+file system:
+.sk;.indent 10
+[.ZIP30.VMS]DESCRIP.MMS
+.sk
+would appear in an archive as:
+.sk;.indent 10
+zip30/vms/descrip.mms
+.sk
+Zip versions before 3.0 down-cased all VMS file names. Now, various
+options give the user control over these conversions:
+.sk
+.lm +10;.literal
+-C preserve case of all file names
+-C- down-case all file names
+-C2 preserve case of ODS2 names
+-C2- down-case ODS2 file names (default)
+-C5 preserve case of ODS5 names (default)
+-C5- down-case ODS5 file names
+.end literal;.lm -10
+.sk
+Case is handled differently for archive member names, which the user
+specifies with the -R, -d, -i, -x, and -U options. By default, on VMS,
+archive name pattern matching is case sensitive, even when the file
+system is not case sensitive (or even case preserving). This allows
+accurate matching of mixed-case names in an archive which may have been
+created on a system with a case sensitive file system, but it can
+involve extra effort on VMS, where it may be necessary to use unnatural
+case names (or the same names in multiple cases, like "*.obj *.OBJ") for
+this kind of pattern matching to give the desired behavior. If
+completely case-blind pattern matching behavior is desired, specify the
+-ic (--ignore-case) option.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Fixing_Damage
+.br
+Two options can be used to fix a damaged Zip archive.
+.sk;.literal
+-F --fix
+-FF --fixfix
+.end literal;.sk
+The -F (--fix) option can be used if some portions of the archive are
+missing, but it requires a reasonably intact central directory. The
+input archive is scanned as usual, but zip will ignore some problems.
+The resulting archive should be valid, but any inconsistent entries
+will be left out.
+.sk
+If the archive is too damaged or the end (where the central directory is
+situated) has been truncated, you must use -FF (--fixfix). This is a
+change from zip 2.32, where the -F option is able to read a truncated
+archive. The -F option now more reliably fixes archives with minor
+damage, and the -FF option is needed to fix archives where -F and -FF
+was used before.
+.sk
+With -FF, the archive is scanned from the beginning and Zip scans for
+special signatures to identify the limits between the archive members.
+The -F option is more reliable if the archive is not too much damaged,
+so try this option first.
+.sk
+Neither option will recover archives that have been incorrectly
+transferred, such as by FTP in ASCII mode instead of binary. After the
+repair, the -t option of UnZip may show that some files have a bad CRC.
+Such files cannot be recovered; you can remove them from the archive
+using the -d option of Zip.
+.sk
+Because of the uncertainty of the "fixing" process, it's required
+to specify an output archive, rather than risking further damage to the
+original damaged archive. For example, to fix the damaged archive
+foo.zip,
+.sk;.indent 10
+zip -F foo --out foo_fix
+.sk
+tries to read the entries normally, copying good entries to the new
+archive foo_fix.zip. If this doesn't work, as when the archive is
+truncated, or if some entries are missed because of bad central
+directory entries, try -FF:
+.sk;.indent 10
+zip -FF foo --out foo_fixfix
+.sk
+and compare the resulting archive to the archive created using -F. The
+-FF option may create an inconsistent archive. Depending on what is
+damaged, you can then use the -F option to fix that archive.
+.sk
+A split archive with missing split files can be fixed using -F if you
+have the last split of the archive (the ".zip" file). If this file is
+missing, you must use -FF to fix the archive, which will prompt you for
+the splits you have.
+.sk
+Currently, the fix options can't recover an entry which has a bad
+checksum or is otherwise damaged.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Log_File
+.br
+Zip normally sends messages to the user's terminal, but these may be
+also directed to a log file.
+.sk;.literal
+-la --log-append
+.end literal;.br
+Append to an existing log file. Default is to create a new version.
+.sk;.literal
+-lf logfilepath --logfile-path logfilepath
+.end literal;.br
+Open a logfile at the given path. By default, a new version will be
+created, but with the -la option an existing file will be opened and the
+new log information appended to any existing information. Only
+warnings and errors are written to the log unless the -li option is also
+given, then all information messages are also written to the log.
+.sk;.literal
+-li --log-info
+.end literal;.br
+Include information messages, such as file names being zipped, in the
+log. The default is to include only the command line, any warnings
+and errors, and the final status.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Modes_of_Operation
+.br
+Zip supports two distinct types of command modes, external and
+internal. The external modes (update, grow, and freshen) read files
+from the file system (as well as from an existing archive) while the
+internal modes (delete and copy) operate exclusively on entries in an
+existing archive.
+.sk;.literal
+-u --update
+.end literal;.br
+Update existing entries and add new files. If the archive does not
+exist, create it. This is the default mode, so -u is optional.
+.sk;.literal
+-g --grow
+.end literal;.br
+Grow (append to) the specified Zip archive, instead of creating a new
+one. If this operation fails, Zip attempts to restore the archive to
+its original state. If the restoration fails, the archive might become
+corrupted. This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+.sk;.literal
+-f --freshen
+.end literal;.br
+Update existing entries in an existing archive. Does not add new files
+to the archive.
+.sk;.literal
+-d --delete
+.end literal;.br
+Delete entries from an existing archive.
+.sk;.literal
+-DF --difference-archive
+.end literal;.br
+Create an incremental backup-style archive, where the resulting archive
+will contain all new and changed files since the original archive was
+created. For this to work, the input file list and current directory
+must be the same as during the original Zip operation.
+.sk
+For example, if the existing archive was created using
+.sk;.indent 10
+zip foo_full.zip [.foo...]*.*
+.sk
+from just above the foo directory, then the command (also from just
+above the foo directory):
+.sk;.indent 10
+zip foo_full.zip [.foo...]*.* -DF -O foo_incr.zip
+.sk
+creates the archive foo_incr.zip with just the files not in foo_full.zip
+and the files where the size or date-time of the files does not match
+that in foo_full.zip. Note that in the "zip -DF" operation, the
+original full archive is specified as the input archive, and the -O
+(--output-file) option is used to specify the new (incremental) output
+archive.
+.sk;.literal
+-FS --filesync
+.end literal;.br
+Delete entries in the archive that do not match files on the OS.
+Normally when an archive is updated, new files are added and changed
+files are updated but files that no longer exist on the OS are not
+deleted from the archive. This option enables deleting of entries that
+are not matched on the OS. Enabling this option should create archives
+that are the same as new archives, but since existing entries are copied
+instead of compressed, updating an existing archive with -FS can be much
+faster than creating a new archive. If few files are being copied from
+the old archive, it may be faster to create a new archive instead.
+.sk
+This option deletes files from the archive. If you need to preserve the
+original archive, make a copy of the archive first, or use the -O
+(--output) option to output the new archive to a new file. Even though
+it's slower, creating a new archive with a new archive name is safer,
+avoids mismatches between archive and OS paths, and is preferred.
+.sk;.literal
+-U --copy-entries
+.end literal;.br
+Select entries in an existing archive and copy them to a new archive.
+Copy mode is like update mode, but entries in the existing archive are
+selected by command line patterns rather than files from the file system
+and it uses the -O (--output-file) option to write the resulting archive
+to a new file rather than updating the existing archive, leaving the
+original archive unchanged.
+.sk
+Normally, when updating an archive using relative file specifications
+("[]", "[.xxx]", and so on), it helps to have the same default directory
+as when the archive was created, but this is not a strict requirement.
+.sk
+Date-time information in a Zip archive may be influenced by time zone.
+.!------------------------------------------------------------------------------
+.indent -4
+3 Examples
+.br
+When given the name of an existing archive, Zip will replace identically
+named entries in the archive or add entries for new names. For example,
+if foo.zip exists and contains foo/file1 and foo/file2, and the
+directory [.foo] contains the files file1 and file3, then:
+.sk;.indent 10
+$ zip foo [.foo...]*.*
+.sk
+will replace foo/file1 in foo.zip and add foo/file3 to foo.zip. After
+this, foo.zip contains foo/file1, foo/file2, and foo/file3, with foo/file2
+unchanged from before. This is the default mode -u (update).
+.sk
+Update will add new entries to the archive and will replace
+existing entries only if the modified date of the file is more recent than
+the date recorded for that name in the archive. For example:
+.sk;.indent 10
+$ zip -u stuff *.*
+.sk
+will add any new files in the current directory, and update any changed
+files in the archive stuff.zip. Note that Zip will not try to pack
+stuff.zip into itself when you do this. Zip avoids including its own
+output files when selecting files to include in the archive, so it
+should be safe, as in this case, to have the archive included in the
+list of input files.
+.sk
+A second mode, -f (freshen), like update will only
+replace entries with newer files. Unlike update, however, it will not
+add files that are not already in the archive. For example:
+.sk;.indent 10
+$ zip -f foo
+.sk
+Note that the -f option with no arguments freshens all the entries in the
+archive. The same is true of -u, so "zip -u foo" and "zip -f foo" do
+the same thing.
+.sk
+When these options are used, Zip should be run from the same directory
+as when the original Zip command was run, so that the path names in the
+archive will continue to agree with the path names in the file system.
+Normally, it's also a good idea to keep the other options the same (-V,
+-w, and the like), to keep the archive contents consistent.
+.sk
+The -t (--from-date) and -tt (--before-date) options can also be used
+with adding, updating, or freshening to restrict further the files to be
+included in the archive. For example:
+.sk;.indent 10
+$ zip -rt 12071991 infamy [.FOO]*.*
+.sk
+will add all the files in [.FOO] and its subdirectories that were last
+modified on December 7, 1991, or later to the achive infamy.zip. Dates
+can be in format mmddyyyy or yyyy-mm-dd.
+.sk
+Also, files can be explicitly excluded using the -x option:
+.sk;.indent 10
+$ zip -r foo [.FOO] -x *.obj
+.sk
+which will zip up the contents of [.FOO] into foo.zip but exclude all the
+files that end in ".obj".
+.sk
+The -d (delete) mode will remove entries from an
+archive. An example might be:
+.sk;.indent 10
+$ zip -d foo foo/harry/*.* *.obj
+.sk
+which will remove all of the files that start with "foo/harry/" and all of
+the files that end with ".obj" (in any path).
+.sk
+The last mode, -U (--copy-entries), selects entries from an existing
+archive and copies them to a new archive.
+.sk;.indent 10
+$ zip -U foo *.obj --out fooobj
+.sk
+will copy all .obj entries from foo.zip and put them in the new archive
+fooobj.zip.
+.sk
+Note: By default, on VMS, archive name pattern matching (-R, -d, -i, -x,
+and -U) is case sensitive, even when the file system is not case
+sensitive (or even case preserving). This allows accurate matching of
+mixed-case names in an archive which may have been created on a system
+with a case sensitive file system, but it can involve extra effort on
+VMS, where it may be necessary to use unnatural case names (or the same
+names in multiple cases, like "*.obj *.OBJ") for this kind of pattern
+matching to give the desired behavior. If completely case-blind pattern
+matching behavior is desired, specify the -ic (--ignore-case) option.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Options_List
+.br
+"zip -h" provides a concise list of common command-line options. "zip
+-h2" provides more details. "zip -so" provides a list of all available
+options. "zip -v" shows the program version and available features.
+(The list below was derived from a "zip -so" listing.)
+.sk
+Short-form options begin with a single hyphen ("-"). Long-form option
+begin with a double hyphen ("--"), and may be abbreviated to any
+unambiguous shorter string. For example:
+.lm +10;.literal
+-v
+--verbose
+--verb
+.end literal;.lm -10
+.sk
+To avoid confusion, if a negatable option contains an embedded hyphen
+("-"), then avoid abbreviating it at the hyphen if you plan to negate
+it. For example, if an option like --some-option were abbreviated to
+--some-, the parser would consider that trailing hyphen to be part of
+the option name, rather than as a negating trailing hyphen. This
+behavior may change in the future, to interpret the trailing hyphen in
+--some- to be negating. (So don't do it.)
+.sk
+Some options may be negated (or modified) by appending a "-":
+.lm +10;.literal
+-la-
+--show-files-
+.end literal;.lm -10
+.sk
+Some options take a value, which may immediately follow the option, or
+be separated by a space or "=". For example:
+.lm +10;.literal
+-ttmmddyyyy
+-tt mmddyyyy
+-tt=mmddyyyy
+.end literal;.lm -10
+.sk
+.lm -4;.literal
+ Sh Long Description
+----+-------------------+--------------------------------------------------
+ 0 store store (instead of compress)
+ 1 compress-1 compress faster (-2, -3, -4, ...)
+ 9 compress-9 compress better
+ ? show the Zip help screen
+ @ names-stdin read input file patterns from SYS$INPUT (1/line)
+ A adjust-sfx adjust self-extracting executable
+ b temp-path path use "path" directory for temporary files
+ C preserve-case preserve case of all file names added to archive
+ C- preserve-case- down-case all file names added to archive
+ C2 preserve-case-2 preserve case of ODS2 names added to archive
+ C2- preserve-case-2- down-case ODS2 file added to archive (default)
+ C5 preserve-case-5 preserve case of ODS5 names added to archive (dflt)
+ C5- preserve-case-5- down-case ODS5 names added to archive
+ c entry-comments add a comment for each entry added to archive
+ D no-dir-entries do not add archive entries for directories
+ DF difference-archive difference archive: add only changed or new files
+ d delete delete entries in archive
+ db display-bytes display running byte counts
+ dc display-counts display running file counts
+ dd display-dots display progress dots for files (dflt size = 10MB)
+ dg display-globaldots display progress dots for archive, not each file
+ ds dot-size size set progress dot interval to "size" (MB)
+ du display-usize display original uncompressed size for entries
+ dv display-volume display volume (disk) number as in_disk>out_disk
+ e encrypt encrypt entries, ask for password
+ F fix fix mostly intact archive (try F before FF)
+ FF fixfix salvage what can be salvaged (not as reliable)
+ FS filesync remove archive entries unmatched in file system
+ f freshen update existing entries (only changed files)
+ fd force-descriptors force data descriptors as if streaming
+ fz force-zip64 force use of Zip64 format
+ g grow grow existing archive (unless updating or deleting)
+ H show the Zip help screen
+ h help show the Zip help screen
+ h2 more-help show extended Zip help
+ i include pat1 [pat2 [...]] include only names matching the patterns
+ ic ignore-case ignore case (case-blind archive entry name matching)
+ J junk-sfx junk (remove) archive preamble (unzipsfx)
+ j junk-paths junk (don't store) directory names, only file names
+ k DOS-names simulate PKZIP-made archive (DOS 8.3 names)
+ L license show software license
+ l to-crlf translate end-of-lines (LF -> CRLF)
+ la log-append append to existing log file
+ lf logfile-path lfile log to log file at lfile (default: new version)
+ li log-info include informational messages in log
+ ll from-crlf translate end-of-lines (CRLF -> LF)
+ MM must-match input file spec must exist (wildcards must match)
+ m move delete files added to archive
+ n suffixes sfx1[:sfx2[...]] don't compress files with these suffixes
+ nw no-wild no wildcards during add or update
+ O output-file ozf use "ozf" as the output archive (dflt = inp archive)
+ o latest-time set archive date-time to match oldest entry
+ P password password encrypt with supplied "password" string
+ q quiet quiet operation (no info messages)
+ R recurse-patterns recurse into subdirs from cur dir, match names only
+ r recurse-paths recurse into directories from specified path pats
+ s split-size size split archive at "size" (K/MB) (0: don't split)
+ sb split-bell ring terminal bell at pause for split medium change
+ sc show-command show command line
+ sd show-debug show debug messages
+ sf show-files show files to process (only)
+ so show-options show list of all command-line options
+ sp split-pause pause to select split destination(s)
+ sv split-verbose be verbose about creating splits
+ T test test archive integrity (runs UnZip -T)
+ t from-date mmddyyyy only do files since (at or after) "mmddyyyy"
+ tt before-date mmddyyyy only do files before "mmddyyyy"
+ u update update changed files, add new files (default mode)
+ V VMS-portable save VMS file attributes
+ VV VMS-specific save VMS file attributes and all allocated blocks
+ v verbose verbose messages (print version info if only arg)
+ w VMS-versions save VMS version numbers in archive
+ ww VMS-dot-versions save VMS version numbers as ".nnn", not ";nnn"
+ X strip-extra strip all but critical extra fields
+ X- strip-extra- keep all extra fields
+ x exclude pat1 [pat2 [...]] exclude all names matching the patterns
+ Z compression-method mthd use compress method "mthd" (bzip2 or deflate)
+ z archive-comment ask for archive comment
+.end literal;.lm +4
+.!------------------------------------------------------------------------------
+.indent -4
+2 Miscellaneous_Options
+.sk;.literal
+-D --no-dir-entries
+.end literal;.br
+Do not create entries in the archive for directories. By default,
+directory entries are added to an archive, so that their attributes can
+be saved in the archive. When an archive is created using -D, UnZip
+will still create directories as needed (subject to user control), but
+they will get the default attributes (date-time, permissions, ...) on
+the destination system, rather than their original atributes.
+.sk;.literal
+-MM --must-match
+.end literal;.br
+All input patterns must match at least one file and all input files
+found must be readable. Normally when an input pattern does not match
+a file the "name not matched" warning is issued and when an input
+file has been found but later is missing or not readable a "missing or
+not readable" warning is issued. In either case Zip continues
+creating the archive, with missing or unreadable new files being skipped
+and files already in the archive remaining unchanged. After the
+archive is created, if any files were not readable zip returns the OPEN
+error code (18 on most systems) instead of the normal success return (0
+on most systems). With -MM, Zip exits as soon as an input pattern
+is not matched (whenever the "name not matched" warning would be issued)
+or when an input file is not readable. In either case Zip exits with
+an OPEN error and no archive is created.
+.sk
+This option is useful when a known list of files is to be zipped so any
+missing or unreadable files should result in an error. It may be less
+useful when used with wildcards, but Zip will still exit with an error
+if any input pattern doesn't match at least one file or if any
+matched files are unreadable. If you want to create the archive anyway
+and only need to know if files were skipped, then don't use -MM and just
+check the exit status. Also, a log file (see -lf (--logfile-path))
+could be useful.
+.sk;.literal
+-O out_file --output-file out_file
+.end literal;.br
+Process the archive changes as usual, but instead of updating the
+existing archive, send the output to a new archive, "out_file". The
+output archive specified must be a different file from the input
+archive.
+.sk
+This option can be used to create updated split archives. It can
+also be used with -U to copy entries from an existing archive to
+a new archive. See the EXAMPLES section below.
+.sk
+Another use is converting zip files from one split size to
+another. For instance, to convert an archive with 700MB CD splits
+to one with 2GB DVD splits, can use:
+.sk;.indent 10
+zip -s 2g cd-split.zip --out dvd-split.zip
+.sk
+which uses copy mode. See -U below. Also:
+.sk;.indent 10
+zip -s 0 split.zip --out unsplit.zip
+.sk
+will convert a split archive to a single-file archive.
+.sk
+Copy mode will convert stream entries (using data descriptors and which
+may be incompatible with some unzip programs) to normal entries (which
+should be compatible with all unzip programs), except if standard
+encryption was used. For archives with encrypted entries, zipcloak
+will decrypt the entries and convert them to normal entries.
+.sk;.literal
+-o --latest-time
+.end literal;.br
+Set the modification date-time of the Zip archive file to the latest
+(newest) modification date-time found among the entries in the zip
+archive. This can be used without any other operations, if
+desired. For example:
+.sk;.indent 10
+zip -o foo
+.sk
+will change the modification date-time of foo.zip to the latest time of
+the entries in foo.zip.
+.sk;.literal
+-q --quiet
+.end literal;.br
+Quiet mode. Eliminates informational messages and comment prompts.
+This mode may be useful in command procedures, or if the Zip operation
+is being performed as a background task ("$ spawn/nowait zip -q foo
+*.c").
+.sk
+.sk;.literal
+-T --test
+.end literal;.br
+Test the integrity of a zip archive (the new one, if -O (--output-file)
+is specified). If the check fails, the old zip file is unchanged and
+(with the -m option) no input files are removed.
+.sk
+Implementation
+.br
+"zip -T" actually runs an "unzip -t" command to do the testing, so UnZip
+must be installed properly for this to work.
+.sk;.literal
+-TT unzip_cmd --unzip-command unzip_cmd
+.end literal;.br
+Specify the actual UnZip command, "unzip_cmd" (normally a DCL symbol) to
+use for "zip -T". This can be useful if multiple versions of UnZip are
+installed on a system, and the default DCL symbol "UNZIP" would run the
+wrong one (or the logical name DCL$PATH would lead to the wrong one).
+.sk
+In "unzip_cmd", the string "{}" is replaced by the temporary name of the
+archive to be tested, otherwise the name of the archive is appended
+to the end of the command. The exit status is checked for success severity.
+.sk;.literal
+-v --verbose
+.end literal;.br
+Verbose mode or print diagnostic version info.
+.sk
+Normally, when applied to real operations, this option enables the
+display of a progress indicator during compression (see -dd for more on
+dots) and requests verbose diagnostic info about archive structure
+oddities.
+.sk
+When -v is the only command line argument, a diagnostic report is
+displayed, showing:
+.lm +3;.br;.indent -2
+o Copyright and other legal notices
+.br;.indent -2
+o Program name, version, and release date
+.br;.indent -2
+o Pointers to Info-ZIP FTP and Web sites
+.br;.indent -2
+o Program build information (compiler type and version, OS version, and
+the compilation date
+.br;.indent -2
+o Optional features enabled at compile-time
+.br;.indent -2
+o Environment variable definitions (ZIP_OPTS, ZIPOPT)
+.lm -3;.br
+.sk
+This information should be included in bug reports.
+.sk;.literal
+-y --symlinks
+.end literal;.br
+Store symbolic links as such in the Zip archive, instead of compressing
+and storing the file referred to by the link. A symbolic link normally
+requires less storage than the actual file, both in the archive, and on
+the destination file system.
+.sk
+On VMS, symbolic links are supported on ODS5 disks where the C RTL
+supports symbolic links. Full support for symbolic links seems to
+require VMS V8.3, but a Zip program supporting symbolic links may be
+built on VMS V7.3-2.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Progress_Display
+.br
+Various options control the display of progress messages during Zip
+operation.
+.sk;.literal
+-db --display-bytes
+.end literal;.br
+Display running byte counts showing the bytes processed and the bytes to
+go.
+.sk;.literal
+-dc --display-counts
+.end literal;.br
+Display running count of entries processed and entries to go.
+.sk;.literal
+-dd --display-dots
+.end literal;.br
+Display dots while each entry is processed (except on ports that have
+their own progress indicator). See -ds below for setting dot size. The
+default is a dot every 10 MB of input file processed. The -v
+(--verbose) option also displays dots and used to at a higher rate than
+this (at the same rate as in previous versions of Zip) but this rate has
+been changed to the new 10 MB default, and is also controlled by -ds.
+.sk;.literal
+-dg --display-globaldots
+.end literal;.br
+Display progress dots for the archive instead of for each file. The
+command
+.sk;.indent 10
+zip -qdgds 10m
+.sk
+will turn off most output except dots every 10 MB.
+.sk;.literal
+-ds size --dot-size size
+.end literal;.br
+Set amount of input file processed for each dot displayed. See -dd to
+enable displaying dots. Setting this option implies -dd. "size" is in
+the format "nm" where n is a number and m is a multiplier. Currently
+"m" can be k (KB), m (MB), g (GB), or t (TB), so if "n" is 100 and "m"
+is k, "size" would be 100k which is 100KB. The default is 10MB.
+.sk
+The -v (--verbose) option also displays dots and used to default to a
+higher rate than this (at the same rate as in previous versions of Zip)
+but now the default is 10 MB and the -v dots are also controlled by this
+option. A "size" of 0 turns dots off.
+.sk
+This option does not control the dots from the "Scanning files" message
+as Zip scans for input files. The dot size for that is fixed at 2
+seconds or a fixed number of entries, whichever is longer.
+.sk;.literal
+-du --display-usize
+.end literal;.br
+Display the uncompressed size of each entry.
+.sk;.literal
+-dv --display-volume
+.end literal;.br
+Display the volume (disk) number each entry is being written to.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Self_Extracting_Archives
+.br
+A self-extracting archive (SFX) comprises a normal Zip archive appended
+to a special UnZip program (such as UNZIPSFX.EXE) for the intended
+target system.
+.sk
+The UnZip distribution includes a VMS command procedure,
+[,vms]makesfx.com, which can be used directly or adapted to create an
+SFX archive from a normal Zip archive.
+.sk
+The .ZIP file format includes offsets to data structures in the archive,
+and these offsets are measured from the start of the archive file.
+Appending an archive to an UnZip SFX executable effectively moves the
+start of the archive file. That makes the original offsets wrong, and
+that will cause the UnZip SFX program to emit warning messages when it
+tries to unpack the archive. Zip -A can be used to adjust these offsets
+in a self-extracting archive. For example, to adjust the offsets in
+foo.sfx_exe:
+.sk;.indent 10
+zip -A foo.sfx_exe
+.sk
+Similarly, the UnZip SFX program can be removed from a self-extracting
+archive (and the offsets in the archive restored) using the -J
+(--junk-sfx) option. For example:
+.sk;.indent 10
+zip -J foo.sfx_exe
+.sk
+Note that a self-extracting archive contains a normal Zip archive, and a
+normal UnZip program can be used to expand it in the normal way. You
+may get a warning about extra bytes at the beginning of the archive (the
+UnZip SFX program), but UnZip should work properly after that. This
+allows data in a self-extracting archive to be accessed on any system,
+not just the target system where its embedded UnZip SFX program runs.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Split_Archives
+.br
+Beginning with version 3.0, Zip supports split archives. A split
+archive is one which is divided into multiple files, usually to allow it
+to be stored on multiple storage media (floppy diskettes, CD-ROMs, or
+the like) when a single medium would be too small to contain the whole
+archive. (Note that split archives are not just unitary archives split
+into pieces, as the .ZIP file format includes offsets to data structures
+in the archive, and for a split archive these are based on the start of
+each split, not on the start of the whole archive. Concatenating the
+pieces will invalidate these offsets, but UnZip can usually deal with
+it. Zip will usually refuse to process such a spliced archive unless
+the -FF fix option is used to fix the offsets.)
+.sk
+For a split archive with, say, 20 split files, the files are typically
+named ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19, ARCHIVE.zip, where
+"ARCHIVE" is the archive name specified by the user on the Zip command
+line. Note that the last split file is the ".zip" file. In contrast,
+"spanned" archives are the original multi-disk archive generally
+requiring floppy disks and using volume labels to store disk numbers.
+Zip supports split archives but not spanned archives, though a procedure
+exists for converting split archives of the right size to spanned
+archives. The reverse is also true, where each file of a spanned
+archive can be copied in order to files with the above names to create a
+split archive.
+.!------------------------------------------------------------------------------
+.indent -4
+3 Options
+.br
+Use "-s size" to create a split archive (and to set the split size).
+The size is given as a number followed optionally by a multiplier suffix
+of k (KB), m (MB, the default if no suffix is specified), g (GB), or t
+(TB). (All are powers of 1024, not 1000). 64K is the minimum split
+size. For example, the following command could be used to create a
+split archive called "foo" from the contents of the "bar" directory with
+splits of 670MB, which might be useful for burning on CDs:
+.sk;.indent 10
+zip -s 670m foo [.bar...]*.*
+.sk
+Using -s without -sp as above creates all the splits in the directory
+specified by "foo", in this case the current default directory. This
+split mode updates the splits as the archive is being created, requiring
+all splits to remain writable, but creates split archives that are
+readable by any UnZip that supports split archives. See -sp below for
+enabling split pause mode which allows splits to be written directly to
+removable media.
+.sk
+The -sv option can be used to enable verbose splitting and display
+details of how the splitting is being done. The -sb option can be used
+to ring the terminal bell when Zip pauses for the next split
+destination.
+.sk
+The -sp option can be used to pause Zip between splits to allow
+changing removable media, for example, but read the descriptions and
+warnings for both -s and -sp below.
+.sk
+Though Zip does not update split archives, Zip provides the option
+-O (--output-file) to allow split archives to be updated and saved in a
+new archive. For example:
+.sk;.indent 10
+zip inarchive.zip foo.c bar.c -O outarchive.zip
+.sk
+reads archive inarchive.zip, even if split, adds the files foo.c and
+bar.c, and writes the resulting archive to outarchive.zip. If
+inarchive.zip is split, then outarchive.zip defaults to the same split
+size. Be aware that outarchive.zip and any split files that are created
+with it are always overwritten without warning. This may be changed in
+the future.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Temporary_Files
+.br
+When creating a new archive or normally when changing an existing
+archive, Zip will write a temporary file in the archive destination
+directory ("ZIxxxxxxxx", where "xxxxxxxx" is the hexadecimal process ID)
+with the new contents. Then, if and when the Zip job has completed with
+no errors, it will rename the temporary file to the specified archive
+name (replacing the old archive, if any).
+.sk
+You can use the -b (--temp-path) option to specify a different path
+(device and/or directory) for the temporary file, but specifying a
+different device will force Zip to copy the temporary file to its final
+destination instead of simply renaming it, and that copying will take
+more time than renaming, especially for a large archive. For example:
+.sk;.indent 10
+$ zip -b disk$scratch:[tmp] stuff *
+.sk
+will cause Zip to put its temporary files in the directory
+"disk$scratch:[tmp]", copying the temporary file back to the current
+directory as stuff.zip when it's complete.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Text_Files
+.br
+Zip offers some options to help deal with line endings in text files.
+These may have limited utility on VMS.
+.sk;.literal
+-l --to-crlf
+.end literal;.br
+Translate the UNIX end-of-line character LF (CR on MAC) into the MSDOS
+convention CR-LF. This option should not be used on binary files. This
+option can be used on UNIX if the Zip file is intended for PKUNZIP under
+MSDOS. If the input files already contain CR-LF, this option adds an
+extra CR. This ensure that "unzip -a" on Unix will get back an exact
+copy of the original file, to undo the effect of "zip -l". See -ll
+below for the binary checks.
+.sk;.literal
+-ll --from-crlf
+.end literal;.br
+Translate the MSDOS end-of-line CR LF into UNIX LF (CR on MAC). This
+option should not be used on binary files. This option can be used on
+MSDOS if the Zip archive is intended for UnZip under UNIX.
+.sk
+For both -l and -ll, if the file is converted and the file is later
+determined to be binary, a warning is issued and the file is probably
+corrupted. If Zip with -l or -ll detects binary (non-text) in the first
+buffer read from a file, it issues a warning and skips line-ending
+conversion on the file, avoiding corruption. This check seems to catch
+all binary files tested, but the original check remains and if a
+converted file is later determined to be binary, that warning is still
+issued. The algorithm now being used for binary detection should allow
+line-ending conversion of text files in UTF-8 and similar encodings.
+.!------------------------------------------------------------------------------
+.indent -4
+2 VMS_Specifics
+.br
+VMS File Attributes
+.sk;.literal
+-V --VMS-portable
+-VV --VMS-specific
+.end literal;.br
+The -V and -VV options cause Zip to store VMS file atributes (such as
+file organization, record format, carriage control, and so on) in
+VMS-specific "extra fields" in an archive along with the usual data.
+These extra fields are ignored on non-VMS systems, but on a VMS system,
+they allow UnZip to restore the files with their VMS attributes intact.
+.sk
+With -V, Zip ignores any data in the file after the end-of-file (EOF)
+point (defined by FAT$L_EFBLK and FAT$W_FFBYTE), which works well for
+well-formed files (that is, those with no valid data beyond EOF).
+Portable-format files (Stream_LF, fixed-512) archived with -V should be
+extracted properly on a non-VMS system. Files with more complex
+structures, such as indexed files and files with embedded byte counts
+or other such data may be of limited use on other systems. (UnZip on
+non-VMS systems may be able to extract various VMS-format text files,
+however.)
+.sk
+With -VV, Zip processes all allocated blocks for the file (including
+those beyond EOF). When extracted on a VMS system, the original file
+should be reproduced with as much fidelity as possible, but on a non-VMS
+system, most files will be seen as corrupt because of the data from
+beyond EOF.
+.sk
+VMS File Version Numbers
+.sk;.literal
+-w --VMS-versions
+-ww --VMS-dot-versions
+.end literal;.br
+By default, for compatibility with non-VMS systems, Zip strips VMS file
+version numbers from the names stored in an archive. The -w
+(--VMS-versions) option causes Zip to retain file version numbers on
+names in an archive. Without -w, a version number wildcard (";*") can
+cause errors when multiple versions of a single file are treated as
+multiple files with the same name.
+.sk
+For better compatibility with non-VMS systems where semi-colons are less
+popular in file names, the -ww (--VMS-dot-versions) option stores the
+file version numbers with a dot (".nnn") instead of a semi-colon
+(";nnn").
+.!------------------------------------------------------------------------------
+.indent -4
+2 Copyright_and_License
+.br
+Zip has an option to display its copyright and license.
+.sk;.literal
+-L --license
+.end literal;.br
+The license is reproduced below.
+.sk.lm +3
+This is version 2007-Mar-4 of the Info-ZIP license. The definitive
+version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and a copy
+at http://www.info-zip.org/pub/infozip/license.html.
+.lm -3;.sk
+--------------------------------------------------------
+.sk
+Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+.sk
+For the purposes of this copyright and license, "Info-ZIP" is defined as
+the following set of individuals:
+.sk;.lm +3
+ Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+ Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+ Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+ David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+ Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+ Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+ Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+ Rich Wales, Mike White.
+.lm -3;.sk
+This software is provided "as is," without warranty of any kind, express
+or implied. In no event shall Info-ZIP or its contributors be held
+liable for any direct, indirect, incidental, special or consequential
+damages arising out of the use of or inability to use this software.
+.sk
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the above disclaimer and the following restrictions:
+.sk;.lm +7;.indent -4
+ 1. Redistributions of source code (in whole or in part) must retain
+ the above copyright notice, definition, disclaimer, and this list
+ of conditions.
+.sk;.indent -4
+ 2. Redistributions in binary form (compiled executables and libraries)
+ must reproduce the above copyright notice, definition, disclaimer,
+ and this list of conditions in documentation and/or other materials
+ provided with the distribution. The sole exception to this condition
+ is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+ part of a self-extracting archive; that is permitted without inclusion
+ of this license, as long as the normal SFX banner has not been removed
+ from the binary or disabled.
+.sk;.indent -4
+ 3. Altered versions -- including, but not limited to, ports to new operating
+ systems, existing ports with new graphical interfaces, versions with
+ modified or added functionality, and dynamic, shared, or static library
+ versions not from Info-ZIP -- must be plainly marked as such and must not
+ be misrepresented as being the original source or, if binaries,
+ compiled from the original source. Such altered versions also must not
+ be misrepresented as being Info-ZIP releases -- including, but not
+ limited to, labeling of the altered versions with the names "Info-ZIP"
+ (or any variation thereof, including, but not limited to, different
+ capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the
+ explicit permission of Info-ZIP. Such altered versions are further
+ prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
+ e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
+ will provide support for the altered versions.
+.sk;.indent -4
+ 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip",
+ "UnZip", "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and
+ "MacZip" for its own source and binary releases.
+.lm -7;.sk
+.!------------------------------------------------------------------------------
+.indent -4
+2 Acknowledgements
+.br
+ Thanks to R. P. Byrne for his Shrink.Pas program, which
+ inspired this project, and from which the shrink algorithm
+ was stolen; to Phil Katz for placing in the public domain
+ the zip file format, compression format, and .ZIP filename
+ extension, and for accepting minor changes to the file
+ format; to Steve Burg for clarifications on the deflate
+ format; to Haruhiko Okumura and Leonid Broukhis for providing
+ some useful ideas for the compression algorithm; to
+ Keith Petersen, Rich Wales, Hunter Goatley and Mark Adler
+ for providing a mailing list and ftp site for the Info-ZIP
+ group to use; and most importantly, to the Info-ZIP group
+ itself (listed in the file infozip.who) without whose
+ tireless testing and bug-fixing efforts a portable zip
+ would not have been possible. Finally we should thank
+ (blame) the first Info-ZIP moderator, David Kirschbaum,
+ for getting us into this mess in the first place.
+.!------------------------------------------------------------------------------
+.indent -4
+2 Bugs
+.br
+All bug reports, patches, or suggestions should go to zip-bugs via the
+web site contact form at http://www.Info-ZIP.org. Patches should be
+sent as unified or context diffs only (diff -u or diff -c).
+.sk
+Any bug report should include the Zip version, any special compilation
+options (see "zip -v" report), the host system type and operating system
+version, and any other relevant information (compiler version, lunar
+phase, ...).
+.!------------------------------------------------------------------------------
diff --git a/vms/build_zip.com b/vms/build_zip.com
new file mode 100644
index 0000000..7bbe13d
--- /dev/null
+++ b/vms/build_zip.com
@@ -0,0 +1,690 @@
+$! BUILD_ZIP.COM
+$!
+$! Build procedure for VMS versions of Zip.
+$!
+$! last revised: 2007-03-15 SMS.
+$!
+$! Command arguments:
+$! - suppress help file processing: "NOHELP"
+$! - suppress message file processing: "NOMSG"
+$! - select link-only: "LINK"
+$! - select compiler environment: "VAXC", "DECC", "GNUC"
+$! - select large-file support: "LARGE"
+$! - select compiler listings: "LIST" Note that the whole argument
+$! is added to the compiler command, so more elaborate options
+$! like "LIST/SHOW=ALL" (quoted or space-free) may be specified.
+$! - supply additional compiler options: "CCOPTS=xxx" Allows the
+$! user to add compiler command options like /ARCHITECTURE or
+$! /[NO]OPTIMIZE. For example, CCOPTS=/ARCH=HOST/OPTI=TUNE=HOST
+$! or CCOPTS=/DEBUG/NOOPTI. These options must be quoted or
+$! space-free.
+$! - supply additional linker options: "LINKOPTS=xxx" Allows the
+$! user to add linker command options like /DEBUG or /MAP. For
+$! example: LINKOPTS=/DEBUG or LINKOPTS=/MAP/CROSS. These options
+$! must be quoted or space-free. Default is
+$! LINKOPTS=/NOTRACEBACK, but if the user specifies a LINKOPTS
+$! string, /NOTRACEBACK will not be included unless specified by
+$! the user.
+$! - select installation of CLI interface version of zip:
+$! "VMSCLI" or "CLI"
+$! - force installation of UNIX interface version of zip
+$! (override LOCAL_ZIP environment): "NOVMSCLI" or "NOCLI"
+$! - select BZIP2 support: "IZ_BZIP2=dev:[dir]", where "dev:[dir]"
+$! (or a suitable logical name) tells where to find "bzlib.h".
+$! The BZIP2 object library (LIBBZ2_NS.OLB) is expected to be in
+$! a "[.dest]" directory under that one ("dev:[dir.ALPHAL]", for
+$! example), or in that directory itself.
+$!
+$! To specify additional options, define the global symbol
+$! LOCAL_ZIP as a comma-separated list of the C macros to be
+$! defined, and then run BUILD_ZIP.COM. For example:
+$!
+$! $ LOCAL_ZIP == "VMS_IM_EXTRA"
+$! $ @ [.VMS]BUILD_ZIP.COM
+$!
+$! Valid VMS-specific options include VMS_PK_EXTRA and VMS_IM_EXTRA.
+$! See the INSTALL file for other options. (VMS_PK_EXTRA is the
+$! default.)
+$!
+$! If editing this procedure to set LOCAL_ZIP, be sure to use only
+$! one "=", to avoid affecting other procedures. For example:
+$! $ LOCAL_ZIP = "VMS_IM_EXTRA"
+$!
+$! Note: This command procedure always generates both the "default"
+$! Zip having the UNIX style command interface and the "VMSCLI" Zip
+$! having the CLI compatible command interface. There is no need to
+$! add "VMSCLI" to the LOCAL_ZIP symbol. (The only effect of
+$! "VMSCLI" now is the selection of the CLI style Zip executable in
+$! the foreign command definition.)
+$!
+$!
+$ on error then goto error
+$ on control_y then goto error
+$ OLD_VERIFY = f$verify( 0)
+$!
+$ edit := edit ! override customized edit commands
+$ say := write sys$output
+$!
+$!##################### Read settings from environment ########################
+$!
+$ if (f$type( LOCAL_ZIP) .eqs. "")
+$ then
+$ LOCAL_ZIP = ""
+$ else ! Trim blanks and append comma if missing
+$ LOCAL_ZIP = f$edit( LOCAL_ZIP, "TRIM")
+$ if (f$extract( f$length( LOCAL_ZIP)- 1, 1, LOCAL_ZIP) .nes. ",")
+$ then
+$ LOCAL_ZIP = LOCAL_ZIP + ","
+$ endif
+$ endif
+$!
+$! Check for the presence of "VMSCLI" in LOCAL_ZIP. If yes, we will
+$! define the foreign command for "zip" to use the executable
+$! containing the CLI interface.
+$!
+$ len_local_zip = f$length( LOCAL_ZIP)
+$!
+$ pos_cli = f$locate( "VMSCLI", LOCAL_ZIP)
+$ if (pos_cli .ne. len_local_zip)
+$ then
+$ CLI_IS_DEFAULT = 1
+$ ! Remove "VMSCLI" macro from LOCAL_ZIP. The Zip executable
+$ ! including the CLI interface is now created unconditionally.
+$ LOCAL_ZIP = f$extract( 0, pos_cli, LOCAL_ZIP)+ -
+ f$extract( pos_cli+7, len_local_zip- (pos_cli+ 7), LOCAL_ZIP)
+$ else
+$ CLI_IS_DEFAULT = 0
+$ endif
+$ delete /symbol /local pos_cli
+$!
+$! Check for the presence of "VMS_IM_EXTRA" in LOCAL_ZIP. If yes, we
+$! will (later) add "I" to the destination directory name.
+$!
+$ desti = ""
+$ pos_im = f$locate( "VMS_IM_EXTRA", LOCAL_ZIP)
+$ if (pos_im .ne. len_local_zip)
+$ then
+$ desti = "I"
+$ endif
+$!
+$ delete /symbol /local len_local_zip
+$!
+$!##################### Customizing section #############################
+$!
+$ zipx_unx = "ZIP"
+$ zipx_cli = "ZIP_CLI"
+$!
+$ CCOPTS = ""
+$ IZ_BZIP2 = ""
+$ LINKOPTS = "/notraceback"
+$ LINK_ONLY = 0
+$ LISTING = " /nolist"
+$ LARGE_FILE = 0
+$ MAKE_HELP = 1
+$ MAKE_MSG = 1
+$ MAY_USE_DECC = 1
+$ MAY_USE_GNUC = 0
+$!
+$! Process command line parameters requesting optional features.
+$!
+$ arg_cnt = 1
+$ argloop:
+$ current_arg_name = "P''arg_cnt'"
+$ curr_arg = f$edit( 'current_arg_name', "UPCASE")
+$ if (curr_arg .eqs. "") then goto argloop_out
+$!
+$ if (f$extract( 0, 5, curr_arg) .eqs. "CCOPT")
+$ then
+$ opts = f$edit( curr_arg, "COLLAPSE")
+$ eq = f$locate( "=", opts)
+$ CCOPTS = f$extract( (eq+ 1), 1000, opts)
+$ goto argloop_end
+$ endif
+$!
+$ if f$extract( 0, 7, curr_arg) .eqs. "IZ_BZIP"
+$ then
+$ opts = f$edit( curr_arg, "COLLAPSE")
+$ eq = f$locate( "=", opts)
+$ IZ_BZIP2 = f$extract( (eq+ 1), 1000, opts)
+$ goto argloop_end
+$ endif
+$!
+$ if (f$extract( 0, 5, curr_arg) .eqs. "LARGE")
+$ then
+$ LARGE_FILE = 1
+$ goto argloop_end
+$ endif
+$!
+$ if (f$extract( 0, 7, curr_arg) .eqs. "LINKOPT")
+$ then
+$ opts = f$edit( curr_arg, "COLLAPSE")
+$ eq = f$locate( "=", opts)
+$ LINKOPTS = f$extract( (eq+ 1), 1000, opts)
+$ goto argloop_end
+$ endif
+$!
+$! Note: LINK test must follow LINKOPTS test.
+$!
+$ if (f$extract( 0, 4, curr_arg) .eqs. "LINK")
+$ then
+$ LINK_ONLY = 1
+$ goto argloop_end
+$ endif
+$!
+$ if (f$extract( 0, 4, curr_arg) .eqs. "LIST")
+$ then
+$ LISTING = "/''curr_arg'" ! But see below for mods.
+$ goto argloop_end
+$ endif
+$!
+$ if (curr_arg .eqs. "NOHELP")
+$ then
+$ MAKE_HELP = 0
+$ goto argloop_end
+$ endif
+$!
+$ if (curr_arg .eqs. "NOMSG")
+$ then
+$ MAKE_MSG = 0
+$ goto argloop_end
+$ endif
+$!
+$ if (curr_arg .eqs. "VAXC")
+$ then
+$ MAY_USE_DECC = 0
+$ MAY_USE_GNUC = 0
+$ goto argloop_end
+$ endif
+$!
+$ if (curr_arg .eqs. "DECC")
+$ then
+$ MAY_USE_DECC = 1
+$ MAY_USE_GNUC = 0
+$ goto argloop_end
+$ endif
+$!
+$ if (curr_arg .eqs. "GNUC")
+$ then
+$ MAY_USE_DECC = 0
+$ MAY_USE_GNUC = 1
+$ goto argloop_end
+$ endif
+$!
+$ if ((curr_arg .eqs. "VMSCLI") .or. (curr_arg .eqs. "CLI"))
+$ then
+$ CLI_IS_DEFAULT = 1
+$ goto argloop_end
+$ endif
+$!
+$ if ((curr_arg .eqs. "NOVMSCLI") .or. (curr_arg .eqs. "NOCLI"))
+$ then
+$ CLI_IS_DEFAULT = 0
+$ goto argloop_end
+$ endif
+$!
+$ say "Unrecognized command-line option: ''curr_arg'"
+$ goto error
+$!
+$ argloop_end:
+$ arg_cnt = arg_cnt + 1
+$ goto argloop
+$ argloop_out:
+$!
+$ if (CLI_IS_DEFAULT)
+$ then
+$ ZIPEXEC = zipx_cli
+$ else
+$ ZIPEXEC = zipx_unx
+$ endif
+$!
+$!#######################################################################
+$!
+$! Find out current disk, directory, compiler and options
+$!
+$ workdir = f$environment( "default")
+$ here = f$parse( workdir, , , "device")+ f$parse( workdir, , , "directory")
+$!
+$! Sense the host architecture (Alpha, Itanium, or VAX).
+$!
+$ if (f$getsyi( "HW_MODEL") .lt. 1024)
+$ then
+$ arch = "VAX"
+$ else
+$ if (f$getsyi( "ARCH_TYPE") .eq. 2)
+$ then
+$ arch = "ALPHA"
+$ else
+$ if (f$getsyi( "ARCH_TYPE") .eq. 3)
+$ then
+$ arch = "IA64"
+$ else
+$ arch = "unknown_arch"
+$ endif
+$ endif
+$ endif
+$!
+$ dest = arch
+$ cmpl = "DEC/Compaq/HP C"
+$ opts = ""
+$ if (arch .nes. "VAX")
+$ then
+$ HAVE_DECC_VAX = 0
+$ USE_DECC_VAX = 0
+$!
+$ if (MAY_USE_GNUC)
+$ then
+$ say "GNU C is not supported for ''arch'."
+$ say "You must use DEC/Compaq/HP C to build Zip."
+$ goto error
+$ endif
+$!
+$ if (.not. MAY_USE_DECC)
+$ then
+$ say "VAX C is not supported for ''arch'."
+$ say "You must use DEC/Compaq/HP C to build Zip."
+$ goto error
+$ endif
+$!
+$ cc = "cc /standard = relax /prefix = all /ansi"
+$ defs = "''LOCAL_ZIP' VMS"
+$ if (LARGE_FILE .ne. 0)
+$ then
+$ defs = "LARGE_FILE_SUPPORT, ''defs'"
+$ endif
+$ else
+$ if (LARGE_FILE .ne. 0)
+$ then
+$ say "LARGE_FILE_SUPPORT is not available on VAX."
+$ LARGE_FILE = 0
+$ endif
+$ HAVE_DECC_VAX = (f$search( "SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "")
+$ HAVE_VAXC_VAX = (f$search( "SYS$SYSTEM:VAXC.EXE") .nes. "")
+$ MAY_HAVE_GNUC = (f$trnlnm( "GNU_CC") .nes. "")
+$ if (HAVE_DECC_VAX .and. MAY_USE_DECC)
+$ then
+$ ! We use DECC:
+$ USE_DECC_VAX = 1
+$ cc = "cc /decc /prefix = all"
+$ defs = "''LOCAL_ZIP' VMS"
+$ else
+$ ! We use VAXC (or GNU C):
+$ USE_DECC_VAX = 0
+$ defs = "''LOCAL_ZIP' VMS"
+$ if ((.not. HAVE_VAXC_VAX .and. MAY_HAVE_GNUC) .or. MAY_USE_GNUC)
+$ then
+$ cc = "gcc"
+$ opts = "GNU_CC:[000000]GCCLIB.OLB /LIBRARY,"
+$ dest = "''dest'G"
+$ cmpl = "GNU C"
+$ else
+$ if (HAVE_DECC_VAX)
+$ then
+$ cc = "cc /vaxc"
+$ else
+$ cc = "cc"
+$ endif
+$ dest = "''dest'V"
+$ cmpl = "VAC C"
+$ endif
+$ opts = "''opts' SYS$DISK:[.''dest']VAXCSHR.OPT /OPTIONS,"
+$ endif
+$ endif
+$!
+$! Change the destination directory, according to the VMS_IM_EXTRA and
+$! large-file options. Set the bzip2 directory.
+$!
+$ dest = dest+ desti
+$ seek_bz = arch
+$ if (LARGE_FILE .ne. 0)
+$ then
+$ dest = dest+ "L"
+$ seek_bz = seek_bz+ "L"
+$ endif
+$!
+$! If BZIP2 support was selected, find the object library.
+$! Complain if things fail.
+$!
+$ cc_incl = "[]"
+$ incl_bzip2_m = ""
+$ lib_bzip2_opts = ""
+$ if (IZ_BZIP2 .nes. "")
+$ then
+$ bz2_olb = "LIBBZ2_NS.OLB"
+$ define incl_bzip2 'IZ_BZIP2'
+$ defs = "''defs', BZIP2_SUPPORT"
+$ @ [.VMS]FIND_BZIP2_LIB.COM 'IZ_BZIP2' 'seek_bz' 'bz2_olb' lib_bzip2
+$ if (f$trnlnm( "lib_bzip2") .eqs. "")
+$ then
+$ say "Can't find BZIP2 object library. Can't link."
+$ goto error
+$ else
+$ say "BZIP2 dir = ''f$trnlnm( "lib_bzip2")'"
+$ incl_bzip2_m = ", ZBZ2ERR"
+$ lib_bzip2_opts = "lib_bzip2:''bz2_olb' /library, "
+$ cc_incl = cc_incl+ ", [.VMS]"
+$ endif
+$ endif
+$!
+$! Reveal the plan. If compiling, set some compiler options.
+$!
+$ if (LINK_ONLY)
+$ then
+$ say "Linking on ''arch' for ''cmpl'."
+$ else
+$ say "Compiling on ''arch' using ''cmpl'."
+$!
+$ DEF_UNX = "/define = (''defs')"
+$ DEF_CLI = "/define = (''defs', VMSCLI)"
+$ DEF_UTIL = "/define = (''defs', UTIL)"
+$ endif
+$!
+$! If [.'dest'] does not exist, either complain (link-only) or make it.
+$!
+$ if (f$search( "''dest'.DIR;1") .eqs. "")
+$ then
+$ if (LINK_ONLY)
+$ then
+$ say "Can't find directory ""[.''dest']"". Can't link."
+$ goto error
+$ else
+$ create /directory [.'dest']
+$ endif
+$ endif
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Arrange to get arch-specific list file placement, if LISTING, and if
+$! the user didn't specify a particular "/LIST =" destination.
+$!
+$ L = f$edit( LISTING, "COLLAPSE")
+$ if ((f$extract( 0, 5, L) .eqs. "/LIST") .and. -
+ (f$extract( 4, 1, L) .nes. "="))
+$ then
+$ LISTING = " /LIST = [.''dest']"+ f$extract( 5, 1000, LISTING)
+$ endif
+$!
+$! Define compiler command.
+$!
+$ cc = cc+ " /include = (''cc_incl')"+ LISTING+ CCOPTS
+$!
+$ endif
+$!
+$! Define linker command.
+$!
+$ link = "link ''LINKOPTS'"
+$!
+$! Make a VAXCRTL options file for GNU C or VAC C, if needed.
+$!
+$ if ((opts .nes. "") .and. -
+ (f$locate( "VAXCSHR", f$edit( opts, "UPCASE")) .lt. f$length( opts)) .and. -
+ (f$search( "[.''dest']VAXCSHR.OPT") .eqs. ""))
+$ then
+$ open /write opt_file_ln [.'dest']VAXCSHR.OPT
+$ write opt_file_ln "SYS$SHARE:VAXCRTL.EXE /SHARE"
+$ close opt_file_ln
+$ endif
+$!
+$! Show interesting facts.
+$!
+$ say " architecture = ''arch' (destination = [.''dest'])"
+$ if (.not. LINK_ONLY)
+$ then
+$ say " cc = ''cc'"
+$ endif
+$ say " link = ''link'"
+$ if (.not. MAKE_HELP)
+$ then
+$ say " Not making new help files."
+$ endif
+$ say ""
+$ if (.not. MAKE_MSG)
+$ then
+$ say " Not making new message files."
+$ endif
+$ say ""
+$!
+$ tmp = f$verify( 1) ! Turn echo on to see what's happening.
+$!
+$!-------------------------------- Zip section -------------------------------
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Process the help file, if desired.
+$!
+$ if (MAKE_HELP)
+$ then
+$ runoff /out = ZIP.HLP [.VMS]VMS_ZIP.RNH
+$ endif
+$!
+$! Process the message file, if desired.
+$!
+$ if (MAKE_MSG)
+$ then
+$!
+$! Create the message source file first, if it's not found.
+$!
+$ if (f$search( "[.VMS]ZIP_MSG.MSG") .eqs. "")
+$ then
+$ cc /include = [] /object = [.'dest']VMS_MSG_GEN.OBJ -
+ [.VMS]VMS_MSG_GEN.C
+$ link /executable = [.'dest']VMS_MSG_GEN.EXE -
+ [.'dest']VMS_MSG_GEN.OBJ
+$ create /fdl = [.VMS]STREAM_LF.FDL [.VMS]ZIP_MSG.MSG
+$ define /user_mode sys$output [.VMS]ZIP_MSG.MSG
+$ run [.'dest']VMS_MSG_GEN.EXE
+$ purge [.VMS]ZIP_MSG.MSG
+$ delete [.'dest']VMS_MSG_GEN.EXE;*, -
+ [.'dest']VMS_MSG_GEN.OBJ;*
+$ endif
+$!
+$ message /object = [.'dest']ZIP_MSG.OBJ /nosymbols -
+ [.VMS]ZIP_MSG.MSG
+$ link /shareable = [.'dest']ZIP_MSG.EXE [.'dest']ZIP_MSG.OBJ
+$ endif
+$!
+$! Compile the sources.
+$!
+$ cc 'DEF_UNX' /object = [.'dest']ZIP.OBJ ZIP.C
+$ cc 'DEF_UNX' /object = [.'dest']CRC32.OBJ CRC32.C
+$ cc 'DEF_UNX' /object = [.'dest']CRYPT.OBJ CRYPT.C
+$ cc 'DEF_UNX' /object = [.'dest']DEFLATE.OBJ DEFLATE.C
+$ cc 'DEF_UNX' /object = [.'dest']FILEIO.OBJ FILEIO.C
+$ cc 'DEF_UNX' /object = [.'dest']GLOBALS.OBJ GLOBALS.C
+$ cc 'DEF_UNX' /object = [.'dest']TREES.OBJ TREES.C
+$ cc 'DEF_UNX' /object = [.'dest']TTYIO.OBJ TTYIO.C
+$ cc 'DEF_UNX' /object = [.'dest']UTIL.OBJ UTIL.C
+$ cc 'DEF_UNX' /object = [.'dest']ZBZ2ERR.OBJ ZBZ2ERR.C
+$ cc 'DEF_UNX' /object = [.'dest']ZIPFILE.OBJ ZIPFILE.C
+$ cc 'DEF_UNX' /object = [.'dest']ZIPUP.OBJ ZIPUP.C
+$ cc /include = [] 'DEF_UNX' /object = [.'dest']VMS.OBJ -
+ [.VMS]VMS.C
+$ cc /include = [] 'DEF_UNX' /object = [.'dest']VMSMUNCH.OBJ -
+ [.VMS]VMSMUNCH.C
+$ cc /include = [] 'DEF_UNX' /object = [.'dest']VMSZIP.OBJ -
+ [.VMS]VMSZIP.C
+$!
+$! Create the object library.
+$!
+$ if (f$search( "[.''dest']ZIP.OLB") .eqs. "") then -
+ libr /object /create [.'dest']ZIP.OLB
+$!
+$ libr /object /replace [.'dest']ZIP.OLB -
+ [.'dest']CRC32.OBJ, -
+ [.'dest']CRYPT.OBJ, -
+ [.'dest']DEFLATE.OBJ, -
+ [.'dest']FILEIO.OBJ, -
+ [.'dest']GLOBALS.OBJ, -
+ [.'dest']TREES.OBJ, -
+ [.'dest']TTYIO.OBJ, -
+ [.'dest']UTIL.OBJ, -
+ [.'dest']ZBZ2ERR.OBJ, -
+ [.'dest']ZIPFILE.OBJ, -
+ [.'dest']ZIPUP.OBJ, -
+ [.'dest']VMS.OBJ, -
+ [.'dest']VMSMUNCH.OBJ, -
+ [.'dest']VMSZIP.OBJ
+$!
+$ endif
+$!
+$! Link the executable.
+$!
+$ link /executable = [.'dest']'ZIPX_UNX'.EXE -
+ [.'dest']ZIP.OBJ, -
+ [.'dest']ZIP.OLB /include = (GLOBALS 'incl_bzip2_m') /library, -
+ 'lib_bzip2_opts' -
+ 'opts' -
+ SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$!------------------------ Zip (CLI interface) section -----------------------
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Process the CLI help file, if desired.
+$!
+$ if (MAKE_HELP)
+$ then
+$ set default [.VMS]
+$ edit /tpu /nosection /nodisplay /command = cvthelp.tpu -
+ zip_cli.help
+$ set default [-]
+$ runoff /output = ZIP_CLI.HLP [.VMS]ZIP_CLI.RNH
+$ endif
+$!
+$! Compile the CLI sources.
+$!
+$ cc 'DEF_CLI' /object = [.'dest']ZIPCLI.OBJ ZIP.C
+$ cc /include = [] 'DEF_CLI' /object = [.'dest']CMDLINE.OBJ -
+ [.VMS]CMDLINE.C
+$!
+$! Create the command definition object file.
+$!
+$ set command /object = [.'dest']ZIP_CLI.OBJ [.VMS]ZIP_CLI.CLD
+$!
+$! Create the CLI object library.
+$!
+$ if (f$search( "[.''dest']ZIPCLI.OLB") .eqs. "") then -
+ libr /object /create [.'dest']ZIPCLI.OLB
+$!
+$ libr /object /replace [.'dest']ZIPCLI.OLB -
+ [.'dest']ZIPCLI.OBJ, -
+ [.'dest']CMDLINE.OBJ, -
+ [.'dest']ZIP_CLI.OBJ
+$!
+$ endif
+$!
+$! Link the CLI executable.
+$!
+$ link /executable = [.'dest']'ZIPX_CLI'.EXE -
+ [.'dest']ZIPCLI.OBJ, -
+ [.'dest']ZIPCLI.OLB /library, -
+ [.'dest']ZIP.OLB /include = (GLOBALS 'incl_bzip2_m') /library, -
+ 'lib_bzip2_opts' -
+ 'opts' -
+ SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$!--------------------------- Zip utilities section --------------------------
+$!
+$ if (.not. LINK_ONLY)
+$ then
+$!
+$! Compile the variant Zip utilities library sources.
+$!
+$ cc 'DEF_UTIL' /object = [.'dest']CRC32_.OBJ CRC32.C
+$ cc 'DEF_UTIL' /object = [.'dest']CRYPT_.OBJ CRYPT.C
+$ cc 'DEF_UTIL' /object = [.'dest']FILEIO_.OBJ FILEIO.C
+$ cc 'DEF_UTIL' /object = [.'dest']UTIL_.OBJ UTIL.C
+$ cc 'DEF_UTIL' /object = [.'dest']ZIPFILE_.OBJ ZIPFILE.C
+$ cc 'DEF_UTIL' /include = [] /object = [.'dest']VMS_.OBJ [.VMS]VMS.C
+$!
+$! Create the Zip utilities object library.
+$!
+$ if f$search( "[.''dest']ZIPUTILS.OLB") .eqs. "" then -
+ libr /object /create [.'dest']ZIPUTILS.OLB
+$!
+$ libr /object /replace [.'dest']ZIPUTILS.OLB -
+ [.'dest']CRC32_.OBJ, -
+ [.'dest']CRYPT_.OBJ, -
+ [.'dest']FILEIO_.OBJ, -
+ [.'dest']GLOBALS.OBJ, -
+ [.'dest']TTYIO.OBJ, -
+ [.'dest']UTIL_.OBJ, -
+ [.'dest']ZIPFILE_.OBJ, -
+ [.'dest']VMS_.OBJ, -
+ [.'dest']VMSMUNCH.OBJ
+$!
+$! Compile the Zip utilities main program sources.
+$!
+$ cc 'DEF_UTIL' /object = [.'dest']ZIPCLOAK.OBJ ZIPCLOAK.C
+$ cc 'DEF_UTIL' /object = [.'dest']ZIPNOTE.OBJ ZIPNOTE.C
+$ cc 'DEF_UTIL' /object = [.'dest']ZIPSPLIT.OBJ ZIPSPLIT.C
+$!
+$ endif
+$!
+$! Link the Zip utilities executables.
+$!
+$ link /executable = [.'dest']ZIPCLOAK.EXE -
+ [.'dest']ZIPCLOAK.OBJ, -
+ [.'dest']ZIPUTILS.OLB /include = (GLOBALS) /library, -
+ 'opts' -
+ SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$ link /executable = [.'dest']ZIPNOTE.EXE -
+ [.'dest']ZIPNOTE.OBJ, -
+ [.'dest']ZIPUTILS.OLB /include = (GLOBALS) /library, -
+ 'opts' -
+ SYS$DISK:[.VMS]ZIP.OPT /OPTIONS
+$!
+$ LINK /EXECUTABLE = [.'DEST']ZIPSPLIT.EXE -
+ [.'DEST']ZIPSPLIT.OBJ, -
+ [.'DEST']ZIPUTILS.OLB /INCLUDE = (globals) /LIBRARY, -
+ 'opts' -
+ SYS$DISK:[.VMS]ZIP.OPT /options
+$!
+$!----------------------- Logical name removal section -----------------------
+$!
+$ if (IZ_BZIP2 .nes. "")
+$ then
+$ if (f$trnlnm( "incl_bzip2", "LNM$PROCESS_TABLE") .nes. "")
+$ then
+$ deassign incl_bzip2
+$ endif
+$ if (f$trnlnm( "lib_bzip2", "LNM$PROCESS_TABLE") .nes. "")
+$ then
+$ deassign lib_bzip2
+$ endif
+$ endif
+$!
+$!------------------------------ Symbols section -----------------------------
+$!
+$ there = here- "]"+ ".''dest']"
+$!
+$! Define the foreign command symbols. Similar commands may be useful
+$! in SYS$MANAGER:SYLOGIN.COM and/or users' LOGIN.COM.
+$!
+$ zip == "$''there'''ZIPEXEC'.exe"
+$ zipcloak == "$''there'zipcloak.exe"
+$ zipnote == "$''there'zipnote.exe"
+$ zipsplit == "$''there'zipsplit.exe"
+$!
+$! Restore the original default directory and DCL verify status.
+$!
+$ error:
+$!
+$ if (f$type( here) .nes. "")
+$ then
+$ if (here .nes. "")
+$ then
+$ set default 'here'
+$ endif
+$ endif
+$!
+$ if (f$type( OLD_VERIFY) .nes. "")
+$ then
+$ tmp = f$verify( OLD_VERIFY)
+$ endif
+$!
+$ exit
+$!
diff --git a/vms/bzlib.h b/vms/bzlib.h
new file mode 100644
index 0000000..20488ea
--- /dev/null
+++ b/vms/bzlib.h
@@ -0,0 +1,21 @@
+/* 2007-01-13 SMS.
+ * VMS-specific BZLIB.H jacket header file to ensure compatibility with
+ * BZIP2 code compiled using /NAMES = AS_IS.
+ *
+ * The logical name INCL_BZIP2 must point to the BZIP2 source directory.
+ *
+ * A "names as_is" prototype for bz_internal_error() is included for the
+ * same reason. See bzip2 "bzlib_private.h". Note that this "names
+ * as_is" prototype must be the first to be read by the compiler, but
+ * one or more other prototypes (perhaps with the default "names"
+ * attributes) should cause no trouble.
+ */
+
+#pragma names save
+#pragma names as_is
+
+#include "INCL_BZIP2:BZLIB.H"
+
+extern void bz_internal_error ( int errcode );
+
+#pragma names restore
diff --git a/vms/cmdline.c b/vms/cmdline.c
new file mode 100644
index 0000000..9816bd5
--- /dev/null
+++ b/vms/cmdline.c
@@ -0,0 +1,1802 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/*
+ Test procedure:
+
+ Compile and link (in [.VMS] directory):
+
+ define vms SYS$DISK:[]
+ set command /object ZIP_CLI.CLD
+ cc /define = (TEST, VMSCLI) /include = [-] CMDLINE
+ link link CMDLINE.OBJ, ZIP_CLI.OBJ
+
+ Run:
+
+ exec*ute == "$SYS$DISK:[]'"
+ exec cmdline [options ...]
+
+*/
+
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# define module_name VMS_ZIP_CMDLINE
+# define module_ident "02-006"
+#endif /* 0 */
+
+/*
+**
+** Facility: ZIP
+**
+** Module: VMS_ZIP_CMDLINE
+**
+** Author: Hunter Goatley <goathunter@MadGoat.com>
+**
+** Date: July 30, 1993
+**
+** Abstract: Routines to handle a VMS CLI interface for Zip. The CLI
+** command line is parsed and a new argc/argv are built and
+** returned to Zip.
+**
+** Modified by:
+**
+** 02-007 Steven Schweda 09-FEB-2005
+** Added /PRESERVE_CASE.
+** 02-006 Onno van der Linden,
+** Christian Spieler 07-JUL-1998 23:03
+** Support GNU CC 2.8 on Alpha AXP (vers-num unchanged).
+** 02-006 Johnny Lee 25-JUN-1998 07:40
+** Fixed typo (superfluous ';') (vers-num unchanged).
+** 02-006 Christian Spieler 12-SEP-1997 23:17
+** Fixed bugs in /BEFORE and /SINCE handlers (vers-num unchanged).
+** 02-006 Christian Spieler 12-JUL-1997 02:05
+** Complete revision of the argv strings construction.
+** Added handling of "-P pwd", "-R", "-i@file", "-x@file" options.
+** 02-005 Patrick Ellis 09-MAY-1996 22:25
+** Show UNIX style help screen when UNIX style options are used.
+** 02-004 Onno van der Linden,
+** Christian Spieler 13-APR-1996 20:05
+** Removed /ENCRYPT=VERIFY ("-ee" option).
+** 02-003 Christian Spieler 11-FEB-1996 23:05
+** Added handling of /EXTRAFIELDS qualifier ("-X" option).
+** 02-002 Christian Spieler 09-JAN-1996 22:25
+** Added "#include crypt.h", corrected typo.
+** 02-001 Christian Spieler 04-DEC-1995 16:00
+** Fixed compilation in DEC CC's ANSI mode.
+** 02-000 Christian Spieler 10-OCT-1995 17:54
+** Modified for Zip v2.1, added several new options.
+** 01-000 Hunter Goatley 30-JUL-1993 07:54
+** Original version (for Zip v1.9p1).
+**
+*/
+
+
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# if defined(__DECC) || defined(__GNUC__)
+# pragma module module_name module_ident
+# else
+# module module_name module_ident
+# endif
+#endif /* 0 */
+
+/* Accomodation for /NAMES = AS_IS with old header files. */
+
+#define lib$establish LIB$ESTABLISH
+#define lib$get_foreign LIB$GET_FOREIGN
+#define lib$get_input LIB$GET_INPUT
+#define lib$sig_to_ret LIB$SIG_TO_RET
+#define ots$cvt_tu_l OTS$CVT_TU_L
+#define str$concat STR$CONCAT
+#define str$find_first_substring STR$FIND_FIRST_SUBSTRING
+#define str$free1_dx STR$FREE1_DX
+
+#include "zip.h"
+#ifndef TEST
+#include "crypt.h" /* for VMSCLI_help() */
+#include "revision.h" /* for VMSCLI_help() */
+#endif /* !TEST */
+
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include <clidef.h>
+#include <lib$routines.h>
+#include <ots$routines.h>
+#include <str$routines.h>
+
+#ifndef CLI$_COMMA
+globalvalue CLI$_COMMA;
+#endif
+
+/*
+** "Macro" to initialize a dynamic string descriptor.
+*/
+#define init_dyndesc(dsc) {\
+ dsc.dsc$w_length = 0;\
+ dsc.dsc$b_dtype = DSC$K_DTYPE_T;\
+ dsc.dsc$b_class = DSC$K_CLASS_D;\
+ dsc.dsc$a_pointer = NULL;}
+
+/*
+** Memory allocation step for argv string buffer.
+*/
+#define ARGBSIZE_UNIT 256
+
+/*
+** Memory reallocation macro for argv string buffer.
+*/
+#define CHECK_BUFFER_ALLOCATION(buf, reserved, requested) { \
+ if ((requested) > (reserved)) { \
+ char *save_buf = (buf); \
+ (reserved) += ARGBSIZE_UNIT; \
+ if (((buf) = (char *) realloc((buf), (reserved))) == NULL) { \
+ if (save_buf != NULL) free(save_buf); \
+ return (SS$_INSFMEM); \
+ } \
+ } \
+}
+
+/*
+** Define descriptors for all of the CLI parameters and qualifiers.
+*/
+$DESCRIPTOR(cli_delete, "DELETE"); /* -d */
+$DESCRIPTOR(cli_freshen, "FRESHEN"); /* -f */
+$DESCRIPTOR(cli_move, "MOVE"); /* -m */
+$DESCRIPTOR(cli_update, "UPDATE"); /* -u */
+$DESCRIPTOR(cli_exclude, "EXCLUDE"); /* -x */
+$DESCRIPTOR(cli_include, "INCLUDE"); /* -i */
+$DESCRIPTOR(cli_exlist, "EXLIST"); /* -x@ */
+$DESCRIPTOR(cli_inlist, "INLIST"); /* -i@ */
+$DESCRIPTOR(cli_adjust, "ADJUST_OFFSETS"); /* -A */
+$DESCRIPTOR(cli_append, "APPEND"); /* -g */
+$DESCRIPTOR(cli_batch, "BATCH"); /* -@ */
+$DESCRIPTOR(cli_before, "BEFORE"); /* -tt */
+$DESCRIPTOR(cli_comments, "COMMENTS"); /* -c,-z */
+$DESCRIPTOR(cli_comment_archive,"COMMENTS.ARCHIVE"); /* -z */
+$DESCRIPTOR(cli_comment_zipfile,"COMMENTS.ZIP_FILE"); /* -z */
+$DESCRIPTOR(cli_comment_files, "COMMENTS.FILES"); /* -c */
+$DESCRIPTOR(cli_compression, "COMPRESSION"); /* -Z */
+$DESCRIPTOR(cli_compression_b, "COMPRESSION.BZIP2"); /* -Zb */
+$DESCRIPTOR(cli_compression_d, "COMPRESSION.DEFLATE"); /* -Zd */
+$DESCRIPTOR(cli_compression_s, "COMPRESSION.STORE"); /* -Zs */
+$DESCRIPTOR(cli_copy_entries, "COPY_ENTRIES"); /* -U */
+$DESCRIPTOR(cli_descriptors, "DESCRIPTORS"); /* -fd */
+$DESCRIPTOR(cli_difference, "DIFFERENCE"); /* -DF */
+$DESCRIPTOR(cli_dirnames, "DIRNAMES"); /* -D */
+$DESCRIPTOR(cli_display, "DISPLAY"); /* -d? */
+$DESCRIPTOR(cli_display_bytes, "DISPLAY.BYTES"); /* -db */
+$DESCRIPTOR(cli_display_counts, "DISPLAY.COUNTS"); /* -dc */
+$DESCRIPTOR(cli_display_dots, "DISPLAY.DOTS"); /* -dd,-ds */
+$DESCRIPTOR(cli_display_globaldots, "DISPLAY.GLOBALDOTS"); /* -dg */
+$DESCRIPTOR(cli_display_usize, "DISPLAY.USIZE"); /* -du */
+$DESCRIPTOR(cli_display_volume, "DISPLAY.VOLUME"); /* -dv */
+$DESCRIPTOR(cli_dot_version, "DOT_VERSION"); /* -ww */
+$DESCRIPTOR(cli_encrypt, "ENCRYPT"); /* -e,-P */
+$DESCRIPTOR(cli_extra_fields, "EXTRA_FIELDS"); /* -X [/NO] */
+$DESCRIPTOR(cli_extra_fields_normal, "EXTRA_FIELDS.NORMAL"); /* no -X */
+$DESCRIPTOR(cli_extra_fields_keep, "EXTRA_FIELDS.KEEP_EXISTING"); /* -X- */
+$DESCRIPTOR(cli_filesync, "FILESYNC"); /* -FS */
+$DESCRIPTOR(cli_fix_archive, "FIX_ARCHIVE"); /* -F[F] */
+$DESCRIPTOR(cli_fix_normal, "FIX_ARCHIVE.NORMAL"); /* -F */
+$DESCRIPTOR(cli_fix_full, "FIX_ARCHIVE.FULL"); /* -FF */
+$DESCRIPTOR(cli_full_path, "FULL_PATH"); /* -p */
+$DESCRIPTOR(cli_grow, "GROW"); /* -g */
+$DESCRIPTOR(cli_help, "HELP"); /* -h */
+$DESCRIPTOR(cli_help_normal, "HELP.NORMAL"); /* -h */
+$DESCRIPTOR(cli_help_extended, "HELP.EXTENDED"); /* -h2 */
+$DESCRIPTOR(cli_junk, "JUNK"); /* -j */
+$DESCRIPTOR(cli_keep_version, "KEEP_VERSION"); /* -w */
+$DESCRIPTOR(cli_latest, "LATEST"); /* -o */
+$DESCRIPTOR(cli_level, "LEVEL"); /* -[0-9] */
+$DESCRIPTOR(cli_license, "LICENSE"); /* -L */
+$DESCRIPTOR(cli_log_file, "LOG_FILE"); /* -la,-lf,-li */
+$DESCRIPTOR(cli_log_file_append, "LOG_FILE.APPEND"); /* -la */
+$DESCRIPTOR(cli_log_file_file, "LOG_FILE.FILE"); /* -lf */
+$DESCRIPTOR(cli_log_file_info, "LOG_FILE.INFORMATIONAL"); /* -li */
+$DESCRIPTOR(cli_must_match, "MUST_MATCH"); /* -MM */
+$DESCRIPTOR(cli_output, "OUTPUT"); /* -O */
+$DESCRIPTOR(cli_patt_case, "PATTERN_CASE"); /* -ic[-] */
+$DESCRIPTOR(cli_patt_case_blind, "PATTERN_CASE.BLIND"); /* -ic */
+$DESCRIPTOR(cli_patt_case_sensitive, "PATTERN_CASE.SENSITIVE"); /* -ic- */
+$DESCRIPTOR(cli_pkzip, "PKZIP"); /* -k */
+$DESCRIPTOR(cli_pres_case, "PRESERVE_CASE"); /* -C */
+$DESCRIPTOR(cli_pres_case_no2, "PRESERVE_CASE.NOODS2");/* -C2- */
+$DESCRIPTOR(cli_pres_case_no5, "PRESERVE_CASE.NOODS5");/* -C5- */
+$DESCRIPTOR(cli_pres_case_ods2, "PRESERVE_CASE.ODS2"); /* -C2 */
+$DESCRIPTOR(cli_pres_case_ods5, "PRESERVE_CASE.ODS5"); /* -C5 */
+$DESCRIPTOR(cli_quiet, "QUIET"); /* -q */
+$DESCRIPTOR(cli_recurse, "RECURSE"); /* -r,-R */
+$DESCRIPTOR(cli_recurse_path, "RECURSE.PATH"); /* -r */
+$DESCRIPTOR(cli_recurse_fnames, "RECURSE.FILENAMES"); /* -R */
+$DESCRIPTOR(cli_show, "SHOW"); /* -s? */
+$DESCRIPTOR(cli_show_command, "SHOW.COMMAND"); /* -sc */
+$DESCRIPTOR(cli_show_debug, "SHOW.DEBUG"); /* -sd */
+$DESCRIPTOR(cli_show_files, "SHOW.FILES"); /* -sf */
+$DESCRIPTOR(cli_show_options, "SHOW.OPTIONS"); /* -so */
+$DESCRIPTOR(cli_since, "SINCE"); /* -t */
+$DESCRIPTOR(cli_split, "SPLIT"); /* -s,-sb,-sp,-sv */
+$DESCRIPTOR(cli_split_bell, "SPLIT.BELL"); /* -sb */
+$DESCRIPTOR(cli_split_pause, "SPLIT.PAUSE"); /* -sp */
+$DESCRIPTOR(cli_split_size, "SPLIT.SIZE"); /* -s */
+$DESCRIPTOR(cli_split_verbose, "SPLIT.VERBOSE"); /* -sv */
+$DESCRIPTOR(cli_store_types, "STORE_TYPES"); /* -n */
+$DESCRIPTOR(cli_sverbose, "SVERBOSE"); /* -sv */
+$DESCRIPTOR(cli_symlinks, "SYMLINKS"); /* -y */
+$DESCRIPTOR(cli_temp_path, "TEMP_PATH"); /* -b */
+$DESCRIPTOR(cli_test, "TEST"); /* -T */
+$DESCRIPTOR(cli_test_unzip, "TEST.UNZIP"); /* -TT */
+$DESCRIPTOR(cli_translate_eol, "TRANSLATE_EOL"); /* -l[l] */
+$DESCRIPTOR(cli_transl_eol_lf, "TRANSLATE_EOL.LF"); /* -l */
+$DESCRIPTOR(cli_transl_eol_crlf,"TRANSLATE_EOL.CRLF"); /* -ll */
+$DESCRIPTOR(cli_unsfx, "UNSFX"); /* -J */
+$DESCRIPTOR(cli_verbose, "VERBOSE"); /* -v (?) */
+$DESCRIPTOR(cli_verbose_normal, "VERBOSE.NORMAL"); /* -v */
+$DESCRIPTOR(cli_verbose_more, "VERBOSE.MORE"); /* -vv */
+$DESCRIPTOR(cli_verbose_debug, "VERBOSE.DEBUG"); /* -vvv */
+$DESCRIPTOR(cli_verbose_command,"VERBOSE.COMMAND"); /* (none) */
+$DESCRIPTOR(cli_vms, "VMS"); /* -V */
+$DESCRIPTOR(cli_vms_all, "VMS.ALL"); /* -VV */
+$DESCRIPTOR(cli_wildcard, "WILDCARD"); /* -nw */
+$DESCRIPTOR(cli_wildcard_nospan,"WILDCARD.NOSPAN"); /* -W */
+
+$DESCRIPTOR(cli_yyz, "YYZ_ZIP");
+
+$DESCRIPTOR(cli_zip64, "ZIP64"); /* -fz */
+$DESCRIPTOR(cli_zipfile, "ZIPFILE");
+$DESCRIPTOR(cli_infile, "INFILE");
+$DESCRIPTOR(zip_command, "zip ");
+
+static int show_VMSCLI_help;
+
+#if !defined(zip_clitable)
+# define zip_clitable ZIP_CLITABLE
+#endif
+#if defined(__DECC) || defined(__GNUC__)
+extern void *zip_clitable;
+#else
+globalref void *zip_clitable;
+#endif
+
+/* extern unsigned long LIB$GET_INPUT(void), LIB$SIG_TO_RET(void); */
+
+#ifndef __STARLET_LOADED
+#ifndef sys$bintim
+# define sys$bintim SYS$BINTIM
+#endif
+#ifndef sys$numtim
+# define sys$numtim SYS$NUMTIM
+#endif
+extern int sys$bintim ();
+extern int sys$numtim ();
+#endif /* !__STARLET_LOADED */
+#ifndef cli$dcl_parse
+# define cli$dcl_parse CLI$DCL_PARSE
+#endif
+#ifndef cli$present
+# define cli$present CLI$PRESENT
+#endif
+#ifndef cli$get_value
+# define cli$get_value CLI$GET_VALUE
+#endif
+extern unsigned long cli$dcl_parse ();
+extern unsigned long cli$present ();
+extern unsigned long cli$get_value ();
+
+unsigned long vms_zip_cmdline (int *, char ***);
+static unsigned long get_list (struct dsc$descriptor_s *,
+ struct dsc$descriptor_d *, int,
+ char **, unsigned long *, unsigned long *);
+static unsigned long get_time (struct dsc$descriptor_s *qual, char *timearg);
+static unsigned long check_cli (struct dsc$descriptor_s *);
+static int verbose_command = 0;
+
+
+#ifdef TEST
+
+char errbuf[ FNMAX+ 81]; /* Error message buffer. */
+
+void ziperr( int c, char *h) /* Error message display function. */
+{
+/* int c: error code from the ZE_ class */
+/* char *h: message about how it happened */
+
+printf( "%d: %s\n", c, h);
+}
+
+int
+main(int argc, char **argv) /* Main program. */
+{
+ return (vms_zip_cmdline(&argc, &argv));
+}
+
+#endif /* def TEST */
+
+
+unsigned long
+vms_zip_cmdline (int *argc_p, char ***argv_p)
+{
+/*
+** Routine: vms_zip_cmdline
+**
+** Function:
+**
+** Parse the DCL command line and create a fake argv array to be
+** handed off to Zip.
+**
+** NOTE: the argv[] is built as we go, so all the parameters are
+** checked in the appropriate order!!
+**
+** Formal parameters:
+**
+** argc_p - Address of int to receive the new argc
+** argv_p - Address of char ** to receive the argv address
+**
+** Calling sequence:
+**
+** status = vms_zip_cmdline (&argc, &argv);
+**
+** Returns:
+**
+** SS$_NORMAL - Success.
+** SS$_INSFMEM - A malloc() or realloc() failed
+** SS$_ABORT - Bad time value
+**
+*/
+ register unsigned long status;
+ char options[ 64];
+ char *the_cmd_line; /* buffer for argv strings */
+ unsigned long cmdl_size; /* allocated size of buffer */
+ unsigned long cmdl_len; /* used size of buffer */
+ char *ptr;
+ int x, len;
+
+ int new_argc;
+ char **new_argv;
+
+ struct dsc$descriptor_d work_str;
+ struct dsc$descriptor_d foreign_cmdline;
+
+ init_dyndesc(work_str);
+ init_dyndesc(foreign_cmdline);
+
+ /*
+ ** See if the program was invoked by the CLI (SET COMMAND) or by
+ ** a foreign command definition. Check for /YYZ_ZIP, which is a
+ ** valid default qualifier solely for this test.
+ */
+ show_VMSCLI_help = TRUE;
+ status = check_cli(&cli_yyz);
+ if (!(status & 1)) {
+ lib$get_foreign(&foreign_cmdline);
+ /*
+ ** If nothing was returned or the first character is a "-", then
+ ** assume it's a UNIX-style command and return.
+ */
+ if (foreign_cmdline.dsc$w_length == 0)
+ return (SS$_NORMAL);
+ if ((*(foreign_cmdline.dsc$a_pointer) == '-') ||
+ ((foreign_cmdline.dsc$w_length > 1) &&
+ (*(foreign_cmdline.dsc$a_pointer) == '"') &&
+ (*(foreign_cmdline.dsc$a_pointer + 1) == '-'))) {
+ show_VMSCLI_help = FALSE;
+ return (SS$_NORMAL);
+ }
+
+ str$concat(&work_str, &zip_command, &foreign_cmdline);
+ status = cli$dcl_parse(&work_str, &zip_clitable, lib$get_input,
+ lib$get_input, 0);
+ if (!(status & 1)) return (status);
+ }
+
+ /*
+ ** There's always going to be a new_argv[] because of the image name.
+ */
+ if ((the_cmd_line = (char *) malloc(cmdl_size = ARGBSIZE_UNIT)) == NULL)
+ return (SS$_INSFMEM);
+
+ strcpy(the_cmd_line, "zip");
+ cmdl_len = sizeof("zip");
+
+ /*
+ ** First, check to see if any of the regular options were specified.
+ */
+
+ options[0] = '-';
+ ptr = &options[1]; /* Point to temporary buffer */
+
+ /*
+ ** Copy entries.
+ */
+ status = cli$present(&cli_copy_entries);
+ if (status & 1)
+ /* /COPY_ENTRIES */
+ *ptr++ = 'U';
+
+ /*
+ ** Delete the specified files from the zip file?
+ */
+ status = cli$present(&cli_delete);
+ if (status & 1)
+ /* /DELETE */
+ *ptr++ = 'd';
+
+ /*
+ ** Freshen (only changed files).
+ */
+ status = cli$present(&cli_freshen);
+ if (status & 1)
+ /* /FRESHEN */
+ *ptr++ = 'f';
+
+ /*
+ ** Delete the files once they've been added to the zip file.
+ */
+ status = cli$present(&cli_move);
+ if (status & 1)
+ /* /MOVE */
+ *ptr++ = 'm';
+
+ /*
+ ** Add changed and new files.
+ */
+ status = cli$present(&cli_update);
+ if (status & 1)
+ /* /UPDATE */
+ *ptr++ = 'u';
+
+ /*
+ ** Check for the compression level (-0 through -9).
+ */
+ status = cli$present(&cli_level);
+ if (status & 1) {
+ /* /LEVEL = value */
+
+ unsigned long binval;
+
+ status = cli$get_value(&cli_level, &work_str);
+ status = ots$cvt_tu_l(&work_str, &binval);
+ if (!(status & 1) || (binval > 9)) {
+ return (SS$_ABORT);
+ }
+ *ptr++ = binval + '0';
+ }
+
+ /*
+ ** Adjust offsets of zip archive entries.
+ */
+ status = cli$present(&cli_adjust);
+ if (status & 1)
+ /* /ADJUST_OFFSETS */
+ *ptr++ = 'A';
+
+ /*
+ ** Add comments?
+ */
+ status = cli$present(&cli_comments);
+ if (status & 1)
+ {
+ int archive_or_zip_file = 0;
+
+ if ((status = cli$present(&cli_comment_archive)) & 1)
+ /* /COMMENTS = ARCHIVE */
+ archive_or_zip_file = 1;
+ if ((status = cli$present(&cli_comment_zipfile)) & 1)
+ /* /COMMENTS = ZIP_FILE */
+ archive_or_zip_file = 1;
+ if (archive_or_zip_file != 0)
+ /* /COMMENTS = ARCHIVE */
+ *ptr++ = 'z';
+ if ((status = cli$present(&cli_comment_files)) & 1)
+ /* /COMMENTS = FILES */
+ *ptr++ = 'c';
+ }
+
+ /*
+ ** Preserve case in file names.
+ */
+#define OPT_C "-C" /* Preserve case all. */
+#define OPT_CN "-C-" /* Down-case all. */
+#define OPT_C2 "-C2" /* Preserve case ODS2. */
+#define OPT_C2N "-C2-" /* Down-case ODS2. */
+#define OPT_C5 "-C5" /* Preserve case ODS5. */
+#define OPT_C5N "-C5-" /* Down-case ODS5. */
+
+ status = cli$present( &cli_pres_case);
+ if ((status & 1) || (status == CLI$_NEGATED))
+ {
+ /* /[NO]PRESERVE_CASE */
+ char *opt;
+ int ods2 = 0;
+ int ods5 = 0;
+
+ if (status == CLI$_NEGATED)
+ {
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_CN)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_CN);
+ }
+ else
+ {
+ if (cli$present( &cli_pres_case_no2) & 1)
+ {
+ /* /PRESERVE_CASE = NOODS2 */
+ ods2 = -1;
+ }
+ if (cli$present( &cli_pres_case_no5) & 1)
+ {
+ /* /PRESERVE_CASE = NOODS5 */
+ ods5 = -1;
+ }
+ if (cli$present( &cli_pres_case_ods2) & 1)
+ {
+ /* /PRESERVE_CASE = ODS2 */
+ ods2 = 1;
+ }
+ if (cli$present( &cli_pres_case_ods5) & 1)
+ {
+ /* /PRESERVE_CASE = ODS5 */
+ ods5 = 1;
+ }
+
+ if (ods2 == ods5)
+ {
+ /* Plain "-C[-]". */
+ if (ods2 < 0)
+ opt = OPT_CN;
+ else
+ opt = OPT_C;
+
+ x = cmdl_len;
+ cmdl_len += strlen( opt)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], opt);
+ }
+ else
+ {
+ if (ods2 != 0)
+ {
+ /* "-C2[-]". */
+ if (ods2 < 0)
+ opt = OPT_C2N;
+ else
+ opt = OPT_C2;
+
+ x = cmdl_len;
+ cmdl_len += strlen( opt)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], opt);
+ }
+
+ if (ods5 != 0)
+ {
+ /* "-C5[-]". */
+ if (ods5 < 0)
+ opt = OPT_C5N;
+ else
+ opt = OPT_C5;
+
+ x = cmdl_len;
+ cmdl_len += strlen( opt)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], opt);
+ }
+ }
+ }
+ }
+
+ /*
+ ** Pattern case sensitivity.
+ */
+#define OPT_IC "-ic" /* Case-insensitive pattern matching. */
+#define OPT_ICN "-ic-" /* Case-sensitive pattern matching. */
+
+ status = cli$present( &cli_patt_case);
+ if (status & 1)
+ {
+ if (cli$present( &cli_patt_case_blind) & 1)
+ {
+ /* "-ic". */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_IC)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_IC);
+ }
+ else if (cli$present( &cli_patt_case_sensitive) & 1)
+ {
+ /* "-ic-". */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_ICN)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_ICN);
+ }
+ }
+
+ /*
+ ** Data descriptors.
+ */
+#define OPT_FD "-fd"
+
+ status = cli$present( &cli_descriptors);
+ if (status & 1)
+ {
+ /* /DESCRIPTORS */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_FD)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_FD);
+ }
+
+ /*
+ ** Difference archive. Add only new or changed files.
+ */
+#define OPT_DF "-DF" /* Difference archive. */
+
+ if ((status = cli$present( &cli_difference)) & 1)
+ {
+ /* /DIFFERENCE */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DF)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DF);
+ }
+
+ /*
+ ** Do not add/modify directory entries.
+ */
+ status = cli$present(&cli_dirnames);
+ if (!(status & 1))
+ /* /DIRNAMES */
+ *ptr++ = 'D';
+
+ /*
+ ** Encrypt?
+ */
+ status = cli$present(&cli_encrypt);
+ if (status & 1)
+ if ((status = cli$get_value(&cli_encrypt, &work_str)) & 1) {
+ /* /ENCRYPT = value */
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length + 4;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-P");
+ strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+ } else {
+ /* /ENCRYPT */
+ *ptr++ = 'e';
+ }
+
+ /*
+ ** Fix the zip archive structure.
+ */
+ status = cli$present(&cli_fix_archive);
+ if (status & 1) {
+ *ptr++ = 'F';
+ /* /FIX_ARCHIVE = NORMAL */
+ if ((status = cli$present(&cli_fix_full)) & 1) {
+ /* /FIX_ARCHIVE = FULL */
+ *ptr++ = 'F';
+ }
+ }
+
+ /*
+ ** Filesync. Delete archive entry if no such file.
+ */
+#define OPT_FS "-FS" /* Filesync. */
+
+ if ((status = cli$present( &cli_filesync)) & 1)
+ {
+ /* /FILESYNC */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_FS)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_FS);
+ }
+
+ /*
+ ** Append (allow growing of existing zip file).
+ */
+ status = cli$present(&cli_append);
+ if (status & 1)
+ /* /APPEND */
+ *ptr++ = 'g';
+
+ status = cli$present(&cli_grow);
+ if (status & 1)
+ /* /GROW */
+ *ptr++ = 'g';
+
+ /*
+ ** Show the help.
+ */
+#define OPT_H2 "-h2"
+
+ status = cli$present(&cli_help);
+ if (status & 1)
+ {
+ status = cli$present( &cli_help_normal);
+ if (status & 1)
+ {
+ /* /HELP [= NORMAL] */
+ *ptr++ = 'h';
+ }
+ status = cli$present( &cli_help_extended);
+ if (status & 1)
+ {
+ /* /HELP = EXTENDED */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_H2)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_H2);
+ }
+ }
+
+ /*
+ ** Junk path names (directory specs).
+ */
+ status = cli$present(&cli_junk);
+ if (status & 1)
+ /* /JUNK */
+ *ptr++ = 'j';
+
+ /*
+ ** Simulate zip file made by PKZIP.
+ */
+ status = cli$present(&cli_pkzip);
+ if (status & 1)
+ /* /KEEP_VERSION */
+ *ptr++ = 'k';
+
+ /*
+ ** Translate end-of-line.
+ */
+ status = cli$present(&cli_translate_eol);
+ if (status & 1) {
+ /* /TRANSLATE_EOL [= LF]*/
+ *ptr++ = 'l';
+ if ((status = cli$present(&cli_transl_eol_crlf)) & 1) {
+ /* /TRANSLATE_EOL = CRLF */
+ *ptr++ = 'l';
+ }
+ }
+
+ /*
+ ** Show the software license.
+ */
+ status = cli$present(&cli_license);
+ if (status & 1)
+ /* /LICENSE */
+ *ptr++ = 'L';
+
+ /*
+ ** Set zip file time to time of latest file in it.
+ */
+ status = cli$present(&cli_latest);
+ if (status & 1)
+ /* /LATEST */
+ *ptr++ = 'o';
+
+ /*
+ ** Store full path (default).
+ */
+ status = cli$present(&cli_full_path);
+ if (status == CLI$_PRESENT)
+ /* /FULL_PATH */
+ *ptr++ = 'p';
+ else if (status == CLI$_NEGATED)
+ /* /NOFULL_PATH */
+ *ptr++ = 'j';
+
+ /*
+ ** Junk Zipfile prefix (SFX stub etc.).
+ */
+ status = cli$present(&cli_unsfx);
+ if (status & 1)
+ /* /UNSFX */
+ *ptr++ = 'J';
+
+ /*
+ ** Recurse through subdirectories.
+ */
+ status = cli$present(&cli_recurse);
+ if (status & 1) {
+ if ((status = cli$present(&cli_recurse_fnames)) & 1)
+ /* /RECURSE [= PATH] */
+ *ptr++ = 'R';
+ else
+ /* /RECURSE [= FILENAMES] */
+ *ptr++ = 'r';
+ }
+
+ /*
+ ** Test Zipfile.
+ */
+ status = cli$present(&cli_test);
+ if (status & 1) {
+ /* /TEST */
+ *ptr++ = 'T';
+ }
+
+ /*
+ ** Be verbose.
+ */
+ status = cli$present(&cli_verbose);
+ if (status & 1) {
+ int i;
+ int verbo = 0;
+
+ /* /VERBOSE */
+ if ((status = cli$present(&cli_verbose_command)) & 1)
+ {
+ /* /VERBOSE = COMMAND */
+ verbose_command = 1;
+ }
+
+ /* Note that any or all of the following options may be
+ specified, and the maximum one is used.
+ */
+ if ((status = cli$present(&cli_verbose_normal)) & 1)
+ /* /VERBOSE [ = NORMAL ] */
+ verbo = 1;
+ if ((status = cli$present(&cli_verbose_more)) & 1)
+ /* /VERBOSE = MORE */
+ verbo = 2;
+ if ((status = cli$present(&cli_verbose_debug)) & 1) {
+ /* /VERBOSE = DEBUG */
+ verbo = 3;
+ }
+ for (i = 0; i < verbo; i++)
+ *ptr++ = 'v';
+ }
+
+ /*
+ ** Quiet mode.
+ ** (Quiet mode is processed after verbose, because a "-v" modifier
+ ** resets "noisy" to 1.)
+ */
+ status = cli$present(&cli_quiet);
+ if (status & 1)
+ /* /QUIET */
+ *ptr++ = 'q';
+
+ /*
+ ** Save the VMS file attributes (and all allocated blocks?).
+ */
+ status = cli$present(&cli_vms);
+ if (status & 1) {
+ /* /VMS */
+ *ptr++ = 'V';
+ if ((status = cli$present(&cli_vms_all)) & 1) {
+ /* /VMS = ALL */
+ *ptr++ = 'V';
+ }
+ }
+
+ /*
+ ** Keep the VMS version number as part of the file name when stored.
+ */
+ status = cli$present(&cli_keep_version);
+ if (status & 1)
+ /* /KEEP_VERSION */
+ *ptr++ = 'w';
+
+ /*
+ ** Store symlinks as symlinks.
+ */
+ status = cli$present(&cli_symlinks);
+ if (status & 1)
+ /* /SYMLINKS */
+ *ptr++ = 'y';
+
+ /*
+ ** `Batch' processing: read filenames to archive from stdin
+ ** or the specified file.
+ */
+ status = cli$present(&cli_batch);
+ if (status & 1) {
+ /* /BATCH */
+ status = cli$get_value(&cli_batch, &work_str);
+ if (status & 1) {
+ /* /BATCH = value */
+ work_str.dsc$a_pointer[work_str.dsc$w_length] = '\0';
+ if ((stdin = freopen(work_str.dsc$a_pointer, "r", stdin)) == NULL)
+ {
+ sprintf(errbuf, "could not open list file: %s",
+ work_str.dsc$a_pointer);
+ ziperr(ZE_PARMS, errbuf);
+ }
+ }
+ *ptr++ = '@';
+ }
+
+ /*
+ ** Now copy the final options string to the_cmd_line.
+ */
+ len = ptr - &options[0];
+ if (len > 1) {
+ options[len] = '\0';
+ x = cmdl_len;
+ cmdl_len += len + 1;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], options);
+ }
+
+ /*
+ **
+ ** OK. We've done all the regular options, so check for -b (temporary
+ ** file path), -n (special suffixes), -O (output atchive file),
+ ** -t (exclude before time), -Z (compression method), zipfile,
+ ** files to zip, and exclude list.
+ **
+ */
+ status = cli$present(&cli_temp_path);
+ if (status & 1) {
+ /* /TEMP_PATH = value */
+ status = cli$get_value(&cli_temp_path, &work_str);
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length + 4;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-b");
+ strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+ }
+
+ status = cli$present(&cli_output);
+ if (status & 1) {
+ /* /OUTPUT = value */
+ status = cli$get_value(&cli_output, &work_str);
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length + 4;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-O");
+ strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+ }
+
+ /*
+ ** Handle "-db", "-dc", "-dd", "-ds".
+ */
+#define OPT_DB "-db"
+#define OPT_DC "-dc"
+#define OPT_DD "-dd"
+#define OPT_DG "-dg"
+#define OPT_DS "-ds="
+#define OPT_DU "-du"
+#define OPT_DV "-dv"
+
+ status = cli$present( &cli_display);
+ if (status & 1)
+ {
+ if ((status = cli$present( &cli_display_bytes)) & 1)
+ {
+ /* /DISPLAY = BYTES */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DB)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DB);
+ }
+
+ if ((status = cli$present( &cli_display_counts)) & 1)
+ {
+ /* /DISPLAY = COUNTS */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DC)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DC);
+ }
+
+ if ((status = cli$present( &cli_display_dots)) & 1)
+ {
+ /* /DISPLAY = DOTS [= value] */
+ status = cli$get_value( &cli_display_dots, &work_str);
+
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DD)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DD);
+
+ /* -dd[=value] now -dd -ds=value - 5/8/05 EG */
+ if (work_str.dsc$w_length > 0) {
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DS);
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DS);
+
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strncpy( &the_cmd_line[ x],
+ work_str.dsc$a_pointer, work_str.dsc$w_length);
+ }
+ }
+
+ if ((status = cli$present( &cli_display_globaldots)) & 1)
+ {
+ /* /DISPLAY = GLOBALDOTS */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DG)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DG);
+ }
+
+ if ((status = cli$present( &cli_display_usize)) & 1)
+ {
+ /* /DISPLAY = USIZE */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DU)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DU);
+ }
+
+ if ((status = cli$present( &cli_display_volume)) & 1)
+ {
+ /* /DISPLAY = VOLUME */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_DV)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_DV);
+ }
+ }
+
+ /*
+ ** Handle "-la", "-lf", "-li".
+ */
+#define OPT_LA "-la"
+#define OPT_LF "-lf"
+#define OPT_LI "-li"
+
+ status = cli$present( &cli_log_file);
+ if (status & 1)
+ {
+ /* /SHOW */
+ if ((status = cli$present( &cli_log_file_append)) & 1)
+ {
+ /* /LOG_FILE = APPEND */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_LA)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_LA);
+ }
+
+ status = cli$present(&cli_log_file_file);
+ if (status & 1) {
+ /* /LOG_FILE = FILE = file */
+ status = cli$get_value(&cli_log_file_file, &work_str);
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_LF)+ 2+ work_str.dsc$w_length;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], OPT_LF);
+ strncpy(&the_cmd_line[x+strlen( OPT_LF)+ 1], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+ }
+
+ if ((status = cli$present( &cli_log_file_info)) & 1)
+ {
+ /* /LOG = INFO */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_LI)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_LI);
+ }
+ }
+
+ /*
+ ** Handle "-s", "-sb", "-sp", "-sv".
+ */
+#define OPT_S "-s"
+#define OPT_SB "-sb"
+#define OPT_SP "-sp"
+#define OPT_SV "-sv"
+
+ status = cli$present( &cli_split);
+ if (status & 1)
+ {
+ status = cli$present( &cli_split_bell);
+ if (status & 1)
+ {
+ /* /SPLIT = BELL */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_SB)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_SB);
+ }
+
+ status = cli$present( &cli_split_pause);
+ if (status & 1)
+ {
+ /* /SPLIT = PAUSE */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_SP)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_SP);
+ }
+
+ status = cli$present( &cli_split_size);
+ if (status & 1)
+ {
+ /* /SPLIT = SIZE = size */
+ status = cli$get_value( &cli_split_size, &work_str);
+
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_S)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_S);
+
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length+ 1;
+ strncpy( &the_cmd_line[ x],
+ work_str.dsc$a_pointer, work_str.dsc$w_length);
+ }
+
+ status = cli$present( &cli_split_verbose);
+ if (status & 1)
+ {
+ /* /SPLIT = VERBOSE */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_SV)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_SV);
+ }
+ }
+
+ /*
+ ** Handle "-sc", "-sd", "-sf", "-so".
+ */
+#define OPT_SC "-sc"
+#define OPT_SD "-sd"
+#define OPT_SF "-sf"
+#define OPT_SO "-so"
+
+ status = cli$present( &cli_show);
+ if (status & 1)
+ {
+ /* /SHOW */
+ if ((status = cli$present( &cli_show_command)) & 1)
+ {
+ /* /SHOW = COMMAND */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_SC)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_SC);
+ }
+
+ if ((status = cli$present( &cli_show_debug)) & 1)
+ {
+ /* /SHOW = DEBUG */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_SD)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_SD);
+ }
+
+ if ((status = cli$present( &cli_show_files)) & 1)
+ {
+ /* /SHOW = FILES */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_SF)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_SF);
+ }
+
+ if ((status = cli$present( &cli_show_options)) & 1)
+ {
+ /* /SHOW = OPTIONS */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_SO)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_SO);
+ }
+ }
+
+ /*
+ ** Handle "-fz".
+ */
+#define OPT_FZ "-fz"
+
+ status = cli$present( &cli_zip64);
+ if (status & 1)
+ {
+ /* /ZIP64 */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_FZ)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_FZ);
+ }
+
+ /*
+ ** Handle "-nw" and "-W".
+ */
+#define OPT_NW "-nw"
+#define OPT_W "-W"
+
+ status = cli$present( &cli_wildcard);
+ if (status & 1)
+ {
+ if ((status = cli$present( &cli_wildcard_nospan)) & 1)
+ {
+ /* /WILDCARD = NOSPAN */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_W)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_W);
+ }
+ }
+ else if (status == CLI$_NEGATED)
+ {
+ /* /NOWILDCARD */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_NW)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_NW);
+ }
+
+ /*
+ ** Handle "-MM".
+ */
+#define OPT_MM "-MM"
+
+ status = cli$present( &cli_must_match);
+ if (status & 1)
+ {
+ /* /MUST_MATCH */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_MM)+ 1;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_MM);
+ }
+
+ /*
+ ** UnZip command for archive test.
+ */
+#define OPT_TT "-TT"
+
+ status = cli$present(&cli_test);
+ if (status & 1) {
+ /* /TEST */
+ status = cli$present(&cli_test_unzip);
+ if (status & 1) {
+ /* /TEST = UNZIP = value */
+ status = cli$get_value(&cli_test_unzip, &work_str);
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_TT)+ 2+ work_str.dsc$w_length;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], OPT_TT);
+ strncpy(&the_cmd_line[x+strlen( OPT_TT)+ 1], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+ }
+ }
+
+ /*
+ ** Handle "-Z".
+ */
+#define OPT_ZB "-Zb"
+#define OPT_ZD "-Zd"
+#define OPT_ZS "-Zs"
+
+ status = cli$present( &cli_compression);
+ if (status & 1)
+ {
+ if ((status = cli$present( &cli_compression_b)) & 1)
+ {
+ /* /COMPRESSION = BZIP2 */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_ZB)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_ZB);
+ }
+
+ if ((status = cli$present( &cli_compression_d)) & 1)
+ {
+ /* /COMPRESSION = DEFLATE */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_ZD)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_ZD);
+ }
+
+ if ((status = cli$present( &cli_compression_s)) & 1)
+ {
+ /* /COMPRESSION = STORE */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_ZS)+ 1;
+ CHECK_BUFFER_ALLOCATION( the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_ZS);
+ }
+ }
+
+ /*
+ ** Handle "-t mmddyyyy".
+ */
+ status = cli$present(&cli_since);
+ if (status & 1) {
+ /* /SINCE = value */
+ char since_time[9];
+
+ status = get_time(&cli_since, &since_time[0]);
+ if (!(status & 1)) return (status);
+
+ /*
+ ** Now let's add the option "-t mmddyyyy" to the new command line.
+ */
+ x = cmdl_len;
+ cmdl_len += (3 + 9);
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-t");
+ strcpy(&the_cmd_line[x+3], since_time);
+ }
+
+ /*
+ ** Handle "-tt mmddyyyy".
+ */
+ status = cli$present(&cli_before);
+ if (status & 1) {
+ /* /BEFORE = value */
+ char before_time[9];
+
+ status = get_time(&cli_before, &before_time[0]);
+ if (!(status & 1)) return (status);
+
+ /*
+ ** Now let's add the option "-tt mmddyyyy" to the new command line.
+ */
+ x = cmdl_len;
+ cmdl_len += (4 + 9);
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-tt");
+ strcpy(&the_cmd_line[x+4], before_time);
+ }
+
+ /*
+ ** Handle "-n suffix:suffix:...". (File types to store only.)
+ */
+ status = cli$present(&cli_store_types);
+ if (status & 1) {
+ /* /STORE_TYPES = value_list */
+ x = cmdl_len;
+ cmdl_len += 3;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-n");
+
+ status = get_list(&cli_store_types, &foreign_cmdline, ':',
+ &the_cmd_line, &cmdl_size, &cmdl_len);
+ if (!(status & 1)) return (status);
+ }
+
+ /*
+ ** Handle "-X", keep or strip extra fields.
+ */
+#define OPT_X "-X"
+#define OPT_XN "-X-"
+
+ status = cli$present(&cli_extra_fields);
+ if (status & 1) {
+ /* /EXTRA_FIELDS */
+ if ((status = cli$present( &cli_extra_fields_keep)) & 1) {
+ /* /EXTRA_FIELDS = KEEP_EXISTING */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_XN)+ 1;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_XN);
+ }
+ }
+ else if (status == CLI$_NEGATED) {
+ /* /NOEXTRA_FIELDS */
+ x = cmdl_len;
+ cmdl_len += strlen( OPT_X)+ 1;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy( &the_cmd_line[ x], OPT_X);
+ }
+
+ /*
+ ** Now get the specified zip file name.
+ */
+ status = cli$present(&cli_zipfile);
+ /* zipfile */
+ if (status & 1) {
+ status = cli$get_value(&cli_zipfile, &work_str);
+
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length + 1;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strncpy(&the_cmd_line[x], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+
+ }
+
+ /*
+ ** Run through the list of input files.
+ */
+ status = cli$present(&cli_infile);
+ if (status & 1) {
+ /* infile_list */
+ status = get_list(&cli_infile, &foreign_cmdline, '\0',
+ &the_cmd_line, &cmdl_size, &cmdl_len);
+ if (!(status & 1)) return (status);
+ }
+
+ /*
+ ** List file containing exclude patterns present? ("-x@exclude.lst")
+ */
+ status = cli$present(&cli_exlist);
+ if (status & 1) {
+ /* /EXLIST = list */
+ status = cli$get_value(&cli_exlist, &work_str);
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length + 4;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strncpy(&the_cmd_line[x], "-x@", 3);
+ strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+ }
+
+ /*
+ ** Any files to exclude? ("-x file file")
+ */
+ status = cli$present(&cli_exclude);
+ if (status & 1) {
+ /* /EXCLUDE = list */
+ x = cmdl_len;
+ cmdl_len += 3;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-x");
+
+ status = get_list(&cli_exclude, &foreign_cmdline, '\0',
+ &the_cmd_line, &cmdl_size, &cmdl_len);
+ if (!(status & 1)) return (status);
+ }
+
+ /*
+ ** List file containing include patterns present? ("-x@exclude.lst")
+ */
+ status = cli$present(&cli_inlist);
+ if (status & 1) {
+ /* /INLIST = list */
+ status = cli$get_value(&cli_inlist, &work_str);
+ x = cmdl_len;
+ cmdl_len += work_str.dsc$w_length + 4;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strncpy(&the_cmd_line[x], "-i@", 3);
+ strncpy(&the_cmd_line[x+3], work_str.dsc$a_pointer,
+ work_str.dsc$w_length);
+ the_cmd_line[cmdl_len-1] = '\0';
+ }
+
+ /*
+ ** Any files to include? ("-i file file")
+ */
+ status = cli$present(&cli_include);
+ if (status & 1) {
+ /* /INCLUDE = list */
+ x = cmdl_len;
+ cmdl_len += 3;
+ CHECK_BUFFER_ALLOCATION(the_cmd_line, cmdl_size, cmdl_len)
+ strcpy(&the_cmd_line[x], "-i");
+
+ status = get_list(&cli_exclude, &foreign_cmdline, '\0',
+ &the_cmd_line, &cmdl_size, &cmdl_len);
+ if (!(status & 1)) return (status);
+ }
+
+
+ /*
+ ** We have finished collecting the strings for the argv vector,
+ ** release unused space.
+ */
+ if ((the_cmd_line = (char *) realloc(the_cmd_line, cmdl_len)) == NULL)
+ return (SS$_INSFMEM);
+
+ /*
+ ** Now that we've built our new UNIX-like command line, count the
+ ** number of args and build an argv array.
+ */
+ for (new_argc = 0, x = 0; x < cmdl_len; x++)
+ if (the_cmd_line[x] == '\0')
+ new_argc++;
+
+ /*
+ ** Allocate memory for the new argv[]. The last element of argv[]
+ ** is supposed to be NULL, so allocate enough for new_argc+1.
+ */
+ if ((new_argv = (char **) calloc(new_argc+1, sizeof(char *))) == NULL)
+ return (SS$_INSFMEM);
+
+ /*
+ ** For each option, store the address in new_argv[] and convert the
+ ** separating blanks to nulls so each argv[] string is terminated.
+ */
+ for (ptr = the_cmd_line, x = 0; x < new_argc; x++) {
+ new_argv[x] = ptr;
+ ptr += strlen(ptr) + 1;
+ }
+ new_argv[new_argc] = NULL;
+
+#if defined(TEST) || defined(DEBUG)
+ printf("new_argc = %d\n", new_argc);
+ for (x = 0; x < new_argc; x++)
+ printf("new_argv[%d] = %s\n", x, new_argv[x]);
+#endif /* TEST || DEBUG */
+
+ /* Show the complete UNIX command line, if requested. */
+ if (verbose_command != 0)
+ {
+ printf( " UNIX command line args (argc = %d):\n", new_argc);
+ for (x = 0; x < new_argc; x++)
+ printf( "%s\n", new_argv[ x]);
+ printf( "\n");
+ }
+
+ /*
+ ** All finished. Return the new argc and argv[] addresses to Zip.
+ */
+ *argc_p = new_argc;
+ *argv_p = new_argv;
+
+ return (SS$_NORMAL);
+}
+
+
+
+static unsigned long
+get_list (struct dsc$descriptor_s *qual, struct dsc$descriptor_d *rawtail,
+ int delim, char **p_str, unsigned long *p_size, unsigned long *p_end)
+{
+/*
+** Routine: get_list
+**
+** Function: This routine runs through a comma-separated CLI list
+** and copies the strings to the argv buffer. The
+** specified separation character is used to separate
+** the strings in the argv buffer.
+**
+** All unquoted strings are converted to lower-case.
+**
+** Formal parameters:
+**
+** qual - Address of descriptor for the qualifier name
+** rawtail - Address of descriptor for the full command line tail
+** delim - Character to use to separate the list items
+** p_str - Address of pointer pointing to output buffer (argv strings)
+** p_size - Address of number containing allocated size for output string
+** p_end - Address of number containing used length in output buf
+**
+*/
+
+ register unsigned long status;
+ struct dsc$descriptor_d work_str;
+
+ init_dyndesc(work_str);
+
+ status = cli$present(qual);
+ if (status & 1) {
+
+ unsigned long len, old_len;
+ long ind, sind;
+ int keep_case;
+ char *src, *dst; int x;
+
+ /*
+ ** Just in case the string doesn't exist yet, though it does.
+ */
+ if (*p_str == NULL) {
+ *p_size = ARGBSIZE_UNIT;
+ if ((*p_str = (char *) malloc(*p_size)) == NULL)
+ return (SS$_INSFMEM);
+ len = 0;
+ } else {
+ len = *p_end;
+ }
+
+ while ((status = cli$get_value(qual, &work_str)) & 1) {
+ old_len = len;
+ len += work_str.dsc$w_length + 1;
+ CHECK_BUFFER_ALLOCATION(*p_str, *p_size, len)
+
+ /*
+ ** Look for the filename in the original foreign command
+ ** line to see if it was originally quoted. If so, then
+ ** don't convert it to lowercase.
+ */
+ keep_case = FALSE;
+ str$find_first_substring(rawtail, &ind, &sind, &work_str);
+ if ((ind > 1 && *(rawtail->dsc$a_pointer + ind - 2) == '"') ||
+ (ind == 0))
+ keep_case = TRUE;
+
+ /*
+ ** Copy the string to the buffer, converting to lowercase.
+ */
+ src = work_str.dsc$a_pointer;
+ dst = *p_str+old_len;
+ for (x = 0; x < work_str.dsc$w_length; x++) {
+ if (!keep_case && ((*src >= 'A') && (*src <= 'Z')))
+ *dst++ = *src++ + 32;
+ else
+ *dst++ = *src++;
+ }
+ if (status == CLI$_COMMA)
+ (*p_str)[len-1] = (char)delim;
+ else
+ (*p_str)[len-1] = '\0';
+ }
+ *p_end = len;
+ }
+
+ return (SS$_NORMAL);
+
+}
+
+
+static unsigned long
+get_time (struct dsc$descriptor_s *qual, char *timearg)
+{
+/*
+** Routine: get_time
+**
+** Function: This routine reads the argument string of the qualifier
+** "qual" that should be a VMS syntax date-time string. The
+** date-time string is converted into the standard format
+** "mmddyyyy", specifying an absolute date. The converted
+** string is written into the 9 bytes wide buffer "timearg".
+**
+** Formal parameters:
+**
+** qual - Address of descriptor for the qualifier name
+** timearg - Address of a buffer carrying the 8-char time string returned
+**
+*/
+
+ register unsigned long status;
+ struct dsc$descriptor_d time_str;
+ struct quadword {
+ long high;
+ long low;
+ } bintimbuf = {0,0};
+#ifdef __DECC
+#pragma member_alignment save
+#pragma nomember_alignment
+#endif /* __DECC */
+ struct tim {
+ short year;
+ short month;
+ short day;
+ short hour;
+ short minute;
+ short second;
+ short hundred;
+ } numtimbuf;
+#ifdef __DECC
+#pragma member_alignment restore
+#endif
+
+ init_dyndesc(time_str);
+
+ status = cli$get_value(qual, &time_str);
+ /*
+ ** If a date is given, convert it to 64-bit binary.
+ */
+ if (time_str.dsc$w_length) {
+ status = sys$bintim(&time_str, &bintimbuf);
+ if (!(status & 1)) return (status);
+ str$free1_dx(&time_str);
+ }
+ /*
+ ** Now call $NUMTIM to get the month, day, and year.
+ */
+ status = sys$numtim(&numtimbuf, (bintimbuf.low ? &bintimbuf : NULL));
+ /*
+ ** Write the "mmddyyyy" string to the return buffer.
+ */
+ if (!(status & 1)) {
+ *timearg = '\0';
+ } else {
+ sprintf(timearg, "%02d%02d%04d", numtimbuf.month,
+ numtimbuf.day, numtimbuf.year);
+ }
+ return (status);
+}
+
+
+static unsigned long
+check_cli (struct dsc$descriptor_s *qual)
+{
+/*
+** Routine: check_cli
+**
+** Function: Check to see if a CLD was used to invoke the program.
+**
+** Formal parameters:
+**
+** qual - Address of descriptor for qualifier name to check.
+**
+*/
+ lib$establish(lib$sig_to_ret); /* Establish condition handler */
+ return (cli$present(qual)); /* Just see if something was given */
+}
+
+
+#ifndef TEST
+
+void VMSCLI_help(void) /* VMSCLI version */
+/* Print help (along with license info) to stdout. */
+{
+ extent i; /* counter for help array */
+
+ /* help array */
+ static char *text[] = {
+"Zip %s (%s). Usage: (zip :== $ dev:[dir]zip_cli.exe)",
+"zip archive[.zip] [list] [/EXCL=(xlist)] /options /modifiers",
+" The default action is to add or replace archive entries from list, except",
+" those in xlist. The include file list may contain the special name \"-\" to",
+" compress standard input. If both archive and list are omitted, Zip",
+" compresses stdin to stdout.",
+" Type zip -h for Unix-style flags.",
+" Major options include:",
+" /COPY, /DELETE, /DIFFERENCE, /FILESYNC, /FRESHEN, /GROW, /MOVE, /UPDATE,",
+" /ADJUST_OFFSETS, /FIX_ARCHIVE[={NORMAL|FULL}], /TEST[=UNZIP=cmd], /UNSFX,",
+" Modifiers include:",
+" /BATCH[=list_file], /BEFORE=creation_time, /COMMENTS[={ARCHIVE|FILES}],",
+" /EXCLUDE=(file_list), /EXLIST=file, /INCLUDE=(file_list), /INLIST=file,",
+" /LATEST, /OUTPUT=out_archive, /SINCE=creation_time, /TEMP_PATH=directory,",
+" /LOG_FILE=(FILE=log_file[,APPEND][,INFORMATIONAL]), /MUST_MATCH,",
+" /PATTERN_CASE={BLIND|SENSITIVE}, /NORECURSE|/RECURSE[={PATH|FILENAMES}],",
+" /STORE_TYPES=(type_list),",
+#if CRYPT
+"\
+ /QUIET, /VERBOSE[={MORE|DEBUG}], /[NO]DIRNAMES, /JUNK, /ENCRYPT[=\"pwd\"],\
+",
+#else /* !CRYPT */
+" /QUIET, /VERBOSE[={MORE|DEBUG}], /[NO]DIRNAMES, /JUNK,",
+#endif /* ?CRYPT */
+" /COMPRESSION = {BZIP2|DEFLATE|STORE}, /LEVEL=[0-9], /NOVMS|/VMS[=ALL],",
+" /STORE_TYPES=(type_list), /[NO]PRESERVE_CASE[=([NO]ODS{2|5}[,...])],",
+" /[NO]PKZIP, /[NO]KEEP_VERSION, /DOT_VERSION, /TRANSLATE_EOL[={LF|CRLF}],",
+" /DISPLAY=([BYTES][,COUNTS][,DOTS=mb_per_dot][,GLOBALDOTS][,USIZE]",
+" [,VOLUME]), /DESCRIPTORS, /[NO]EXTRA_FIELDS, /ZIP64,",
+#ifdef S_IFLNK
+" /SPLIT = (SIZE=ssize [,BELL] [,PAUSE] [,VERBOSE]), /SYMLINKS"
+#else /* S_IFLNK */
+" /SPLIT = (SIZE=ssize [,BELL] [,PAUSE] [,VERBOSE])"
+#endif /* S_IFLNK [else] */
+ };
+
+ if (!show_VMSCLI_help) {
+ help();
+ return;
+ }
+
+ for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+ {
+ printf(copyright[i], "zip");
+ putchar('\n');
+ }
+ for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+ {
+ printf(text[i], VERSION, REVDATE);
+ putchar('\n');
+ }
+} /* end function VMSCLI_help() */
+
+#endif /* !TEST */
diff --git a/vms/collect_deps.com b/vms/collect_deps.com
new file mode 100644
index 0000000..349307c
--- /dev/null
+++ b/vms/collect_deps.com
@@ -0,0 +1,89 @@
+$! 1 December 2006. SMS.
+$!
+$! Info-ZIP VMS accessory procedure.
+$!
+$! For the product named by P1,
+$! collect all source file dependencies specified by P3,
+$! and add P4 prefix.
+$! Convert absolute dependencies to relative from one level above P5.
+$! P2 = output file specification.
+$!
+$! MMS /EXTENDED_SYNTAX can't easily pass a macro invocation for P4, so
+$! we remove any internal spaces which might have been added to prevent
+$! immediate evaluation of a macro invocation.
+$!
+$ prefix = f$edit( p4, "COLLAPSE")
+$!
+$ dev_lose = f$edit( f$parse( p5, , , "DEVICE", "SYNTAX_ONLY"), "UPCASE")
+$ dir_lose = f$edit( f$parse( p5, , , "DIRECTORY", "SYNTAX_ONLY"), "UPCASE")
+$ suffix = ".VMS]"
+$ suffix_loc = f$locate( suffix, dir_lose)
+$ if (suffix_loc .lt f$length( dir_lose))
+$ then
+$ dev_dir_lose = dev_lose+ dir_lose- suffix
+$ else
+$ dev_dir_lose = dev_lose+ dir_lose- "]"
+$ endif
+$!
+$! For portability, make the output file record format Stream_LF.
+$!
+$ create /fdl = sys$input 'p2'
+RECORD
+ Carriage_Control carriage_return
+ Format stream_lf
+$!
+$ open /read /write /error = end_main deps_out 'p2'
+$ on error then goto loop_main_end
+$!
+$! Include proper-inclusion-check preface.
+$!
+$ incl_macro = "INCL_"+ f$parse( p2, , , "NAME", "SYNTAX_ONLY")
+$ write deps_out "#"
+$ write deps_out "# ''p1' for VMS - MMS (or MMK) Source Dependency File."
+$ write deps_out "#"
+$ write deps_out ""
+$ write deps_out -
+ "# This description file is included by other description files. It is"
+$ write deps_out -
+ "# not intended to be used alone. Verify proper inclusion."
+$ write deps_out ""
+$ write deps_out ".IFDEF ''incl_macro'"
+$ write deps_out ".ELSE"
+$ write deps_out -
+ "$$$$ THIS DESCRIPTION FILE IS NOT INTENDED TO BE USED THIS WAY."
+$ write deps_out ".ENDIF"
+$ write deps_out ""
+$!
+$! Actual dependencies from individual dependency files.
+$!
+$ loop_main_top:
+$ file = f$search( p3)
+$ if (file .eqs. "") then goto loop_main_end
+$!
+$ open /read /error = end_subs deps_in 'file'
+$ loop_subs_top:
+$ read /error = loop_subs_end deps_in line
+$ line_reduced = f$edit( line, "COMPRESS, TRIM, UPCASE")
+$ colon = f$locate( " : ", line_reduced)
+$ d_d_l_loc = f$locate( dev_dir_lose, -
+ f$extract( (colon+ 3), 1000, line_reduced))
+$ if (d_d_l_loc .eq. 0)
+$ then
+$ front = f$extract( 0, (colon+ 3), line_reduced)
+$ back = f$extract( (colon+ 3+ f$length( dev_dir_lose)), -
+ 1000, line_reduced)
+$ line = front+ "["+ back
+$ endif
+$ write deps_out "''prefix'"+ "''line'"
+$ goto loop_subs_top
+$!
+$ loop_subs_end:
+$ close deps_in
+$!
+$ goto loop_main_top
+$!
+$ loop_main_end:
+$ close deps_out
+$!
+$ end_main:
+$!
diff --git a/vms/cvthelp.tpu b/vms/cvthelp.tpu
new file mode 100644
index 0000000..8c60369
--- /dev/null
+++ b/vms/cvthelp.tpu
@@ -0,0 +1,182 @@
+! TITLE CVTHELP.TPU
+! IDENT 01-001
+!
+!++
+! Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+!
+! See the accompanying file LICENSE, version 2000-Apr-09 or later
+! (the contents of which are also included in zip.h) for terms of use.
+! If, for some reason, all these files are missing, the Info-ZIP license
+! also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+!
+!++
+!
+! Program: CVTHELP.TPU
+!
+! Author: Hunter Goatley
+!
+! Date: January 12, 1992
+!
+! Purpose: Convert .HELP files to RUNOFF .RNH files. Substitutes
+! RUNOFF commands for tags imbedded in the .HELP file.
+!
+! Calling sequence:
+!
+! $ EDIT/TPU/NOJOURNAL/NODISPLAY/COMMAND=CVTHELP file.HELP
+!
+! Modified by:
+!
+! 01-001 Hunter Goatley 7-FEB-2001 15:40
+! Added <NEXT> for qualifier separators.
+!
+! 01-000 Hunter Goatley 12-JAN-1992 15:15
+! Original version.
+!
+!--
+Procedure eve_convert_help
+Local temp
+ ,x
+ ;
+
+ qualifier_level := 0;
+ hg$substitute_topic(current_buffer, "<MAIN>", ".indent-3", "1");
+ hg$substitute_topic(current_buffer, "<QUALIFIER>", ".sk;.indent-3", "");
+ hg$substitute_topic(current_buffer, "<TOPIC>", ".indent-3", "2");
+ hg$substitute_topic(current_buffer, "<SUBTOPIC>", ".indent-3", "3");
+ hg$substitute_topic(current_buffer, "<SUBSUBTOPIC>", ".indent-3", "4");
+ hg$substitute_comment(current_buffer,"<QUALIFIERS>",".indent-3;2 Qualifiers");
+ hg$substitute_comment(current_buffer,"<PARAMETER>",".indent-2");
+ hg$substitute_comment(current_buffer,"<PTEXT>",".lm+3");
+ hg$substitute_comment(current_buffer,"<TXETP>",".lm-3");
+ hg$substitute_comment(current_buffer,"<ETEXT>",".lm+4");
+ hg$substitute_comment(current_buffer,"<TXETE>",".lm-4");
+ hg$substitute_comment(current_buffer,"<INIT>",".noflags;.lm3;.rm70");
+ hg$substitute_comment(current_buffer,"<LITERAL>",".lm+4;.literal");
+ hg$substitute_comment(current_buffer,"<LARETIL>",".end literal;.lm-4");
+ hg$substitute_comment(current_buffer,"<LITERAL0>",".literal");
+ hg$substitute_comment(current_buffer,"<0LARETIL>",".end literal");
+ hg$substitute_comment(current_buffer,"<DOT1LIST>",'.list 1,"o"');
+ hg$substitute_comment(current_buffer,"<DOT0LIST>",'.list 0,"o"');
+ hg$substitute_comment(current_buffer,"<ENTRY>",".le");
+ hg$substitute_comment(current_buffer,"<TSIL>",".end list");
+ hg$substitute_comment(current_buffer,"<CENTER>",".center");
+ hg$substitute_comment(current_buffer,"<FORMAT>",".sk;.indent2");
+ hg$substitute_comment(current_buffer,"<NOTE>",".note");
+ hg$substitute_comment(current_buffer,"<ETON>",".end note");
+ hg$substitute_comment(current_buffer, LINE_BEGIN & LINE_END,".sk");
+ hg$substitute_comment(current_buffer, LINE_BEGIN & "|", "");
+ hg$substitute_comment(current_buffer,"<NEXT>",".br");
+
+EndProcedure; ! eve_convert_help
+
+Procedure hg$substitute_comment (the_buffer, target, new)
+Local temp
+ ,save_pos
+ ,x
+ ;
+ on_error;
+ endon_error;
+
+ save_pos := mark(none);
+ position(beginning_of(the_buffer));
+ loop
+ x := search(target, forward);
+ exitif x = 0;
+ position (x);
+ erase_character(length(x));
+ copy_text(new);
+ endloop;
+
+ position(save_pos);
+
+EndProcedure; ! hg$substitute_comment
+
+Procedure hg$substitute_topic (the_buffer, target, new, level)
+Local temp
+ ,save_pos
+ ,x
+ ;
+ on_error;
+ endon_error;
+
+ save_pos := mark(none);
+ position(beginning_of(the_buffer));
+ loop
+ x := search(target, forward);
+ exitif x = 0;
+ position (x);
+ erase_character(length(x));
+ move_vertical(-1);
+ if (length(current_line) = 0)
+ then copy_text("|");
+ endif;
+ move_vertical(1);
+ copy_text(".!------------------------------------------------------");
+ split_line;
+ copy_text(new);
+ move_horizontal(-current_offset);
+ move_vertical(1);
+ if level <> "" then
+ copy_text(level + " ");
+! else
+! if qualifier_level = 0
+! then
+! copy_text("2 Qualifiers");
+! split_line; split_line;
+! copy_text(new); split_line;
+! qualifier_level := 1;
+! endif;
+ endif;
+ move_horizontal(-current_offset);
+ move_vertical(1);
+ if length(current_line) = 0
+ then
+ if (target = "<MAIN>") OR (target = "<TOPIC>")
+ OR (target = "<SUBTOPIC>") or (target = "<SUBSUBTOPIC>")
+ then copy_text(".br");
+ else copy_text(".sk");
+ endif;
+ endif;
+ endloop;
+
+ position(save_pos);
+
+EndProcedure; ! hg$substitute_topic
+
+!===============================================================================
+Procedure tpu$init_procedure
+Local temp
+ ,orig_filespec
+ ,f
+ ;
+
+ on_error
+ endon_error;
+
+ !Prompt user for information
+
+ orig_filespec := get_info(command_line, "file_name");
+ if orig_filespec = ""
+ then
+ message("No .HELP file given");
+ quit;
+ endif;
+ f := file_parse(orig_filespec, ".HELP"); !Add .LIS ending
+
+ ! Create a buffer and window for editing
+
+ main_buf := create_buffer ("MAIN",f);
+ set (eob_text, main_buf, "[End of buffer]");
+
+ position (beginning_of(main_buf));
+
+ eve_convert_help;
+
+ f := file_parse(orig_filespec,"","",NAME);
+
+ write_file (main_buf, f+".RNH");
+
+ quit;
+EndProcedure; !TPU$INIT_PROCEDURE
+
+tpu$init_procedure;
diff --git a/vms/descrip.mms b/vms/descrip.mms
new file mode 100644
index 0000000..ae2bc04
--- /dev/null
+++ b/vms/descrip.mms
@@ -0,0 +1,358 @@
+# 23 February 2007. SMS.
+#
+# Zip 3.0 for VMS - MMS (or MMK) Description File.
+#
+# Usage:
+#
+# MMS /DESCRIP = [.VMS]DESCRIP.MMS [/MACRO = (<see_below>)] [target]
+#
+# Note that this description file must be used from the main
+# distribution directory, not from the [.VMS] subdirectory.
+#
+# Optional macros:
+#
+# CCOPTS=xxx Compile with CC options xxx. For example:
+# CCOPTS=/ARCH=HOST
+#
+# DBG=1 Compile with /DEBUG /NOOPTIMIZE.
+# Link with /DEBUG /TRACEBACK.
+# (Default is /NOTRACEBACK.)
+#
+# IM=1 Use the old "IM" scheme for storing VMS/RMS file
+# atributes, instead of the newer "PK" scheme.
+#
+# IZ_BZIP2=dev:[dir] Add optional BZIP2 support. The valus of the
+# MMS macro IZ_BZIP2 ("dev:[dir]", or a suitable
+# logical name) tells where to find "bzlib.h". The
+# BZIP2 object library (LIBBZ2_NS.OLB) is expected to
+# be in a "[.dest]" directory under that one
+# ("dev:[dir.ALPHAL]", for example), or in that
+# directory itself.
+#
+# LARGE=1 Enable large-file (>2GB) support. Non-VAX only.
+#
+# LINKOPTS=xxx Link with LINK options xxx. For example:
+# LINKOPTS=/NOINFO
+#
+# LIST=1 Compile with /LIST /SHOW = (ALL, NOMESSAGES).
+# Link with /MAP /CROSS_REFERENCE /FULL.
+#
+# "LOCAL_ZIP=c_macro_1=value1 [, c_macro_2=value2 [...]]"
+# Compile with these additional C macros defined.
+#
+# VAX-specific optional macros:
+#
+# VAXC=1 Use the VAX C compiler, assuming "CC" runs it.
+# (That is, DEC C is not installed, or else DEC C is
+# installed, but VAX C is the default.)
+#
+# FORCE_VAXC=1 Use the VAX C compiler, assuming "CC /VAXC" runs it.
+# (That is, DEC C is installed, and it is the
+# default, but you want VAX C anyway, you fool.)
+#
+# GNUC=1 Use the GNU C compiler. (Seriously under-tested.)
+#
+#
+# The default target, ALL, builds the selected product executables and
+# help files.
+#
+# Other targets:
+#
+# CLEAN deletes architecture-specific files, but leaves any
+# individual source dependency files and the help files.
+#
+# CLEAN_ALL deletes all generated files, except the main (collected)
+# source dependency file.
+#
+# CLEAN_EXE deletes only the architecture-specific executables.
+# Handy if all you wish to do is re-link the executables.
+#
+# Example commands:
+#
+# To build the conventional small-file product using the DEC/Compaq/HP C
+# compiler (Note: DESCRIP.MMS is the default description file name.):
+#
+# MMS /DESCRIP = [.VMS]
+#
+# To get the large-file executables (on a non-VAX system):
+#
+# MMS /DESCRIP = [.VMS] /MACRO = (LARGE=1)
+#
+# To delete the architecture-specific generated files for this system
+# type:
+#
+# MMS /DESCRIP = [.VMS] /MACRO = (LARGE=1) CLEAN ! Large-file.
+# or
+# MMS /DESCRIP = [.VMS] CLEAN ! Small-file.
+#
+# To build a complete small-file product for debug with compiler
+# listings and link maps:
+#
+# MMS /DESCRIP = [.VMS] CLEAN
+# MMS /DESCRIP = [.VMS] /MACRO = (DBG=1, LIST=1)
+#
+########################################################################
+
+# Include primary product description file.
+
+INCL_DESCRIP_SRC = 1
+.INCLUDE [.VMS]DESCRIP_SRC.MMS
+
+# Object library names.
+
+LIB_ZIP = [.$(DEST)]ZIP.OLB
+LIB_ZIPCLI = [.$(DEST)]ZIPCLI.OLB
+LIB_ZIPUTILS = [.$(DEST)]ZIPUTILS.OLB
+
+# Help file names.
+
+ZIP_HELP = ZIP.HLP ZIP_CLI.HLP
+
+# Message file names.
+
+ZIP_MSG_MSG = [.VMS]ZIP_MSG.MSG
+ZIP_MSG_EXE = [.$(DEST)]ZIP_MSG.EXE
+ZIP_MSG_OBJ = [.$(DEST)]ZIP_MSG.OBJ
+
+
+# TARGETS.
+
+# Default target, ALL. Build All Zip executables, utility executables,
+# and help files.
+
+ALL : $(ZIP) $(ZIP_CLI) $(ZIPUTILS) $(ZIP_HELP) $(ZIP_MSG_EXE)
+ @ write sys$output "Done."
+
+# CLEAN target. Delete the [.$(DEST)] directory and everything in it.
+
+CLEAN :
+ if (f$search( "[.$(DEST)]*.*") .nes. "") then -
+ delete /noconfirm [.$(DEST)]*.*;*
+ if (f$search( "$(DEST).DIR") .nes. "") then -
+ set protection = w:d $(DEST).DIR;*
+ if (f$search( "$(DEST).DIR") .nes. "") then -
+ delete /noconfirm $(DEST).DIR;*
+
+# CLEAN_ALL target. Delete:
+# The [.$(DEST)] directories and everything in them.
+# All help-related derived files,
+# All individual C dependency files.
+# Also mention:
+# Comprehensive dependency file.
+
+CLEAN_ALL :
+ if (f$search( "[.ALPHA*]*.*") .nes. "") then -
+ delete /noconfirm [.ALPHA*]*.*;*
+ if (f$search( "ALPHA*.DIR", 1) .nes. "") then -
+ set protection = w:d ALPHA*.DIR;*
+ if (f$search( "ALPHA*.DIR", 2) .nes. "") then -
+ delete /noconfirm ALPHA*.DIR;*
+ if (f$search( "[.IA64*]*.*") .nes. "") then -
+ delete /noconfirm [.IA64*]*.*;*
+ if (f$search( "IA64*.DIR", 1) .nes. "") then -
+ set protection = w:d IA64*.DIR;*
+ if (f$search( "IA64*.DIR", 2) .nes. "") then -
+ delete /noconfirm IA64*.DIR;*
+ if (f$search( "[.VAX*]*.*") .nes. "") then -
+ delete /noconfirm [.VAX*]*.*;*
+ if (f$search( "VAX*.DIR", 1) .nes. "") then -
+ set protection = w:d VAX*.DIR;*
+ if (f$search( "VAX*.DIR", 2) .nes. "") then -
+ delete /noconfirm VAX*.DIR;*
+ if (f$search( "[.vms]ZIP_CLI.RNH") .nes. "") then -
+ delete /noconfirm [.vms]ZIP_CLI.RNH;*
+ if (f$search( "ZIP_CLI.HLP") .nes. "") then -
+ delete /noconfirm ZIP_CLI.HLP;*
+ if (f$search( "ZIP.HLP") .nes. "") then -
+ delete /noconfirm ZIP.HLP;*
+ if (f$search( "*.MMSD") .nes. "") then -
+ delete /noconfirm *.MMSD;*
+ if (f$search( "[.vms]*.MMSD") .nes. "") then -
+ delete /noconfirm [.vms]*.MMSD;*
+ @ write sys$output ""
+ @ write sys$output "Note: This procedure will not"
+ @ write sys$output " DELETE [.VMS]DESCRIP_DEPS.MMS;*"
+ @ write sys$output -
+ "You may choose to, but a recent version of MMS (V3.5 or newer?) is"
+ @ write sys$output -
+ "needed to regenerate it. (It may also be recovered from the original"
+ @ write sys$output -
+ "distribution kit.) See [.VMS]DESCRIP_MKDEPS.MMS for instructions on"
+ @ write sys$output -
+ "generating [.VMS]DESCRIP_DEPS.MMS."
+ @ write sys$output ""
+ @ write sys$output -
+ "It also does not delete the error message source file:"
+ @ write sys$output " DELETE [.VMS]ZIP_MSG.MSG;*"
+ @ write sys$output -
+ "but it can regenerate it if needed."
+ @ write sys$output ""
+
+# CLEAN_EXE target. Delete the executables in [.$(DEST)].
+
+CLEAN_EXE :
+ if (f$search( "[.$(DEST)]*.EXE") .nes. "") then -
+ delete /noconfirm [.$(DEST)]*.EXE;*
+
+
+# Object library module dependencies.
+
+$(LIB_ZIP) : $(LIB_ZIP)($(MODS_OBJS_LIB_ZIP))
+ @ write sys$output "$(MMS$TARGET) updated."
+
+$(LIB_ZIPCLI) : $(LIB_ZIPCLI)($(MODS_OBJS_LIB_ZIPCLI))
+ @ write sys$output "$(MMS$TARGET) updated."
+
+$(LIB_ZIPUTILS) : $(LIB_ZIPUTILS)($(MODS_OBJS_LIB_ZIPUTILS))
+ @ write sys$output "$(MMS$TARGET) updated."
+
+# Module ID options file.
+
+OPT_ID = SYS$DISK:[.VMS]ZIP.OPT
+
+# Default C compile rule.
+
+.C.OBJ :
+ $(CC) $(CFLAGS) $(CDEFS_UNX) $(MMS$SOURCE)
+
+
+# Normal sources in [.VMS].
+
+[.$(DEST)]VMS.OBJ : [.VMS]VMS.C
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSMUNCH.C
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMSZIP.C
+
+# Command-line interface files.
+
+[.$(DEST)]CMDLINE.OBJ : [.VMS]CMDLINE.C
+ $(CC) $(CFLAGS) $(CDEFS_CLI) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPCLI.OBJ : ZIP.C
+ $(CC) $(CFLAGS) $(CDEFS_CLI) $(MMS$SOURCE)
+
+[.$(DEST)]ZIP_CLI.OBJ : [.VMS]ZIP_CLI.CLD
+
+# Utility variant sources.
+
+[.$(DEST)]CRC32_.OBJ : CRC32.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]CRYPT_.OBJ : CRYPT.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]FILEIO_.OBJ : FILEIO.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]UTIL_.OBJ : UTIL.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPFILE_.OBJ : ZIPFILE.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+# Utility main sources.
+
+[.$(DEST)]ZIPCLOAK.OBJ : ZIPCLOAK.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPNOTE.OBJ : ZIPNOTE.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+[.$(DEST)]ZIPSPLIT.OBJ : ZIPSPLIT.C
+ $(CC) $(CFLAGS) $(CDEFS_UTIL) $(MMS$SOURCE)
+
+# VAX C LINK options file.
+
+.IFDEF OPT_FILE
+$(OPT_FILE) :
+ open /write opt_file_ln $(OPT_FILE)
+ write opt_file_ln "SYS$SHARE:VAXCRTL.EXE /SHARE"
+ close opt_file_ln
+.ENDIF
+
+# Normal Zip executable.
+
+$(ZIP) : [.$(DEST)]ZIP.OBJ $(LIB_ZIP) $(OPT_FILE)
+ $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+ $(LIB_ZIP) /include = (GLOBALS $(INCL_BZIP2_M)) /library, -
+ $(LIB_BZIP2_OPTS) -
+ $(LFLAGS_ARCH) -
+ $(OPT_ID) /options
+
+# CLI Zip executable.
+
+$(ZIP_CLI) : [.$(DEST)]ZIPCLI.OBJ \
+ $(LIB_ZIPCLI) $(OPT_ID) $(OPT_FILE)
+ $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+ $(LIB_ZIPCLI) /library, -
+ $(LIB_ZIP) /include = (GLOBALS $(INCL_BZIP2_M)) /library, -
+ $(LIB_BZIP2_OPTS) -
+ $(LFLAGS_ARCH) -
+ $(OPT_ID) /options
+
+# Utility executables.
+
+[.$(DEST)]ZIPCLOAK.EXE : [.$(DEST)]ZIPCLOAK.OBJ \
+ $(LIB_ZIPUTILS) \
+ $(OPT_ID) $(OPT_FILE)
+ $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+ $(LIB_ZIPUTILS) /include = (GLOBALS) /library, -
+ $(LFLAGS_ARCH) -
+ $(OPT_ID) /options
+
+[.$(DEST)]ZIPNOTE.EXE : [.$(DEST)]ZIPNOTE.OBJ \
+ $(LIB_ZIPUTILS) \
+ $(OPT_ID) $(OPT_FILE)
+ $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+ $(LIB_ZIPUTILS) /include = (GLOBALS) /library, -
+ $(LFLAGS_ARCH) -
+ $(OPT_ID) /options
+
+[.$(DEST)]ZIPSPLIT.EXE : [.$(DEST)]ZIPSPLIT.OBJ \
+ $(LIB_ZIPUTILS) \
+ $(OPT_ID) $(OPT_FILE)
+ $(LINK) $(LINKFLAGS) $(MMS$SOURCE), -
+ $(LIB_ZIPUTILS) /include = (GLOBALS) /library, -
+ $(LFLAGS_ARCH) -
+ $(OPT_ID) /options
+
+# Help files.
+
+ZIP.HLP : [.VMS]VMS_ZIP.RNH
+ runoff /output = $(MMS$TARGET) $(MMS$SOURCE)
+
+ZIP_CLI.HLP : [.VMS]ZIP_CLI.HELP [.VMS]CVTHELP.TPU
+ edit := edit
+ edit /tpu /nosection /nodisplay /command = [.VMS]CVTHELP.TPU -
+ $(MMS$SOURCE)
+ rename /noconfirm ZIP_CLI.RNH; [.VMS];
+ purge /noconfirm /nolog /keep = 1 [.VMS]ZIP_CLI.RNH
+ runoff /output = $(MMS$TARGET) [.VMS]ZIP_CLI.RNH
+
+# Message file.
+
+$(ZIP_MSG_EXE) : $(ZIP_MSG_OBJ)
+ link /shareable = $(MMS$TARGET) $(ZIP_MSG_OBJ)
+
+$(ZIP_MSG_OBJ) : $(ZIP_MSG_MSG)
+ message /object = $(MMS$TARGET) /nosymbols $(ZIP_MSG_MSG)
+
+$(ZIP_MSG_MSG) : ZIPERR.H [.VMS]STREAM_LF.FDL [.VMS]VMS_MSG_GEN.C
+ $(CC) /include = [] /object = [.$(DEST)]VMS_MSG_GEN.OBJ -
+ [.VMS]VMS_MSG_GEN.C
+ $(LINK) /executable = [.$(DEST)]VMS_MSG_GEN.EXE -
+ $(LFLAGS_ARCH) -
+ [.$(DEST)]VMS_MSG_GEN.OBJ
+ create /fdl = [.VMS]STREAM_LF.FDL $(MMS$TARGET)
+ define /user_mode sys$output $(MMS$TARGET)
+ run [.$(DEST)]VMS_MSG_GEN.EXE
+ purge $(MMS$TARGET)
+ delete [.$(DEST)]VMS_MSG_GEN.EXE;*, [.$(DEST)]VMS_MSG_GEN.OBJ;*
+
+# Include generated source dependencies.
+
+INCL_DESCRIP_DEPS = 1
+.INCLUDE [.VMS]DESCRIP_DEPS.MMS
+
diff --git a/vms/descrip_deps.mms b/vms/descrip_deps.mms
new file mode 100644
index 0000000..cf8f9b1
--- /dev/null
+++ b/vms/descrip_deps.mms
@@ -0,0 +1,207 @@
+#
+# Zip for VMS - MMS (or MMK) Source Dependency File.
+#
+
+# This description file is included by other description files. It is
+# not intended to be used alone. Verify proper inclusion.
+
+.IFDEF INCL_DESCRIP_DEPS
+.ELSE
+$$$$ THIS DESCRIPTION FILE IS NOT INTENDED TO BE USED THIS WAY.
+.ENDIF
+
+[.$(DEST)]CRC32.OBJ : []CRC32.C
+[.$(DEST)]CRC32.OBJ : []ZIP.H
+[.$(DEST)]CRC32.OBJ : []TAILOR.H
+[.$(DEST)]CRC32.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRC32.OBJ : []ZIPERR.H
+[.$(DEST)]CRC32.OBJ : []CRC32.H
+[.$(DEST)]CRC32_.OBJ : []CRC32.C
+[.$(DEST)]CRC32_.OBJ : []ZIP.H
+[.$(DEST)]CRC32_.OBJ : []TAILOR.H
+[.$(DEST)]CRC32_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRC32_.OBJ : []ZIPERR.H
+[.$(DEST)]CRC32_.OBJ : []CRC32.H
+[.$(DEST)]CRYPT.OBJ : []CRYPT.C
+[.$(DEST)]CRYPT.OBJ : []ZIP.H
+[.$(DEST)]CRYPT.OBJ : []TAILOR.H
+[.$(DEST)]CRYPT.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRYPT.OBJ : []ZIPERR.H
+[.$(DEST)]CRYPT.OBJ : []CRYPT.H
+[.$(DEST)]CRYPT.OBJ : []TTYIO.H
+[.$(DEST)]CRYPT.OBJ : []CRC32.H
+[.$(DEST)]CRYPT_.OBJ : []CRYPT.C
+[.$(DEST)]CRYPT_.OBJ : []ZIP.H
+[.$(DEST)]CRYPT_.OBJ : []TAILOR.H
+[.$(DEST)]CRYPT_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CRYPT_.OBJ : []ZIPERR.H
+[.$(DEST)]CRYPT_.OBJ : []CRYPT.H
+[.$(DEST)]CRYPT_.OBJ : []TTYIO.H
+[.$(DEST)]CRYPT_.OBJ : []CRC32.H
+[.$(DEST)]DEFLATE.OBJ : []DEFLATE.C
+[.$(DEST)]DEFLATE.OBJ : []ZIP.H
+[.$(DEST)]DEFLATE.OBJ : []TAILOR.H
+[.$(DEST)]DEFLATE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]DEFLATE.OBJ : []ZIPERR.H
+[.$(DEST)]FILEIO.OBJ : []FILEIO.C
+[.$(DEST)]FILEIO.OBJ : []ZIP.H
+[.$(DEST)]FILEIO.OBJ : []TAILOR.H
+[.$(DEST)]FILEIO.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]FILEIO.OBJ : []ZIPERR.H
+[.$(DEST)]FILEIO.OBJ : []CRC32.H
+[.$(DEST)]FILEIO.OBJ : [.VMS]VMS.H
+[.$(DEST)]FILEIO_.OBJ : []FILEIO.C
+[.$(DEST)]FILEIO_.OBJ : []ZIP.H
+[.$(DEST)]FILEIO_.OBJ : []TAILOR.H
+[.$(DEST)]FILEIO_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]FILEIO_.OBJ : []ZIPERR.H
+[.$(DEST)]FILEIO_.OBJ : []CRC32.H
+[.$(DEST)]FILEIO_.OBJ : [.VMS]VMS.H
+[.$(DEST)]GLOBALS.OBJ : []GLOBALS.C
+[.$(DEST)]GLOBALS.OBJ : []ZIP.H
+[.$(DEST)]GLOBALS.OBJ : []TAILOR.H
+[.$(DEST)]GLOBALS.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]GLOBALS.OBJ : []ZIPERR.H
+[.$(DEST)]TREES.OBJ : []TREES.C
+[.$(DEST)]TREES.OBJ : []ZIP.H
+[.$(DEST)]TREES.OBJ : []TAILOR.H
+[.$(DEST)]TREES.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]TREES.OBJ : []ZIPERR.H
+[.$(DEST)]TTYIO.OBJ : []TTYIO.C
+[.$(DEST)]TTYIO.OBJ : []ZIP.H
+[.$(DEST)]TTYIO.OBJ : []TAILOR.H
+[.$(DEST)]TTYIO.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]TTYIO.OBJ : []ZIPERR.H
+[.$(DEST)]TTYIO.OBJ : []CRYPT.H
+[.$(DEST)]TTYIO.OBJ : []TTYIO.H
+[.$(DEST)]UTIL.OBJ : []UTIL.C
+[.$(DEST)]UTIL.OBJ : []ZIP.H
+[.$(DEST)]UTIL.OBJ : []TAILOR.H
+[.$(DEST)]UTIL.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]UTIL.OBJ : []ZIPERR.H
+[.$(DEST)]UTIL.OBJ : []EBCDIC.H
+[.$(DEST)]UTIL_.OBJ : []UTIL.C
+[.$(DEST)]UTIL_.OBJ : []ZIP.H
+[.$(DEST)]UTIL_.OBJ : []TAILOR.H
+[.$(DEST)]UTIL_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]UTIL_.OBJ : []ZIPERR.H
+[.$(DEST)]UTIL_.OBJ : []EBCDIC.H
+[.$(DEST)]ZBZ2ERR.OBJ : []ZBZ2ERR.C
+[.$(DEST)]ZBZ2ERR.OBJ : []ZIP.H
+[.$(DEST)]ZBZ2ERR.OBJ : []TAILOR.H
+[.$(DEST)]ZBZ2ERR.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZBZ2ERR.OBJ : []ZIPERR.H
+[.$(DEST)]ZIP.OBJ : []ZIP.C
+[.$(DEST)]ZIP.OBJ : []ZIP.H
+[.$(DEST)]ZIP.OBJ : []TAILOR.H
+[.$(DEST)]ZIP.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIP.OBJ : []ZIPERR.H
+[.$(DEST)]ZIP.OBJ : []REVISION.H
+[.$(DEST)]ZIP.OBJ : []CRC32.H
+[.$(DEST)]ZIP.OBJ : []CRYPT.H
+[.$(DEST)]ZIP.OBJ : []TTYIO.H
+[.$(DEST)]ZIP.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIP.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPCLI.OBJ : []ZIP.C
+[.$(DEST)]ZIPCLI.OBJ : []ZIP.H
+[.$(DEST)]ZIPCLI.OBJ : []TAILOR.H
+[.$(DEST)]ZIPCLI.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPCLI.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPCLI.OBJ : []REVISION.H
+[.$(DEST)]ZIPCLI.OBJ : []CRC32.H
+[.$(DEST)]ZIPCLI.OBJ : []CRYPT.H
+[.$(DEST)]ZIPCLI.OBJ : []TTYIO.H
+[.$(DEST)]ZIPCLI.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIPCLI.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPCLOAK.OBJ : []ZIPCLOAK.C
+[.$(DEST)]ZIPCLOAK.OBJ : []ZIP.H
+[.$(DEST)]ZIPCLOAK.OBJ : []TAILOR.H
+[.$(DEST)]ZIPCLOAK.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPCLOAK.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPCLOAK.OBJ : []REVISION.H
+[.$(DEST)]ZIPCLOAK.OBJ : []CRC32.H
+[.$(DEST)]ZIPCLOAK.OBJ : []CRYPT.H
+[.$(DEST)]ZIPCLOAK.OBJ : []TTYIO.H
+[.$(DEST)]ZIPFILE.OBJ : []ZIPFILE.C
+[.$(DEST)]ZIPFILE.OBJ : []ZIP.H
+[.$(DEST)]ZIPFILE.OBJ : []TAILOR.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPFILE.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPFILE.OBJ : []REVISION.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIPFILE.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]ZIPFILE_.OBJ : []ZIPFILE.C
+[.$(DEST)]ZIPFILE_.OBJ : []ZIP.H
+[.$(DEST)]ZIPFILE_.OBJ : []TAILOR.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPFILE_.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPFILE_.OBJ : []REVISION.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]VMS.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]ZIPFILE_.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]ZIPNOTE.OBJ : []ZIPNOTE.C
+[.$(DEST)]ZIPNOTE.OBJ : []ZIP.H
+[.$(DEST)]ZIPNOTE.OBJ : []TAILOR.H
+[.$(DEST)]ZIPNOTE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPNOTE.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPNOTE.OBJ : []REVISION.H
+[.$(DEST)]ZIPSPLIT.OBJ : []ZIPSPLIT.C
+[.$(DEST)]ZIPSPLIT.OBJ : []ZIP.H
+[.$(DEST)]ZIPSPLIT.OBJ : []TAILOR.H
+[.$(DEST)]ZIPSPLIT.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPSPLIT.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPSPLIT.OBJ : []REVISION.H
+[.$(DEST)]ZIPUP.OBJ : []ZIPUP.C
+[.$(DEST)]ZIPUP.OBJ : []ZIP.H
+[.$(DEST)]ZIPUP.OBJ : []TAILOR.H
+[.$(DEST)]ZIPUP.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]ZIPUP.OBJ : []ZIPERR.H
+[.$(DEST)]ZIPUP.OBJ : []REVISION.H
+[.$(DEST)]ZIPUP.OBJ : []CRC32.H
+[.$(DEST)]ZIPUP.OBJ : []CRYPT.H
+[.$(DEST)]ZIPUP.OBJ : [.VMS]ZIPUP.H
+[.$(DEST)]CMDLINE.OBJ : [.VMS]CMDLINE.C
+[.$(DEST)]CMDLINE.OBJ : []ZIP.H
+[.$(DEST)]CMDLINE.OBJ : []TAILOR.H
+[.$(DEST)]CMDLINE.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]CMDLINE.OBJ : []ZIPERR.H
+[.$(DEST)]CMDLINE.OBJ : []CRYPT.H
+[.$(DEST)]CMDLINE.OBJ : []REVISION.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS.C
+[.$(DEST)]VMS.OBJ : []ZIP.H
+[.$(DEST)]VMS.OBJ : []TAILOR.H
+[.$(DEST)]VMS.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMS.OBJ : []ZIPERR.H
+[.$(DEST)]VMS.OBJ : [.VMS]ZIPUP.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS_PK.C
+[.$(DEST)]VMS.OBJ : []CRC32.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]VMS.OBJ : [.VMS]VMS_IM.C
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSMUNCH.C
+[.$(DEST)]VMSMUNCH.OBJ : []ZIP.H
+[.$(DEST)]VMSMUNCH.OBJ : []TAILOR.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMSMUNCH.OBJ : []ZIPERR.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]VMSMUNCH.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMSZIP.C
+[.$(DEST)]VMSZIP.OBJ : []ZIP.H
+[.$(DEST)]VMSZIP.OBJ : []TAILOR.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMSZIP.OBJ : []ZIPERR.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMSMUNCH.H
+[.$(DEST)]VMSZIP.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS.C
+[.$(DEST)]VMS_.OBJ : []ZIP.H
+[.$(DEST)]VMS_.OBJ : []TAILOR.H
+[.$(DEST)]VMS_.OBJ : [.VMS]OSDEP.H
+[.$(DEST)]VMS_.OBJ : []ZIPERR.H
+[.$(DEST)]VMS_.OBJ : [.VMS]ZIPUP.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS_PK.C
+[.$(DEST)]VMS_.OBJ : []CRC32.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMSDEFS.H
+[.$(DEST)]VMS_.OBJ : [.VMS]VMS_IM.C
diff --git a/vms/descrip_mkdeps.mms b/vms/descrip_mkdeps.mms
new file mode 100644
index 0000000..9bf5add
--- /dev/null
+++ b/vms/descrip_mkdeps.mms
@@ -0,0 +1,247 @@
+# 1 February 2008. SMS.
+#
+# Zip 3.0 for VMS - MMS Dependency Description File.
+#
+# MMS /EXTENDED_SYNTAX description file to generate a C source
+# dependencies file. Unsightly errors result when /EXTENDED_SYNTAX
+# is not specified. Typical usage:
+#
+# $ MMS /EXTEND /DESCRIP = [.VMS]DESCRIP_MKDEPS.MMS /SKIP
+#
+# Note that this description file must be used from the main
+# distribution directory, not from the [.VMS] subdirectory.
+#
+# This description file uses these command procedures:
+#
+# [.VMS]MOD_DEP.COM
+# [.VMS]COLLECT_DEPS.COM
+#
+# MMK users without MMS will be unable to generate the dependencies file
+# using this description file, however there should be one supplied in
+# the kit. If this file has been deleted, users in this predicament
+# will need to recover it from the original distribution kit.
+#
+# Note: This dependency generation scheme assumes that the dependencies
+# do not depend on host architecture type or other such variables.
+# Therefore, no "#include" directive in the C source itself should be
+# conditional on such variables.
+#
+# The default target is the comprehensive source dependency file,
+# DEPS_FILE = [.VMS]DESCRIP_DEPS.MMS.
+#
+# Other targets:
+#
+# CLEAN deletes the individual source dependency files,
+# *.MMSD;*, but leaves the comprehensive source dependency
+# file.
+#
+# CLEAN_ALL deletes all source dependency files, including the
+# individual *.MMSD;* files and the comprehensive file,
+# DESCRIP_DEPS.MMS.*.
+#
+
+# Required command procedures.
+
+COMS = [.VMS]MOD_DEP.COM [.VMS]COLLECT_DEPS.COM
+
+# Include the source file lists (among other data).
+
+INCL_DESCRIP_SRC = 1
+.INCLUDE [.VMS]DESCRIP_SRC.MMS
+
+# The ultimate product, a comprehensive dependency list.
+
+DEPS_FILE = [.VMS]DESCRIP_DEPS.MMS
+
+# Detect valid qualifier and/or macro options.
+
+.IF $(FINDSTRING Skip, $(MMSQUALIFIERS)) .eq Skip
+DELETE_MMSD = 1
+.ELSIF NOSKIP
+PURGE_MMSD = 1
+.ELSE
+UNK_MMSD = 1
+.ENDIF
+
+# Dependency suffixes and rules.
+#
+# .FIRST is assumed to be used already, so the MMS qualifier/macro check
+# is included in each rule (one way or another).
+
+.SUFFIXES_BEFORE .C .MMSD
+
+.C.MMSD :
+.IF UNK_MMSD
+ @ write sys$output -
+ " /SKIP_INTERMEDIATES is expected on the MMS command line."
+ @ write sys$output -
+ " For normal behavior (delete .MMSD files), specify ""/SKIP""."
+ @ write sys$output -
+ " To retain the .MMSD files, specify ""/MACRO = NOSKIP=1""."
+ @ exit %x00000004
+.ENDIF
+ $(CC) $(CFLAGS_INCL) $(MMS$SOURCE) /NOLIST /NOOBJECT -
+ /MMS_DEPENDENCIES = (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+
+# List of MMS dependency files.
+
+# In case it's not obvious...
+# To extract module name lists from object library module=object lists:
+# 1. Transform "module=[.dest]name.OBJ" into "module=[.dest] name".
+# 2. For [.VMS], add [.VMS] to name.
+# 3. Delete "*]" words.
+#
+# A similar scheme works for executable lists.
+
+MODS_LIB_ZIP_N = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] *, $(MODS_OBJS_LIB_ZIP_N)))
+
+MODS_LIB_ZIP_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIP_V)))
+
+MODS_LIB_ZIPUTILS_N = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] *, $(MODS_OBJS_LIB_ZIPUTILS_N)))
+
+MODS_LIB_ZIPUTILS_N_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIPUTILS_N_V)))
+
+MODS_LIB_ZIPUTILS_U = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] *, $(MODS_OBJS_LIB_ZIPUTILS_U)))
+
+MODS_LIB_ZIPUTILS_U_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIPUTILS_U_V)))
+
+MODS_LIB_ZIPCLI_V = $(FILTER-OUT *], \
+ $(PATSUBST *]*.OBJ, *] [.VMS]*, $(MODS_OBJS_LIB_ZIPCLI_C_V)))
+
+MODS_ZIP = $(FILTER-OUT *], \
+ $(PATSUBST *]*.EXE, *] *, $(ZIP)))
+
+MODS_ZIPUTILS = $(FILTER-OUT *], \
+ $(PATSUBST *]*.EXE, *] *, $(ZIPUTILS)))
+
+# Complete list of C object dependency file names.
+# Note that the CLI Zip main program object file is a special case.
+
+DEPS = $(FOREACH NAME, \
+ $(MODS_LIB_ZIP_N) $(MODS_LIB_ZIP_V) \
+ $(MODS_ZIPUTILS_N) $(MODS_ZIPUTILS_N_V) \
+ $(MODS_LIB_ZIPUTILS_U) $(MODS_LIB_ZIPUTILS_U_V) \
+ $(MODS_LIB_ZIPCLI_V) \
+ $(MODS_ZIP) ZIPCLI $(MODS_ZIPUTILS), \
+ $(NAME).MMSD)
+
+# Default target is the comprehensive dependency list.
+
+$(DEPS_FILE) : $(DEPS) $(COMS)
+.IF UNK_MMSD
+ @ write sys$output -
+ " /SKIP_INTERMEDIATES is expected on the MMS command line."
+ @ write sys$output -
+ " For normal behavior (delete individual .MMSD files), specify ""/SKIP""."
+ @ write sys$output -
+ " To retain the individual .MMSD files, specify ""/MACRO = NOSKIP=1""."
+ @ exit %x00000004
+.ENDIF
+#
+# Note that the space in P3, which prevents immediate macro
+# expansion, is removed by COLLECT_DEPS.COM.
+#
+ @[.VMS]COLLECT_DEPS.COM "Zip" -
+ "$(MMS$TARGET)" "[...]*.MMSD" "[.$ (DEST)]" $(MMSDESCRIPTION_FILE)
+ @ write sys$output -
+ "Created a new dependency file: $(MMS$TARGET)"
+.IF DELETE_MMSD
+ @ write sys$output -
+ "Deleting intermediate .MMSD files..."
+ delete /log *.MMSD;*, [.VMS]*.MMSD;*
+.ELSE
+ @ write sys$output -
+ "Purging intermediate .MMSD files..."
+ purge /log *.MMSD, [.VMS]*.MMSD
+.ENDIF
+
+# CLEAN target. Delete the individual C dependency files.
+
+CLEAN :
+ if (f$search( "*.MMSD") .nes. "") then -
+ delete /log *.MMSD;*
+ if (f$search( "[.VMS]*.MMSD") .nes. "") then -
+ delete /log [.VMS]*.MMSD;*
+
+# CLEAN_ALL target. Delete:
+# The individual C dependency files.
+# The collected source dependency file.
+
+CLEAN_ALL :
+ if (f$search( "*.MMSD") .nes. "") then -
+ delete /log *.MMSD;*
+ if (f$search( "[.VMS]*.MMSD") .nes. "") then -
+ delete /log [.VMS]*.MMSD;*
+ if (f$search( "[.VMS]DESCRIP_DEPS.MMS") .nes. "") then -
+ delete /log [.VMS]DESCRIP_DEPS.MMS;*
+
+# Explicit dependencies and rules for utility variant modules.
+#
+# The extra dependency on the normal dependency file obviates including
+# the /SKIP warning code in each rule here.
+
+CRC32_.MMSD : CRC32.C CRC32.MMSD
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+CRYPT_.MMSD : CRYPT.C CRYPT.MMSD
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+FILEIO_.MMSD : FILEIO.C FILEIO.MMSD
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+UTIL_.MMSD : UTIL.C UTIL.MMSD
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+ZIPFILE_.MMSD : ZIPFILE.C ZIPFILE.MMSD
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+[.VMS]VMS_.MMSD : [.VMS]VMS.C [.VMS]VMS.MMSD
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+ZIPCLI.MMSD : ZIP.C ZIP.MMSD
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
+# Special case. No normal (non-CLI) version.
+
+[.VMS]CMDLINE.MMSD : [.VMS]CMDLINE.C
+.IF UNK_MMSD
+ @ write sys$output -
+ " /SKIP_INTERMEDIATES is expected on the MMS command line."
+ @ write sys$output -
+ " For normal behavior (delete .MMSD files), specify ""/SKIP""."
+ @ write sys$output -
+ " To retain the .MMSD files, specify ""/MACRO = NOSKIP=1""."
+ @ exit %x00000004
+.ENDIF
+ $(CC) $(CFLAGS_INCL) $(CFLAGS_CLI) $(MMS$SOURCE) -
+ /NOLIST /NOOBJECT /MMS_DEPENDENCIES = -
+ (FILE = $(MMS$TARGET), NOSYSTEM_INCLUDE_FILES)
+ @[.VMS]MOD_DEP.COM $(MMS$TARGET) $(MMS$TARGET_NAME).OBJ $(MMS$TARGET)
+
diff --git a/vms/descrip_src.mms b/vms/descrip_src.mms
new file mode 100644
index 0000000..33f3281
--- /dev/null
+++ b/vms/descrip_src.mms
@@ -0,0 +1,373 @@
+# 23 February 2007. SMS.
+#
+# Zip 3.0 for VMS - MMS (or MMK) Source Description File.
+#
+
+# This description file is included by other description files. It is
+# not intended to be used alone. Verify proper inclusion.
+
+.IFDEF INCL_DESCRIP_SRC
+.ELSE
+$$$$ THIS DESCRIPTION FILE IS NOT INTENDED TO BE USED THIS WAY.
+.ENDIF
+
+
+# Define MMK architecture macros when using MMS.
+
+.IFDEF __MMK__ # __MMK__
+.ELSE # __MMK__
+ALPHA_X_ALPHA = 1
+IA64_X_IA64 = 1
+VAX_X_VAX = 1
+.IFDEF $(MMS$ARCH_NAME)_X_ALPHA # $(MMS$ARCH_NAME)_X_ALPHA
+__ALPHA__ = 1
+.ENDIF # $(MMS$ARCH_NAME)_X_ALPHA
+.IFDEF $(MMS$ARCH_NAME)_X_IA64 # $(MMS$ARCH_NAME)_X_IA64
+__IA64__ = 1
+.ENDIF # $(MMS$ARCH_NAME)_X_IA64
+.IFDEF $(MMS$ARCH_NAME)_X_VAX # $(MMS$ARCH_NAME)_X_VAX
+__VAX__ = 1
+.ENDIF # $(MMS$ARCH_NAME)_X_VAX
+.ENDIF # __MMK__
+
+# Combine command-line VAX C compiler macros.
+
+.IFDEF VAXC # VAXC
+VAXC_OR_FORCE_VAXC = 1
+.ELSE # VAXC
+.IFDEF FORCE_VAXC # FORCE_VAXC
+VAXC_OR_FORCE_VAXC = 1
+.ENDIF # FORCE_VAXC
+.ENDIF # VAXC
+
+# Analyze architecture-related and option macros.
+
+.IFDEF __ALPHA__ # __ALPHA__
+DECC = 1
+DESTM = ALPHA
+.ELSE # __ALPHA__
+.IFDEF __IA64__ # __IA64__
+DECC = 1
+DESTM = IA64
+.ELSE # __IA64__
+.IFDEF __VAX__ # __VAX__
+.IFDEF VAXC_OR_FORCE_VAXC # VAXC_OR_FORCE_VAXC
+DESTM = VAXV
+.ELSE # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC # GNUC
+CC = GCC
+DESTM = VAXG
+.ELSE # GNUC
+DECC = 1
+DESTM = VAX
+.ENDIF # GNUC
+.ENDIF # VAXC_OR_FORCE_VAXC
+.ELSE # __VAX__
+DESTM = UNK
+UNK_DEST = 1
+.ENDIF # __VAX__
+.ENDIF # __IA64__
+.ENDIF # __ALPHA__
+
+.IFDEF IM # IM
+DESTI = I
+.ELSE # IM
+DESTI =
+.ENDIF # IM
+
+.IFDEF LARGE # LARGE
+.IFDEF __VAX__ # __VAX__
+DESTL =
+.ELSE # __VAX__
+DESTL = L
+.ENDIF # __VAX__
+.ELSE # LARGE
+DESTL =
+.ENDIF # LARGE
+
+DEST = $(DESTM)$(DESTI)$(DESTL)
+SEEK_BZ = $(DESTM)$(DESTL)
+
+# Library module name suffix for XXX_.OBJ with GNU C.
+
+.IFDEF GNUC # GNUC
+GCC_ = _
+.ELSE # GNUC
+GCC_ =
+.ENDIF # GNUC
+
+# Check for option problems.
+
+.IFDEF __VAX__ # __VAX__
+.IFDEF LARGE # LARGE
+LARGE_VAX = 1
+.ENDIF # LARGE
+.IFDEF VAXC_OR_FORCE_VAXC # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC # GNUC
+VAX_MULTI_CMPL = 1
+.ENDIF # GNUC
+.ENDIF # VAXC_OR_FORCE_VAXC
+.ELSE # __VAX__
+.IFDEF VAXC_OR_FORCE_VAXC # VAXC_OR_FORCE_VAXC
+NON_VAX_CMPL = 1
+.ELSE # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC # GNUC
+NON_VAX_CMPL = 1
+.ENDIF # GNUC
+.ENDIF # VAXC_OR_FORCE_VAXC
+.ENDIF # __VAX__
+
+# Complain if warranted. Otherwise, show destination directory.
+# Make the destination directory, if necessary.
+
+.IFDEF UNK_DEST # UNK_DEST
+.FIRST
+ @ write sys$output -
+ " Unknown system architecture."
+.IFDEF __MMK__ # __MMK__
+ @ write sys$output -
+ " MMK on IA64? Try adding ""/MACRO = __IA64__""."
+.ELSE # __MMK__
+ @ write sys$output -
+ " MMS too old? Try adding ""/MACRO = MMS$ARCH_NAME=ALPHA"","
+ @ write sys$output -
+ " or ""/MACRO = MMS$ARCH_NAME=IA64"", or ""/MACRO = MMS$ARCH_NAME=VAX"","
+ @ write sys$output -
+ " as appropriate. (Or try a newer version of MMS.)"
+.ENDIF # __MMK__
+ @ write sys$output ""
+ I_WILL_DIE_NOW. /$$$$INVALID$$$$
+.ELSE # UNK_DEST
+.IFDEF VAX_MULTI_CMPL # VAX_MULTI_CMPL
+.FIRST
+ @ write sys$output -
+ " Macro ""GNUC"" is incompatible with ""VAXC"" or ""FORCE_VAXC""."
+ @ write sys$output ""
+ I_WILL_DIE_NOW. /$$$$INVALID$$$$
+.ELSE # VAX_MULTI_CMPL
+.IFDEF NON_VAX_CMPL # NON_VAX_CMPL
+.FIRST
+ @ write sys$output -
+ " Macros ""GNUC"", ""VAXC"", and ""FORCE_VAXC"" are valid only on VAX."
+ @ write sys$output ""
+ I_WILL_DIE_NOW. /$$$$INVALID$$$$
+.ELSE # NON_VAX_CMPL
+.IFDEF LARGE_VAX # LARGE_VAX
+.FIRST
+ @ write sys$output -
+ " Macro ""LARGE"" is invalid on VAX."
+ @ write sys$output ""
+ I_WILL_DIE_NOW. /$$$$INVALID$$$$
+.ELSE # LARGE_VAX
+.IFDEF IZ_BZIP2 # IZ_BZIP2
+CDEFS_BZ = , BZIP2_SUPPORT
+CFLAGS_INCL = /INCLUDE = ([], [.VMS])
+INCL_BZIP2_M = , ZBZ2ERR
+LIB_BZIP2_OPTS = LIB_BZIP2:LIBBZ2_NS.OLB /library,
+.FIRST
+ @ define incl_bzip2 $(IZ_BZIP2)
+ @ @[.VMS]FIND_BZIP2_LIB.COM $(IZ_BZIP2) $(SEEK_BZ) -
+ LIBBZ2_NS.OLB lib_bzip2
+ @ write sys$output ""
+ @ if (f$trnlnm( "lib_bzip2") .nes. "") then -
+ write sys$output " BZIP2 dir: ''f$trnlnm( "lib_bzip2")'"
+ @ if (f$trnlnm( "lib_bzip2") .eqs. "") then -
+ write sys$output " Can not find BZIP2 object library."
+ @ write sys$output ""
+ @ if (f$trnlnm( "lib_bzip2") .eqs. "") then -
+ I_WILL_DIE_NOW. /$$$$INVALID$$$$
+ @ write sys$output " Destination: [.$(DEST)]"
+ @ write sys$output ""
+ if (f$search( "$(DEST).DIR;1") .eqs. "") then -
+ create /directory [.$(DEST)]
+.ELSE # IZ_BZIP2
+CDEFS_BZ =
+CFLAGS_INCL = /include = []
+INCL_BZIP2_M = , ZBZ2ERR
+LIB_BZIP2_OPTS =
+.FIRST
+ @ write sys$output " Destination: [.$(DEST)]"
+ @ write sys$output ""
+ if (f$search( "$(DEST).DIR;1") .eqs. "") then -
+ create /directory [.$(DEST)]
+.ENDIF # IZ_BZIP2
+.ENDIF # LARGE_VAX
+.ENDIF # NON_VAX_CMPL
+.ENDIF # VAX_MULTI_CMPL
+.ENDIF # UNK_DEST
+
+# DBG options.
+
+.IFDEF DBG # DBG
+CFLAGS_DBG = /debug /nooptimize
+LINKFLAGS_DBG = /debug /traceback
+.ELSE # DBG
+CFLAGS_DBG =
+LINKFLAGS_DBG = /notraceback
+.ENDIF # DBG
+
+# "IM" scheme for storing VMS/RMS file attributes.
+
+.IFDEF IM # IM
+CDEFS_IM = , VMS_IM_EXTRA
+.ELSE # IM
+CDEFS_IM =
+.ENDIF # IM
+
+# Large-file options.
+
+.IFDEF LARGE # LARGE
+CDEFS_LARGE = , LARGE_FILE_SUPPORT
+.ELSE # LARGE
+CDEFS_LARGE =
+.ENDIF # LARGE
+
+# C compiler defines.
+
+.IFDEF LOCAL_ZIP
+C_LOCAL_ZIP = , $(LOCAL_ZIP)
+.ELSE
+C_LOCAL_ZIP =
+.ENDIF
+
+CDEFS = VMS $(CDEFS_BZ) $(CDEFS_IM) $(CDEFS_LARGE) $(C_LOCAL_ZIP)
+
+CDEFS_UNX = /define = ($(CDEFS))
+
+CDEFS_CLI = /define = ($(CDEFS), VMSCLI)
+
+CDEFS_UTIL = /define = ($(CDEFS), UTIL)
+
+# Other C compiler options.
+
+.IFDEF DECC # DECC
+CFLAGS_ARCH = /decc /prefix = (all)
+.ELSE # DECC
+.IFDEF FORCE_VAXC # FORCE_VAXC
+CFLAGS_ARCH = /vaxc
+.IFDEF VAXC # VAXC
+.ELSE # VAXC
+VAXC = 1
+.ENDIF # VAXC
+.ELSE # FORCE_VAXC
+CFLAGS_ARCH =
+.ENDIF # FORCE_VAXC
+.ENDIF # DECC
+
+.IFDEF VAXC_OR_FORCE_VAXC # VAXC_OR_FORCE_VAXC
+OPT_FILE = [.$(DEST)]VAXCSHR.OPT
+LFLAGS_ARCH = $(OPT_FILE) /options,
+.ELSE # VAXC_OR_FORCE_VAXC
+.IFDEF GNUC # GNUC
+OPT_FILE = [.$(DEST)]VAXCSHR.OPT
+LFLAGS_GNU = GNU_CC:[000000]GCCLIB.OLB /LIBRARY
+LFLAGS_ARCH = $(LFLAGS_GNU), SYS$DISK:$(OPT_FILE) /options,
+.ELSE # GNUC
+OPT_FILE =
+LFLAGS_ARCH =
+.ENDIF # GNUC
+.ENDIF # VAXC_OR_FORCE_VAXC
+
+# LIST options.
+
+.IFDEF LIST # LIST
+.IFDEF DECC # DECC
+CFLAGS_LIST = /list = $*.LIS /show = (all, nomessages)
+.ELSE # DECC
+CFLAGS_LIST = /list = $*.LIS /show = (all)
+.ENDIF # DECC
+LINKFLAGS_LIST = /map = $*.MAP /cross_reference /full
+.ELSE # LIST
+CFLAGS_LIST =
+LINKFLAGS_LIST =
+.ENDIF # LIST
+
+# Common CFLAGS and LINKFLAGS.
+
+CFLAGS = \
+ $(CFLAGS_ARCH) $(CFLAGS_DBG) $(CFLAGS_INCL) $(CFLAGS_LIST) $(CCOPTS) \
+ /object = $(MMS$TARGET)
+
+LINKFLAGS = \
+ $(LINKFLAGS_DBG) $(LINKFLAGS_LIST) $(LINKOPTS) \
+ /executable = $(MMS$TARGET)
+
+# Object library module=object lists.
+
+# Primary object library, [].
+
+MODS_OBJS_LIB_ZIP_N = \
+ CRC32=[.$(DEST)]CRC32.OBJ \
+ CRYPT=[.$(DEST)]CRYPT.OBJ \
+ DEFLATE=[.$(DEST)]DEFLATE.OBJ \
+ FILEIO=[.$(DEST)]FILEIO.OBJ \
+ GLOBALS=[.$(DEST)]GLOBALS.OBJ \
+ TREES=[.$(DEST)]TREES.OBJ \
+ TTYIO=[.$(DEST)]TTYIO.OBJ \
+ UTIL=[.$(DEST)]UTIL.OBJ \
+ ZBZ2ERR=[.$(DEST)]ZBZ2ERR.OBJ \
+ ZIPFILE=[.$(DEST)]ZIPFILE.OBJ \
+ ZIPUP=[.$(DEST)]ZIPUP.OBJ
+
+# Primary object library, [.VMS].
+
+MODS_OBJS_LIB_ZIP_V = \
+ VMS=[.$(DEST)]VMS.OBJ \
+ VMSMUNCH=[.$(DEST)]VMSMUNCH.OBJ \
+ VMSZIP=[.$(DEST)]VMSZIP.OBJ
+
+MODS_OBJS_LIB_ZIP = $(MODS_OBJS_LIB_ZIP_N) $(MODS_OBJS_LIB_ZIP_V)
+
+# Utility object library, normal, [].
+
+MODS_OBJS_LIB_ZIPUTILS_N = \
+ GLOBALS=[.$(DEST)]GLOBALS.OBJ \
+ TTYIO=[.$(DEST)]TTYIO.OBJ
+
+# Utility object library, variant, [].
+
+MODS_OBJS_LIB_ZIPUTILS_U = \
+ CRC32$(GCC_)=[.$(DEST)]CRC32_.OBJ \
+ CRYPT$(GCC_)=[.$(DEST)]CRYPT_.OBJ \
+ FILEIO$(GCC_)=[.$(DEST)]FILEIO_.OBJ \
+ UTIL$(GCC_)=[.$(DEST)]UTIL_.OBJ \
+ ZIPFILE$(GCC_)=[.$(DEST)]ZIPFILE_.OBJ
+
+# Utility object library, normal, [.VMS].
+
+MODS_OBJS_LIB_ZIPUTILS_N_V = \
+ VMSMUNCH=[.$(DEST)]VMSMUNCH.OBJ
+
+# Utility object library, variant, [.VMS].
+
+MODS_OBJS_LIB_ZIPUTILS_U_V = \
+ VMS$(GCC_)=[.$(DEST)]VMS_.OBJ
+
+MODS_OBJS_LIB_ZIPUTILS = $(MODS_OBJS_LIB_ZIPUTILS_N) \
+ $(MODS_OBJS_LIB_ZIPUTILS_U) \
+ $(MODS_OBJS_LIB_ZIPUTILS_N_V) \
+ $(MODS_OBJS_LIB_ZIPUTILS_U_V) \
+
+# CLI object library, [.VMS].
+
+MODS_OBJS_LIB_ZIPCLI_C_V = \
+ CMDLINE=[.$(DEST)]CMDLINE.OBJ
+
+MODS_OBJS_LIB_ZIPCLI_CLD_V = \
+ ZIP_CLITABLE=[.$(DEST)]ZIP_CLI.OBJ
+
+MODS_OBJS_LIB_ZIPCLI = \
+ $(MODS_OBJS_LIB_ZIPCLI_C_V) \
+ $(MODS_OBJS_LIB_ZIPCLI_CLD_V)
+
+# Executables.
+
+ZIP = [.$(DEST)]ZIP.EXE
+
+ZIP_CLI = [.$(DEST)]ZIP_CLI.EXE
+
+ZIPUTILS = \
+ [.$(DEST)]ZIPCLOAK.EXE \
+ [.$(DEST)]ZIPNOTE.EXE \
+ [.$(DEST)]ZIPSPLIT.EXE
+
diff --git a/vms/find_bzip2_lib.com b/vms/find_bzip2_lib.com
new file mode 100644
index 0000000..21ebf7b
--- /dev/null
+++ b/vms/find_bzip2_lib.com
@@ -0,0 +1,71 @@
+$! 28 December 2006. SMS.
+$!
+$! Info-ZIP VMS accessory procedure.
+$!
+$! Find the BZIP2 object library under P1, starting in the [.'P2']
+$! destination directory. (We assume, initially, that the BZIP2
+$! directory has a destination directory structure like ours.)
+$!
+$! Set the P4 logical name to the directory where it was found.
+$! P5 and P6 may be used for qualifiers on the DEFINE command.
+$!
+$ bz_orig = p1
+$ dest = p2
+$ libbz2 = p3
+$!
+$! Remove any trailing colon, to allow logical name translation.
+$!
+$ bz_dev_dir = ""
+$ bz_base = bz_orig
+$ if (f$extract( (f$length( bz_base)- 1), 1, bz_base) .eqs. ":")
+$ then
+$ bz_base = bz_base- ":"
+$ endif
+$!
+$ bz_base_eqv = f$trnlnm( bz_base)
+$ if (bz_base_eqv .nes. "")
+$ then
+$ bz_orig = bz_base_eqv
+$ bz_base = bz_base_eqv
+$ endif
+$ bz_base = bz_base- "]"
+$!
+$! Candidate 1 = the actual analogue destination directory.
+$!
+$ bz_dev_dir_cand = bz_base+ "."+ dest+ "]"
+$ lib_cand = bz_dev_dir_cand+ libbz2
+$ if (f$search( lib_cand) .nes. "")
+$ then
+$ bz_dev_dir = bz_dev_dir_cand
+$ else
+$!
+$! Candidate 2 = the actual analogue destination directory + "L".
+$!
+$ bz_dev_dir_cand = bz_base+ "."+ dest+ "L]"
+$ lib_cand = bz_dev_dir_cand+ libbz2
+$ if (f$search( lib_cand) .nes. "")
+$ then
+$ bz_dev_dir = bz_dev_dir_cand
+$ else
+$!
+$! Candidate 3 = the actual user-specified directory.
+$!
+$ bz_dev_dir_cand = bz_orig
+$ lib_cand = bz_dev_dir_cand+ libbz2
+$ if (f$search( lib_cand) .nes. "")
+$ then
+$ bz_dev_dir = bz_dev_dir_cand
+$ endif
+$ endif
+$ endif
+$!
+$ if (bz_dev_dir .nes. "")
+$ then
+$ if (p4 .eqs. "")
+$ then
+$ write sys$output bz_dev_dir
+$ else
+$ define 'p5' 'p4' 'bz_dev_dir' 'p6'
+$ endif
+$ endif
+$!
diff --git a/vms/hlp_lib_next.com b/vms/hlp_lib_next.com
new file mode 100644
index 0000000..f9b14a5
--- /dev/null
+++ b/vms/hlp_lib_next.com
@@ -0,0 +1,17 @@
+$! 21 November 2004. SMS.
+$!
+$! HLP_LIB_NEXT.COM
+$!
+$! Find the next available HLP$LIBRARY[_*] logical name.
+$!
+$ base = "HLP$LIBRARY"
+$ candidate = base
+$ i = 0
+$!
+$ loop_top:
+$ if (i .gt. 0) then candidate = base+ "_"+ f$string( i)
+$ i = i+ 1
+$ if (f$trnlnm( candidate) .nes. "") then goto loop_top
+$!
+$ write sys$output candidate
+$!
diff --git a/vms/install_vms.txt b/vms/install_vms.txt
new file mode 100644
index 0000000..47dfebb
--- /dev/null
+++ b/vms/install_vms.txt
@@ -0,0 +1,158 @@
+
+ VMS (OpenVMS):
+
+ Building:
+
+ On VMS, two build methods are provided: a command procedure, and
+ description files for MMS or MMK. Both methods must be run from
+ the main directory, not the [.VMS] subdirectory.
+
+ A simple build using the command procedure looks like this:
+ @ [.VMS]BUILD_ZIP.COM
+
+ A simple build using MMS or MMK looks like this:
+ MMS /DESCRIP = [.VMS]DESCRIP.MMS ! Or, with MMK, ...
+ MMK /DESCRIP = [.VMS]DESCRIP.MMS
+
+ Various options for each build method are explained in comments in
+ the main builder file, either BUILD_ZIP.COM or DESCRIP.MMS.
+
+ Note that on non-VAX systems with VMS V7.2 or later (and with a
+ sufficiently new C compiler), Zip 3.0 can support files (both data
+ files and Zip archives) larger than 2GB. For the greatest
+ compatibility with previous Zip versions, the builders by default
+ create old-style small-file programs. The user must specify the
+ appropriate builder command-line option to create
+ large-file-capable programs.
+
+ Here are some more complex build examples:
+
+ o Build with the large-file option enabled (non-VAX only):
+
+ @ [.VMS]BUILD_ZIP LARGE
+ or:
+ MMS /DESC = [.VMS] /MACRO = LARGE=1
+
+ o Re-link the executables (small-file and large-file):
+
+ @ [.VMS]BUILD_ZIP LINK
+ @ [.VMS]BUILD_ZIP LARGE LINK
+ or
+ MMK /DESC = [.VMS] CLEAN_EXE ! Deletes existing executables.
+ MMK /DESC = [.VMS] ! Builds new executables.
+ MMK /DESC = [.VMS] /MACRO = LARGE=1 CLEAN_EXE
+ MMK /DESC = [.VMS] /MACRO = LARGE=1
+
+ o Build a large-file product from scratch, for debug, getting
+ compiler listings and link maps:
+
+ MMS /DESC = [.VMS] CLEAN
+ MMS /DESC = [.VMS] /MACRO = (DBG=1, LARGE=1. LIST=1)
+
+ On VAX, the builders attempt to cope with the various available C
+ compilers, DEC/Compaq/HP C, VAX C, or GNU C. If DEC/Compaq/HP C is
+ not available or not desired, comments in the relevant builder file
+ explain the command-line options used to select a different
+ compiler.
+
+ By default, Zip uses the "deflate" compression method. To add
+ support for the optional "bzip2" compression method, first obtain
+ and build the bzip2 software (http://www.bzip.org/ or, for a more
+ VMS-friendly kit, http://antinode.info/dec/sw/bzip2.html). Then,
+ define the macro IZ_BZIP2 on the BUILD_ZIP.COM or MMS/MMK command
+ line to specify the directory where the bzip2 files may be found.
+ For example:
+
+ @ [.VMS]BUILD_ZIP LARGE -
+ IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS]
+ or:
+ MMS /DESC = [.VMS] /MACRO = (LARGE=1, -
+ IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS])
+
+ Note that historically, Zip has been built with the default
+ compiler option, /NAMES = UPPERCASE, while bzip2 is normally built
+ with /NAMES = AS_IS, to avoid name collisions. With modern
+ compilers, the "#pragma names" directives in [.VMS]BZLIB.H will
+ handle these differences without user intervention. An old
+ compiler (for example, DEC C V4.0-000) will emit complaints
+ %CC-I-UNKNOWNPRAGMA, and will mishandle the bzip2 library function
+ names, which will cause the link to fail. To solve this problem,
+ either build the bzip2 BZ_NO_STDIO object library with /NAMES =
+ UPPERCASE, or else build Zip with /NAMES = AS_IS. For example:
+
+ @ [.VMS]BUILD_ZIP LARGE "CCOPTS=/NAMES=AS_IS" -
+ IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS]
+ or:
+ MMS /DESC = [.VMS] /MACRO = (LARGE=1, "CCOPTS=/NAMES=AS_IS", -
+ IZ_BZIP2=SYS$SYSDEVICE:[UTILITY.SOURCE.BZIP2.BZIP2-1_0_3C_VMS])
+
+ System-architecture-specific files (like objects and executables)
+ are placed in separate directories, such as [.ALPHA], [.IA64], or
+ [.VAX]. Large-file products get their own directories, [.ALPHAL]
+ or [.IA64L]. On VAX, VAX C products are placed in [.VAXV], GNU C
+ products in [.VAXG]. Each product builder announces what the
+ destination directory will be when it is run.
+
+ Common files, such as the help libraries (ZIP.HLP for the default
+ UNIX-like command-line interface, ZIP_CLI.HLP for the VMS-like
+ command-line interface), are placed in the main directory. With a
+ mixed-architecture VMS cluster, the same main directory on a shared
+ disk may be used by all system types. (Using the NOHELP option
+ with BUILD_ZIP.COM can keep it from making the same help files
+ repeatedly.) Building the help files is detailed below.
+
+ Completing installation:
+
+ To complete the installation, the executables may be left in place,
+ or moved (or copied) to a convenient place. While other methods
+ (like DCL$PATH) exist, most users define symbols to make the Zip
+ executables available as foreign commands. These symbol definitions
+ may be placed in a user's SYS$LOGIN:LOGIN.COM, or in a more central
+ location, like SYS$MANAGER:SYLOGIN.COM. Typical symbol definitions
+ might look like these:
+
+ ZIP :== $ dev:[dir]ZIP.EXE ! UNIX-like command line.
+ or:
+ ZIP :== $ dev:[dir]ZIP_CLI.EXE ! VMS-like command line.
+
+ On a non-VAX system, different symbols could be defined for the
+ small-file and large-file programs. For example:
+
+ ZIPS :== $ dev:[dir.ALPHA]ZIP.EXE ! ZIPS = small-file Zip.
+ ZIP*L :== $ dev:[dir.ALPHAL]ZIP.EXE ! ZIP[L] = large-file Zip.
+
+ The builders create help text files, ZIP.HLP and ZIP_CLI.HLP.
+ These may be incorporated into an existing help library, or a separate
+ Zip help library may be created using commands like these, using
+ either ZIP.HLP (as shown) or ZIP_CLI.HLP:
+
+ $ LIBRARY /HELP dev:[dir]existing_library.HLB ZIP.HLP
+
+ $ LIBRARY /CREATE /HELP ZIP.HLB ZIP.HLP
+
+ Zip help may then be accessed from a separate Zip help library
+ using a command like:
+
+ $ HELP /LIBRARY = device:[directory]ZIP.HLB
+
+ For greater ease, the user (or system manager) may define a
+ HLP$LIBRARY logical name to allow the HELP utility to find the Zip
+ help library automatically. See HELP HELP /USERLIBRARY for more
+ details. The command procedure HLP_LIB_NEXT.COM may be used to
+ determine the next available HLP$LIBRARY logical name, and could be
+ adapted to define a HLP$LIBRARY logical name for a Zip help library.
+
+ The builders also create VMS message files, ZIP_MSG.EXE, in the
+ destination directory with the program executables. A user may
+ gain DCL access to the Zip error messages using a command like:
+
+ $ SET MESSAGE device:[directory]ZIP_MSG.EXE
+
+ For system-wide access, the system manager may move or copy this
+ file to SYS$MESSAGE, although this could cause some confusion if
+ multiple versions of Zip are used on the system, and their error
+ message source files differ.
+
+ Some further information may be found in the files
+ [.VMS]00README.TXT and [.VMS]00BINARY.VMS, though much of what's
+ there is now obsolete.
diff --git a/vms/mod_dep.com b/vms/mod_dep.com
new file mode 100644
index 0000000..bbc6d2d
--- /dev/null
+++ b/vms/mod_dep.com
@@ -0,0 +1,33 @@
+$! 3 March 2005. SMS.
+$!
+$! Info-ZIP VMS accessory procedure.
+$!
+$! Modify a dependencies file (P1), changing the object file name to
+$! P2.
+$! P3 = output file specification.
+$!
+$!
+$ prefix = f$edit( p3, "COLLAPSE")
+$!
+$! Strip any device:[directory] from P2.
+$!
+$ obj_name = f$parse( P2, , , "NAME", "SYNTAX_ONLY")+ -
+ f$parse( P2, , , "TYPE", "SYNTAX_ONLY")
+$!
+$ open /read /error = end_main deps_in 'p1'
+$ open /write /error = end_main deps_out 'p3'
+$ on error then goto loop_main_end
+$ loop_main_top:
+$ read /error = loop_main_end deps_in line
+$ line_reduced = f$edit( line, "COMPRESS, TRIM")
+$ colon = f$locate( " : ", line_reduced)
+$ line = obj_name+ f$extract( colon, 2000, line)
+$ write deps_out "''line'"
+$ goto loop_main_top
+$!
+$ loop_main_end:
+$ close deps_in
+$ close deps_out
+$!
+$ end_main:
+$!
diff --git a/vms/osdep.h b/vms/osdep.h
new file mode 100644
index 0000000..d7a07a4
--- /dev/null
+++ b/vms/osdep.h
@@ -0,0 +1,178 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef VMS
+# define VMS 1
+#endif
+
+#if (defined(__VMS_VER) && !defined(__CRTL_VER))
+# define __CRTL_VER __VMS_VER
+#endif
+
+#if (defined(__VMS_VERSION) && !defined(VMS_VERSION))
+# define VMS_VERSION __VMS_VERSION
+#endif
+
+#if !(defined(__DECC) || defined(__DECCXX) || defined(__GNUC__))
+ /* VAX C does not properly support the void keyword. (Only functions
+ are allowed to have the type "void".) */
+# ifndef NO_TYPEDEF_VOID
+# define NO_TYPEDEF_VOID
+# endif
+# define NO_FCNTL_H /* VAXC does not supply fcntl.h. */
+#endif /* VAX C */
+
+#define USE_CASE_MAP
+#define PROCNAME(n) \
+ (((action == ADD) || (action == UPDATE) || (action == FRESHEN)) ? \
+ wild(n) : procname(n, filter_match_case))
+
+/* 2004-11-09 SMS.
+ Large file support.
+*/
+#ifdef LARGE_FILE_SUPPORT
+
+# define _LARGEFILE /* Define the pertinent macro. */
+
+/* LARGE_FILE_SUPPORT implies ZIP64_SUPPORT,
+ unless explicitly disabled by NO_ZIP64_SUPPORT.
+*/
+# ifdef NO_ZIP64_SUPPORT
+# ifdef ZIP64_SUPPORT
+# undef ZIP64_SUPPORT
+# endif /* def ZIP64_SUPPORT */
+# else /* def NO_ZIP64_SUPPORT */
+# ifndef ZIP64_SUPPORT
+# define ZIP64_SUPPORT
+# endif /* ndef ZIP64_SUPPORT */
+# endif /* def NO_ZIP64_SUPPORT */
+
+# define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+#else /* def LARGE_FILE_SUPPORT */
+
+# define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+
+#endif /* def LARGE_FILE_SUPPORT */
+
+/* Need _LARGEFILE for types.h. */
+
+#include <types.h>
+
+#ifdef __GNUC__
+#include <sys/types.h>
+#endif /* def __GNUC__ */
+
+/* Need types.h for off_t. */
+
+#ifdef LARGE_FILE_SUPPORT
+ typedef off_t zoff_t;
+ typedef unsigned long long uzoff_t;
+#else /* def LARGE_FILE_SUPPORT */
+ typedef long zoff_t;
+ typedef unsigned long uzoff_t;
+#endif /* def LARGE_FILE_SUPPORT */
+
+#include <stat.h>
+
+typedef struct stat z_stat;
+
+#include <unixio.h>
+
+#if defined(__GNUC__) && !defined(ZCRYPT_INTERNAL)
+# include <unixlib.h> /* ctermid() declaration needed in ttyio.c */
+#endif
+#ifdef ZCRYPT_INTERNAL
+# include <unixlib.h> /* getpid() declaration for srand seed */
+#endif
+
+#if defined(_MBCS)
+# undef _MBCS /* Zip on VMS does not support MBCS */
+#endif
+
+/* VMS is run on little-endian processors with 4-byte ints:
+ * enable the optimized CRC-32 code */
+#ifdef IZ_CRC_BE_OPTIMIZ
+# undef IZ_CRC_BE_OPTIMIZ
+#endif
+#if !defined(IZ_CRC_LE_OPTIMIZ) && !defined(NO_CRC_OPTIMIZ)
+# define IZ_CRC_LE_OPTIMIZ
+#endif
+#if !defined(IZ_CRCOPTIM_UNFOLDTBL) && !defined(NO_CRC_OPTIMIZ)
+# define IZ_CRCOPTIM_UNFOLDTBL
+#endif
+
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+# if (defined(__CRTL_VER) && (__CRTL_VER >= 70000000))
+# define USE_EF_UT_TIME
+# endif
+#endif
+
+#if defined(VMS_PK_EXTRA) && defined(VMS_IM_EXTRA)
+# undef VMS_IM_EXTRA /* PK style takes precedence */
+#endif
+#if !defined(VMS_PK_EXTRA) && !defined(VMS_IM_EXTRA)
+# define VMS_PK_EXTRA 1 /* PK style VMS support is default */
+#endif
+
+/* 2007-02-22 SMS.
+ * <unistd.h> is needed for symbolic link functions, so use it when the
+ * symbolic link criteria are met.
+ */
+#if defined(__VAX) || __CRTL_VER < 70301000
+# define NO_UNISTD_H
+# define NO_SYMLINKS
+#endif /* defined(__VAX) || __CRTL_VER < 70301000 */
+
+/* 2007-02-22 SMS. Use delete() when unlink() is not available. */
+#if defined(NO_UNISTD_H) || (__CRTL_VER < 70000000)
+# define unlink delete
+#endif /* defined(NO_UNISTD_H) || __CRTL_VER < 70000000) */
+
+#define SSTAT vms_stat
+#define EXIT(exit_code) vms_exit(exit_code)
+#define RETURN(exit_code) return (vms_exit(exit_code), 1)
+
+
+#ifdef __DECC
+
+/* File open callback ID values. */
+
+# define FOPM_ID 1
+# define FOPR_ID 2
+# define FOPW_ID 3
+
+/* File open callback ID storage. */
+
+extern int fopm_id;
+extern int fopr_id;
+extern int fopw_id;
+
+/* File open callback ID function. */
+
+extern int acc_cb();
+
+/* Option macros for zfopen().
+ * General: Stream access
+ * Output: fixed-length, 512-byte records.
+ *
+ * Callback function (DEC C only) sets deq, mbc, mbf, rah, wbh, ...
+ */
+
+# define FOPM "r+b", "ctx=stm", "rfm=fix", "mrs=512", "acc", acc_cb, &fopm_id
+# define FOPR "rb", "ctx=stm", "acc", acc_cb, &fopr_id
+# define FOPW "wb", "ctx=stm", "rfm=fix", "mrs=512", "acc", acc_cb, &fopw_id
+
+#else /* def __DECC */ /* (So, GNU C, VAX C, ...)*/
+
+# define FOPM "r+b", "ctx=stm", "rfm=fix", "mrs=512"
+# define FOPR "rb", "ctx=stm"
+# define FOPW "wb", "ctx=stm", "rfm=fix", "mrs=512"
+
+#endif /* def __DECC */
+
diff --git a/vms/stream_lf.fdl b/vms/stream_lf.fdl
new file mode 100644
index 0000000..ab0f907
--- /dev/null
+++ b/vms/stream_lf.fdl
@@ -0,0 +1,3 @@
+RECORD
+ Carriage_Control carriage_return
+ Format stream_lf
diff --git a/vms/unixio_gcc.h b/vms/unixio_gcc.h
new file mode 100644
index 0000000..05bc421
--- /dev/null
+++ b/vms/unixio_gcc.h
@@ -0,0 +1,27 @@
+/* 2004-12-12 SMS.
+ *
+ * Emergency replacement UNIXIO.H for GNU C, for use as needed.
+ * Install as GNU_CC_INCLUDE:[000000]UNIXIO.H
+ */
+
+#ifndef __UNIXIO_LOADED
+#define __UNIXIO_LOADED 1
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif /* ndef SEEK_SET */
+
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif /* ndef SEEK_CUR */
+
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif /* ndef SEEK_END */
+
+#endif /* ndef __UNIXIO_LOADED */
+
diff --git a/vms/unixlib_gcc.h b/vms/unixlib_gcc.h
new file mode 100644
index 0000000..eda4ed9
--- /dev/null
+++ b/vms/unixlib_gcc.h
@@ -0,0 +1,16 @@
+/* 2004-12-12 SMS.
+ *
+ * Emergency replacement UNIXLIB.H for GNU C, for use as needed.
+ * Install as GNU_CC_INCLUDE:[000000]UNIXLIB.H
+ */
+
+#ifndef __UNIXLIB_LOADED
+#define __UNIXLIB_LOADED 1
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+typedef struct stat stat_t;
+
+#endif /* ndef __UNIXLIB_LOADED */
+
diff --git a/vms/vms.c b/vms/vms.c
new file mode 100644
index 0000000..1b194c6
--- /dev/null
+++ b/vms/vms.c
@@ -0,0 +1,1007 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * vms.c (zip) by Igor Mandrichenko Version 2.2-2
+ *
+ * Revision history:
+ * ...
+ * 2.2-2 18-jan-1993 I.Mandrichenko
+ * vms_stat() added - version of stat() that handles special
+ * case when end-of-file-block == 0
+ *
+ * 3.0 11-oct-2004 SMS
+ * It would be nice to know why vms_stat() is needed. If EOF can't
+ * be trusted for a zero-length file, why trust it for any file?
+ * Anyway, I removed the (int) cast on ->st_size, which may now be
+ * bigger than an int, just in case this code ever does get used.
+ * (A true zero-length file should still report zero length, even
+ * after the long fight with RMS.)
+ * Moved the VMS_PK_EXTRA test(s) into VMS_IM.C and VMS_PK.C to
+ * allow more general automatic dependency generation.
+ */
+
+#ifdef VMS /* For VMS only ! */
+
+#define NO_ZIPUP_H /* Prevent full inclusion of vms/zipup.h. */
+
+#include "zip.h"
+#include "zipup.h" /* Only partial. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <jpidef.h>
+#include <fab.h> /* Needed only in old environments. */
+#include <nam.h> /* Needed only in old environments. */
+#include <starlet.h>
+#include <ssdef.h>
+#include <stsdef.h>
+
+/* On VAX, define Goofy VAX Type-Cast to obviate /standard = vaxc.
+ Otherwise, lame system headers on VAX cause compiler warnings.
+ (GNU C may define vax but not __VAX.)
+*/
+#ifdef vax
+# define __VAX 1
+#endif /* def vax */
+
+#ifdef __VAX
+# define GVTC (unsigned int)
+#else /* def __VAX */
+# define GVTC
+#endif /* def __VAX */
+
+
+#ifdef UTIL
+
+/* For utilities, include only vms.h, as either of the vms_XX.c files
+ * would do.
+ */
+
+# include "vms.h"
+
+#else /* not UTIL */
+
+/* Include the `VMS attributes' preserving file-io code. We distinguish
+ between two incompatible flavours of storing VMS attributes in the
+ Zip archive:
+ a) The "PKware" style follows the extra field specification for
+ PKware's VMS Zip.
+ b) The "IM (Info-ZIP)" flavour was defined from scratch by
+ Igor Mandrichenko. This version has be used in official Info-ZIP
+ releases for several years and is known to work well.
+ */
+
+/* Note that only one of these #include directives will include any
+ * active code, depending on VMS_PK_EXTRA. Both are included here (and
+ * tested there) to allow more general automatic dependency generation.
+ */
+
+#include "vms_pk.c"
+#include "vms_im.c"
+
+#endif /* not UTIL [else] */
+
+#ifndef ERR
+#define ERR(x) (((x)&1)==0)
+#endif
+
+#ifndef NULL
+#define NULL (void*)(0L)
+#endif
+
+int vms_stat( char *file, stat_t *s)
+{
+ int status;
+ int staterr;
+ struct FAB fab;
+ struct NAM_STRUCT nam;
+ struct XABFHC fhc;
+
+ /*
+ * In simplest case when stat() returns "ok" and file size is
+ * nonzero or this is directory, finish with this
+ */
+
+ if( (staterr=stat(file,s)) == 0
+ && ( s->st_size >= 0 /* Size - ok */
+ || (s->st_mode & S_IFREG) == 0 /* Not a plain file */
+ )
+ ) return staterr;
+
+ /*
+ * Get here to handle the special case when stat() returns
+ * invalid file size. Use RMS to compute the size.
+ * When EOF block is zero, set file size to its physical size.
+ * One more case to get here is when this is remote file accessed
+ * via DECnet.
+ */
+
+ fab = cc$rms_fab;
+ nam = CC_RMS_NAM;
+ fhc = cc$rms_xabfhc;
+ fab.FAB_NAM = &nam;
+ fab.fab$l_xab = (char*)(&fhc);
+
+#ifdef NAML$C_MAXRSS
+
+ fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
+ fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = file;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( file);
+
+ fab.fab$b_fac = FAB$M_GET;
+
+ status = sys$open(&fab);
+ fab.fab$l_xab = (char*)0L;
+ sys$close(&fab);
+
+ if( !ERR(status) )
+ {
+ if( fhc.xab$l_ebk > 0 )
+ s->st_size = ( fhc.xab$l_ebk-1 ) * 512 + fhc.xab$w_ffb;
+ else if( fab.fab$b_org == FAB$C_IDX
+ || fab.fab$b_org == FAB$C_REL
+ || fab.fab$b_org == FAB$C_HSH )
+ /* Special case, when ebk=0: save entire allocated space */
+ s->st_size = fhc.xab$l_hbk * 512;
+ else
+ s->st_size = fhc.xab$w_ffb;
+ return 0; /* stat() success code */
+ }
+ else
+ return status;
+}
+
+
+/*
+ * 2007-01-29 SMS.
+ *
+ * VMS Status Code Summary (See STSDEF.H for details.)
+ *
+ * Bits: 31:28 27:16 15:3 2:0
+ * Field: Control Facility Message Severity
+ *
+ * In the Control field, bits 31:29 are reserved. Bit 28 inhibits
+ * printing the message. In the Facility field, bit 27 means
+ * customer-defined (not HP-assigned, like us). In the Message field,
+ * bit 15 means facility-specific (which our messages are). The
+ * Severity codes are 0 = Warning, 1 = Success, 2 = Error, 3 = Info,
+ * 4 = Severe (fatal).
+ *
+ * Previous versions of Info-ZIP programs used a generic ("chosen (by
+ * experimentation)") Control+Facility code of 0x7FFF, which included
+ * some reserved control bits, the inhibit-printing bit, and the
+ * customer-defined bit.
+ *
+ * HP has now assigned official Facility names and corresponding
+ * Facility codes for the Info-ZIP products:
+ *
+ * Facility Name Facility Code
+ * IZ_UNZIP 1954 = 0x7A2
+ * IZ_ZIP 1955 = 0x7A3
+ *
+ * Now, unless the CTL_FAC_IZ_ZIP macro is defined at build-time, we
+ * will use the official Facility code.
+ *
+ */
+
+/* Official HP-assigned Info-ZIP Zip Facility code. */
+#define FAC_IZ_ZIP 1955 /* 0x7A3 */
+
+#ifndef CTL_FAC_IZ_ZIP
+ /*
+ * Default is inhibit-printing with the official Facility code.
+ */
+# define CTL_FAC_IZ_ZIP ((0x1 << 12)| FAC_IZ_ZIP)
+# define MSG_FAC_SPEC 0x8000 /* Facility-specific code. */
+#else /* ndef CTL_FAC_IZ_ZIP */
+ /* Use the user-supplied Control+Facility code for err or warn. */
+# define OLD_STATUS
+# ifndef MSG_FAC_SPEC /* Old default is not Facility-specific. */
+# define MSG_FAC_SPEC 0x0 /* Facility-specific code. Or 0x8000. */
+# endif /* ndef MSG_FAC_SPEC */
+#endif /* ndef CTL_FAC_IZ_ZIP [else] */
+
+
+/* Return an intelligent status/severity code. */
+
+void vms_exit(e)
+ int e;
+{
+ {
+#ifndef OLD_STATUS
+
+ /*
+ * Exit with code comprising Control, Facility, (facility-specific)
+ * Message, and Severity.
+ */
+ exit( (CTL_FAC_IZ_ZIP << 16) | /* Facility */
+ MSG_FAC_SPEC | /* Facility-specific */
+ (e << 4) | /* Message code */
+ (ziperrors[ e].severity & 0x07) /* Severity */
+ );
+
+#else /* ndef OLD_STATUS */
+
+ /* 2007-01-17 SMS.
+ * Defining OLD_STATUS provides the same behavior as in Zip versions
+ * before an official VMS Facility code had been assigned, which
+ * means that Success (ZE_OK) gives a status value of 1 (SS$_NORMAL)
+ * with no Facility code, while any error or warning gives a status
+ * value which includes a Facility code. (Curiously, under the old
+ * scheme, message codes were left-shifted by 4 instead of 3,
+ * resulting in all-even message codes.) I don't like this, but I
+ * was afraid to remove it, as someone, somewhere may be depending
+ * on it. Define CTL_FAC_IZ_ZIP as 0x7FFF to get the old behavior.
+ * Define only OLD_STATUS to get the old behavior for Success
+ * (ZE_OK), but using the official HP-assigned Facility code for an
+ * error or warning. Define MSG_FAC_SPEC to get the desired
+ * behavior.
+ *
+ * Exit with simple SS$_NORMAL for ZE_OK. Otherwise, exit with code
+ * comprising Control, Facility, Message, and Severity.
+ */
+ exit(
+ (e == ZE_OK) ? SS$_NORMAL : /* Success (others below) */
+ ((CTL_FAC_IZ_ZIP << 16) | /* Facility */
+ MSG_FAC_SPEC | /* Facility-specific (?) */
+ (e << 4) | /* Message code */
+ (ziperrors[ e].severity & 0x07) /* Severity */
+ )
+ );
+
+#endif /* ndef OLD_STATUS */
+ }
+}
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#ifdef VMS_VERSION
+ char *chrp1;
+ char *chrp2;
+ char buf[40];
+ char vms_vers[ 16];
+ int ver_maj;
+#endif
+#ifdef __DECC_VER
+ char buf2[40];
+ int vtyp;
+#endif
+
+#ifdef VMS_VERSION
+ /* Truncate the version string at the first (trailing) space. */
+ strncpy( vms_vers, VMS_VERSION, sizeof( vms_vers));
+ chrp1 = strchr( vms_vers, ' ');
+ if (chrp1 != NULL)
+ *chrp1 = '\0';
+
+ /* Determine the major version number. */
+ ver_maj = 0;
+ chrp1 = strchr( &vms_vers[ 1], '.');
+ for (chrp2 = &vms_vers[ 1];
+ chrp2 < chrp1;
+ ver_maj = ver_maj* 10+ *(chrp2++)- '0');
+
+#endif /* def VMS_VERSION */
+
+/* DEC C in ANSI mode does not like "#ifdef MACRO" inside another
+ macro when MACRO is equated to a value (by "#define MACRO 1"). */
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+# if defined(DECC) || defined(__DECC) || defined (__DECC__)
+ "DEC C",
+# ifdef __DECC_VER
+ (sprintf(buf2, " %c%d.%d-%03d",
+ ((vtyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
+ (vtyp == 8 ? 'S' : 'V')),
+ __DECC_VER / 10000000,
+ (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000), buf2),
+# else
+ "",
+# endif
+# else
+# ifdef VAXC
+ "VAX C", "",
+# else
+ "unknown compiler", "",
+# endif
+# endif
+#endif
+
+#ifdef VMS_VERSION
+# if defined( __alpha)
+ "OpenVMS",
+ (sprintf( buf, " (%s Alpha)", vms_vers), buf),
+# elif defined( __ia64) /* defined( __alpha) */
+ "OpenVMS",
+ (sprintf( buf, " (%s IA64)", vms_vers), buf),
+# else /* defined( __alpha) */
+ (ver_maj >= 6) ? "OpenVMS" : "VMS",
+ (sprintf( buf, " (%s VAX)", vms_vers), buf),
+# endif /* defined( __alpha) */
+#else
+ "VMS",
+ "",
+#endif /* def VMS_VERSION */
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
+
+/* 2004-10-08 SMS.
+ *
+ * tempname() for VMS.
+ *
+ * Generate a temporary Zip archive file name, near the actual
+ * destination Zip archive file, or at "tempath", if specified.
+ *
+ * Using sys$parse() is probably more work than it's worth, but it
+ * should also be ODS5-safe.
+ *
+ * Note that the generic method using tmpnam() (in FILEIO.C)
+ * produces "ziXXXXXX", where "XXXXXX" is the low six digits of the
+ * decimal representation of the process ID. This method produces
+ * "ZIxxxxxxxx", where "xxxxxxxx" is the (whole) eight-digit
+ * hexadecimal representation of the process ID. More important, it
+ * actually uses the directory part of the argument or "tempath".
+ */
+
+
+char *tempname( char *zip)
+/* char *zip; */ /* Path name of Zip archive. */
+{
+ char *temp_name; /* Return value. */
+ int sts; /* System service status. */
+
+ static int pid; /* Process ID. */
+ static int pid_len; /* Returned size of process ID. */
+
+ struct /* Item list for GETJPIW. */
+ {
+ short buf_len; /* Buffer length. */
+ short itm_cod; /* Item code. */
+ int *buf; /* Buffer address. */
+ int *ret_len; /* Returned length. */
+ int term; /* Item list terminator. */
+ } jpi_itm_lst = { sizeof( pid), JPI$_PID, &pid, &pid_len };
+
+ /* ZI<UNIQUE> name storage. */
+ static char zip_tmp_nam[ 16] = "ZI<unique>.;";
+
+ struct FAB fab; /* FAB structure. */
+ struct NAM_STRUCT nam; /* NAM[L] structure. */
+
+ char exp_str[ NAM_MAXRSS+ 1]; /* Expanded name storage. */
+
+#ifdef VMS_UNIQUE_TEMP_BY_TIME
+
+ /* Use alternate time-based scheme to generate a unique temporary name. */
+ sprintf( &zip_tmp_nam[ 2], "%08X", time( NULL));
+
+#else /* def VMS_UNIQUE_TEMP_BY_TIME */
+
+ /* Use the process ID to generate a unique temporary name. */
+ sts = sys$getjpiw( 0, 0, 0, &jpi_itm_lst, 0, 0, 0);
+ sprintf( &zip_tmp_nam[ 2], "%08X", pid);
+
+#endif /* def VMS_UNIQUE_TEMP_BY_TIME */
+
+ /* Smoosh the unique temporary name against the actual Zip archive
+ name (or "tempath") to create the full temporary path name.
+ (Truncate it at the file type to remove any file type.)
+ */
+ if (tempath != NULL) /* Use "tempath", if it's been specified. */
+ zip = tempath;
+
+ /* Initialize the FAB and NAM[L], and link the NAM[L] to the FAB. */
+ fab = cc$rms_fab;
+ nam = CC_RMS_NAM;
+ fab.FAB_NAM = &nam;
+
+ /* Point the FAB/NAM[L] fields to the actual name and default name. */
+
+#ifdef NAML$C_MAXRSS
+
+ fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
+ fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ /* Default name = Zip archive name. */
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = zip;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = strlen( zip);
+
+ /* File name = "ZI<unique>,;". */
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = zip_tmp_nam;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( zip_tmp_nam);
+
+ nam.NAM_ESA = exp_str; /* Expanded name (result) storage. */
+ nam.NAM_ESS = NAM_MAXRSS; /* Size of expanded name storage. */
+
+ nam.NAM_NOP = NAM_M_SYNCHK; /* Syntax-only analysis. */
+
+ temp_name = NULL; /* Prepare for failure (unlikely). */
+ sts = sys$parse( &fab, 0, 0); /* Parse the name(s). */
+
+ if ((sts& STS$M_SEVERITY) == STS$M_SUCCESS)
+ {
+ /* Overlay any resulting file type (typically ".ZIP") with none. */
+ strcpy( nam.NAM_L_TYPE, ".;");
+
+ /* Allocate temp name storage (as caller expects), and copy the
+ (truncated) temp name into the new location.
+ */
+ temp_name = malloc( strlen( nam.NAM_ESA)+ 1);
+
+ if (temp_name != NULL)
+ {
+ strcpy( temp_name, nam.NAM_ESA);
+ }
+ }
+ return temp_name;
+} /* tempname() for VMS. */
+
+
+/* 2005-02-17 SMS.
+ *
+ * ziptyp() for VMS.
+ *
+ * Generate a real Zip archive file name (exact, if it exists), using
+ * a default file name.
+ *
+ * 2005-02-17 SMS. Moved to here from [-]ZIPFILE.C, to segregate
+ * better the RMS stuff.
+ *
+ * Before 2005-02-17, if sys$parse() failed, ziptyp() returned a null
+ * string ("&zero", where "static char zero = '\0';"). This
+ * typically caused Zip to proceed, but then the final rename() of
+ * the temporary archive would (silently) fail (null file name, after
+ * all), leaving only the temporary archive file, and providing no
+ * warning message to the victim. Now, when sys$parse() fails,
+ * ziptyp() returns the original string, so a later open() fails, and
+ * a relatively informative message is provided. (A VMS-specific
+ * message could also be provided here, if desired.)
+ *
+ * 2005-09-16 SMS.
+ * Changed name parsing in ziptyp() to solve a problem with a
+ * search-list logical name device-directory spec for the zipfile.
+ * Previously, when the zipfile did not exist (so sys$search()
+ * failed), the expanded name was used, but as it was
+ * post-sys$search(), it was based on the _last_ member of the search
+ * list instead of the first. Now, the expanded name from the
+ * original sys$parse() (pre-sys$search()) is retained, and it is
+ * used if sys$search() fails. This name is based on the first
+ * member of the search list, as a user might expect.
+ */
+
+/* Default Zip archive file spec. */
+#define DEF_DEVDIRNAM "SYS$DISK:[].zip"
+
+char *ziptyp( char *s)
+{
+ int status;
+ int exp_len;
+ struct FAB fab;
+ struct NAM_STRUCT nam;
+ char result[ NAM_MAXRSS+ 1];
+ char exp[ NAM_MAXRSS+ 1];
+ char *p;
+
+ fab = cc$rms_fab; /* Initialize FAB. */
+ nam = CC_RMS_NAM; /* Initialize NAM[L]. */
+ fab.FAB_NAM = &nam; /* FAB -> NAM[L] */
+
+#ifdef NAML$C_MAXRSS
+
+ fab.fab$l_dna =(char *) -1; /* Using NAML for default name. */
+ fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ /* Argument file name and length. */
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = s;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( s);
+
+ /* Default file spec and length. */
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = DEF_DEVDIRNAM;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = sizeof( DEF_DEVDIRNAM)- 1;
+
+ nam.NAM_ESA = exp; /* Expanded name, */
+ nam.NAM_ESS = NAM_MAXRSS; /* storage size. */
+ nam.NAM_RSA = result; /* Resultant name, */
+ nam.NAM_RSS = NAM_MAXRSS; /* storage size. */
+
+ status = sys$parse(&fab);
+ if ((status & 1) == 0)
+ {
+ /* Invalid file name. Return (re-allocated) original, and hope
+ for a later error message.
+ */
+ if ((p = malloc( strlen( s)+ 1)) != NULL )
+ {
+ strcpy( p, s);
+ }
+ return p;
+ }
+
+ /* Save expanded name length from sys$parse(). */
+ exp_len = nam.NAM_ESL;
+
+ /* Leave expanded name as-is, in case of search failure. */
+ nam.NAM_ESA = NULL; /* Expanded name, */
+ nam.NAM_ESS = 0; /* storage size. */
+
+ status = sys$search(&fab);
+ if (status & 1)
+ { /* Zip file exists. Use resultant (complete, exact) name. */
+ if ((p = malloc( nam.NAM_RSL+ 1)) != NULL )
+ {
+ result[ nam.NAM_RSL] = '\0';
+ strcpy( p, result);
+ }
+ }
+ else
+ { /* New Zip file. Use pre-search expanded name. */
+ if ((p = malloc( exp_len+ 1)) != NULL )
+ {
+ exp[ exp_len] = '\0';
+ strcpy( p, exp);
+ }
+ }
+ return p;
+} /* ziptyp() for VMS. */
+
+
+/* 2005-12-30 SMS.
+ *
+ * vms_file_version().
+ *
+ * Return the ";version" part of a VMS file specification.
+ */
+
+char *vms_file_version( char *s)
+{
+ int status;
+ struct FAB fab;
+ struct NAM_STRUCT nam;
+ char *p;
+
+ static char exp[ NAM_MAXRSS+ 1]; /* Expanded name storage. */
+
+
+ fab = cc$rms_fab; /* Initialize FAB. */
+ nam = CC_RMS_NAM; /* Initialize NAM[L]. */
+ fab.FAB_NAM = &nam; /* FAB -> NAM[L] */
+
+#ifdef NAML$C_MAXRSS
+
+ fab.fab$l_dna =(char *) -1; /* Using NAML for default name. */
+ fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ /* Argument file name and length. */
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = s;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( s);
+
+ nam.NAM_ESA = exp; /* Expanded name, */
+ nam.NAM_ESS = NAM_MAXRSS; /* storage size. */
+
+ nam.NAM_NOP = NAM_M_SYNCHK; /* Syntax-only analysis. */
+
+ status = sys$parse(&fab);
+
+ if ((status & 1) == 0)
+ {
+ /* Invalid file name. Return "". */
+ exp[ 0] = '\0';
+ p = exp;
+ }
+ else
+ {
+ /* Success. NUL-terminate, and return a pointer to the ";" in
+ the expanded name storage buffer.
+ */
+ p = nam.NAM_L_VER;
+ p[ nam.NAM_B_VER] = '\0';
+ }
+ return p;
+} /* vms_file_version(). */
+
+
+/* 2004-11-23 SMS.
+ *
+ * get_rms_defaults().
+ *
+ * Get user-specified values from (DCL) SET RMS_DEFAULT. FAB/RAB
+ * items of particular interest are:
+ *
+ * fab$w_deq default extension quantity (blocks) (write).
+ * rab$b_mbc multi-block count.
+ * rab$b_mbf multi-buffer count (used with rah and wbh).
+ */
+
+#define DIAG_FLAG (verbose >= 2)
+
+/* Default RMS parameter values. */
+
+#define RMS_DEQ_DEFAULT 16384 /* About 1/4 the max (65535 blocks). */
+#define RMS_MBC_DEFAULT 127 /* The max, */
+#define RMS_MBF_DEFAULT 2 /* Enough to enable rah and wbh. */
+
+/* GETJPI item descriptor structure. */
+typedef struct
+ {
+ short buf_len;
+ short itm_cod;
+ void *buf;
+ int *ret_len;
+ } jpi_item_t;
+
+/* Durable storage */
+
+static int rms_defaults_known = 0;
+
+/* JPI item buffers. */
+static unsigned short rms_ext;
+static char rms_mbc;
+static unsigned char rms_mbf;
+
+/* Active RMS item values. */
+unsigned short rms_ext_active;
+char rms_mbc_active;
+unsigned char rms_mbf_active;
+
+/* GETJPI item lengths. */
+static int rms_ext_len; /* Should come back 2. */
+static int rms_mbc_len; /* Should come back 1. */
+static int rms_mbf_len; /* Should come back 1. */
+
+/* Desperation attempts to define unknown macros. Probably doomed.
+ * If these get used, expect sys$getjpiw() to return %x00000014 =
+ * %SYSTEM-F-BADPARAM, bad parameter value.
+ * They keep compilers with old header files quiet, though.
+ */
+#ifndef JPI$_RMS_EXTEND_SIZE
+# define JPI$_RMS_EXTEND_SIZE 542
+#endif /* ndef JPI$_RMS_EXTEND_SIZE */
+
+#ifndef JPI$_RMS_DFMBC
+# define JPI$_RMS_DFMBC 535
+#endif /* ndef JPI$_RMS_DFMBC */
+
+#ifndef JPI$_RMS_DFMBFSDK
+# define JPI$_RMS_DFMBFSDK 536
+#endif /* ndef JPI$_RMS_DFMBFSDK */
+
+/* GETJPI item descriptor set. */
+
+struct
+ {
+ jpi_item_t rms_ext_itm;
+ jpi_item_t rms_mbc_itm;
+ jpi_item_t rms_mbf_itm;
+ int term;
+ } jpi_itm_lst =
+ { { 2, JPI$_RMS_EXTEND_SIZE, &rms_ext, &rms_ext_len },
+ { 1, JPI$_RMS_DFMBC, &rms_mbc, &rms_mbc_len },
+ { 1, JPI$_RMS_DFMBFSDK, &rms_mbf, &rms_mbf_len },
+ 0
+ };
+
+int get_rms_defaults()
+{
+int sts;
+
+/* Get process RMS_DEFAULT values. */
+
+sts = sys$getjpiw( 0, 0, 0, &jpi_itm_lst, 0, 0, 0);
+if ((sts& STS$M_SEVERITY) != STS$M_SUCCESS)
+ {
+ /* Failed. Don't try again. */
+ rms_defaults_known = -1;
+ }
+else
+ {
+ /* Fine, but don't come back. */
+ rms_defaults_known = 1;
+ }
+
+/* Limit the active values according to the RMS_DEFAULT values. */
+
+if (rms_defaults_known > 0)
+ {
+ /* Set the default values. */
+
+ rms_ext_active = RMS_DEQ_DEFAULT;
+ rms_mbc_active = RMS_MBC_DEFAULT;
+ rms_mbf_active = RMS_MBF_DEFAULT;
+
+ /* Default extend quantity. Use the user value, if set. */
+ if (rms_ext > 0)
+ {
+ rms_ext_active = rms_ext;
+ }
+
+ /* Default multi-block count. Use the user value, if set. */
+ if (rms_mbc > 0)
+ {
+ rms_mbc_active = rms_mbc;
+ }
+
+ /* Default multi-buffer count. Use the user value, if set. */
+ if (rms_mbf > 0)
+ {
+ rms_mbf_active = rms_mbf;
+ }
+ }
+
+if (DIAG_FLAG)
+ {
+ fprintf( stderr,
+ "Get RMS defaults. getjpi sts = %%x%08x.\n",
+ sts);
+
+ if (rms_defaults_known > 0)
+ {
+ fprintf( stderr,
+ " Default: deq = %6d, mbc = %3d, mbf = %3d.\n",
+ rms_ext, rms_mbc, rms_mbf);
+ }
+ }
+return sts;
+}
+
+#ifdef __DECC
+
+/* 2004-11-23 SMS.
+ *
+ * acc_cb(), access callback function for DEC C zfopen().
+ *
+ * Set some RMS FAB/RAB items, with consideration of user-specified
+ * values from (DCL) SET RMS_DEFAULT. Items of particular interest are:
+ *
+ * fab$w_deq default extension quantity (blocks).
+ * rab$b_mbc multi-block count.
+ * rab$b_mbf multi-buffer count (used with rah and wbh).
+ *
+ * See also the FOP* macros in OSDEP.H. Currently, no notice is
+ * taken of the caller-ID value, but options could be set differently
+ * for read versus write access. (I assume that specifying fab$w_deq,
+ * for example, for a read-only file has no ill effects.)
+ */
+
+/* Global storage. */
+
+int fopm_id = FOPM_ID; /* Callback id storage, modify. */
+int fopr_id = FOPR_ID; /* Callback id storage, read. */
+int fopw_id = FOPW_ID; /* Callback id storage, write. */
+
+int fhow_id = FHOW_ID; /* Callback id storage, in read. */
+
+/* acc_cb() */
+
+int acc_cb( int *id_arg, struct FAB *fab, struct RAB *rab)
+{
+int sts;
+
+/* Get process RMS_DEFAULT values, if not already done. */
+if (rms_defaults_known == 0)
+ {
+ get_rms_defaults();
+ }
+
+/* If RMS_DEFAULT (and adjusted active) values are available, then set
+ * the FAB/RAB parameters. If RMS_DEFAULT values are not available,
+ * suffer with the default parameters.
+ */
+if (rms_defaults_known > 0)
+ {
+ /* Set the FAB/RAB parameters accordingly. */
+ fab-> fab$w_deq = rms_ext_active;
+ rab-> rab$b_mbc = rms_mbc_active;
+ rab-> rab$b_mbf = rms_mbf_active;
+
+ /* Truncate at EOF on close, as we'll probably over-extend. */
+ fab-> fab$v_tef = 1;
+
+ /* If using multiple buffers, enable read-ahead and write-behind. */
+ if (rms_mbf_active > 1)
+ {
+ rab-> rab$v_rah = 1;
+ rab-> rab$v_wbh = 1;
+ }
+
+ if (DIAG_FLAG)
+ {
+ fprintf( mesg,
+ "Open callback. ID = %d, deq = %6d, mbc = %3d, mbf = %3d.\n",
+ *id_arg, fab-> fab$w_deq, rab-> rab$b_mbc, rab-> rab$b_mbf);
+ }
+ }
+
+/* Declare success. */
+return 0;
+}
+
+#endif /* def __DECC */
+
+/*
+ * 2004-09-19 SMS.
+ *
+ *----------------------------------------------------------------------
+ *
+ * decc_init()
+ *
+ * On non-VAX systems, uses LIB$INITIALIZE to set a collection of C
+ * RTL features without using the DECC$* logical name method.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#ifdef __DECC
+
+#ifdef __CRTL_VER
+
+#if !defined( __VAX) && (__CRTL_VER >= 70301000)
+
+#include <unixlib.h>
+
+/*--------------------------------------------------------------------*/
+
+/* Global storage. */
+
+/* Flag to sense if decc_init() was called. */
+
+int decc_init_done = -1;
+
+/*--------------------------------------------------------------------*/
+
+/* decc_init()
+
+ Uses LIB$INITIALIZE to set a collection of C RTL features without
+ requiring the user to define the corresponding logical names.
+*/
+
+/* Structure to hold a DECC$* feature name and its desired value. */
+
+typedef struct
+ {
+ char *name;
+ int value;
+ } decc_feat_t;
+
+/* Array of DECC$* feature names and their desired values. */
+
+decc_feat_t decc_feat_array[] = {
+
+ /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
+ { "DECC$ARGV_PARSE_STYLE", 1 },
+
+ /* Preserve case for file names on ODS5 disks. */
+ { "DECC$EFS_CASE_PRESERVE", 1 },
+
+ /* Enable multiple dots (and most characters) in ODS5 file names,
+ while preserving VMS-ness of ";version". */
+ { "DECC$EFS_CHARSET", 1 },
+
+ /* List terminator. */
+ { (char *)NULL, 0 } };
+
+/* LIB$INITIALIZE initialization function. */
+
+static void decc_init( void)
+{
+int feat_index;
+int feat_value;
+int feat_value_max;
+int feat_value_min;
+int i;
+int sts;
+
+/* Set the global flag to indicate that LIB$INITIALIZE worked. */
+
+decc_init_done = 1;
+
+/* Loop through all items in the decc_feat_array[]. */
+
+for (i = 0; decc_feat_array[ i].name != NULL; i++)
+ {
+ /* Get the feature index. */
+ feat_index = decc$feature_get_index( decc_feat_array[ i].name);
+ if (feat_index >= 0)
+ {
+ /* Valid item. Collect its properties. */
+ feat_value = decc$feature_get_value( feat_index, 1);
+ feat_value_min = decc$feature_get_value( feat_index, 2);
+ feat_value_max = decc$feature_get_value( feat_index, 3);
+
+ if ((decc_feat_array[ i].value >= feat_value_min) &&
+ (decc_feat_array[ i].value <= feat_value_max))
+ {
+ /* Valid value. Set it if necessary. */
+ if (feat_value != decc_feat_array[ i].value)
+ {
+ sts = decc$feature_set_value( feat_index,
+ 1,
+ decc_feat_array[ i].value);
+ }
+ }
+ else
+ {
+ /* Invalid DECC feature value. */
+ printf( " INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n",
+ feat_value,
+ feat_value_min, decc_feat_array[ i].name, feat_value_max);
+ }
+ }
+ else
+ {
+ /* Invalid DECC feature name. */
+ printf( " UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[ i].name);
+ }
+ }
+}
+
+/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
+
+#pragma nostandard
+
+/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
+ other attributes. Note that "nopic" is significant only on VAX.
+*/
+#pragma extern_model save
+
+#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
+const int spare[ 8] = { 0 };
+
+#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
+void (*const x_decc_init)() = decc_init;
+
+#pragma extern_model restore
+
+/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
+
+#pragma extern_model save
+
+int LIB$INITIALIZE( void);
+
+#pragma extern_model strict_refdef
+int dmy_lib$initialize = (int) LIB$INITIALIZE;
+
+#pragma extern_model restore
+
+#pragma standard
+
+#endif /* !defined( __VAX) && (__CRTL_VER >= 70301000) */
+
+#endif /* def __CRTL_VER */
+
+#endif /* def __DECC */
+
+#endif /* VMS */
diff --git a/vms/vms.h b/vms/vms.h
new file mode 100644
index 0000000..8685fdd
--- /dev/null
+++ b/vms/vms.h
@@ -0,0 +1,354 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ vms.h
+
+ Generic VMS header file for Info-ZIP's Zip and UnZip.
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef __vms_h
+#define __vms_h 1
+
+#ifndef __DESCRIP_LOADED
+#include <descrip.h>
+#endif
+#ifndef __STARLET_LOADED
+#include <starlet.h>
+#endif
+#ifndef __SYIDEF_LOADED
+#include <syidef.h>
+#endif
+#ifndef __ATRDEF_LOADED
+#include <atrdef.h>
+#endif
+#ifndef __FIBDEF_LOADED
+#include <fibdef.h>
+#endif
+#ifndef __IODEF_LOADED
+#include <iodef.h>
+#endif
+#if !defined(_RMS_H) && !defined(__RMS_LOADED)
+#include <rms.h>
+#endif
+
+#define ERR(s) !((s) & 1) /* VMS system error */
+
+#ifndef SYI$_VERSION
+#define SYI$_VERSION 4096 /* VMS 5.4 definition */
+#endif
+
+/*
+ * Under Alpha (DEC C in VAXC mode) and under `good old' VAXC, the FIB unions
+ * are declared as variant_unions. DEC C (Alpha) in ANSI modes and third
+ * party compilers which do not support `variant_union' define preprocessor
+ * symbols to `hide' the "intermediate union/struct" names from the
+ * programmer's API.
+ * We check the presence of these defines and for DEC's FIBDEF.H defining
+ * __union as variant_union to make sure we access the structure correctly.
+ */
+#define variant_union 1
+#if defined(fib$w_did) || (defined(__union) && (__union == variant_union))
+# define FIB$W_DID fib$w_did
+# define FIB$W_FID fib$w_fid
+# define FIB$L_ACCTL fib$l_acctl
+# define FIB$W_EXCTL fib$w_exctl
+#else
+# define FIB$W_DID fib$r_did_overlay.fib$w_did
+# define FIB$W_FID fib$r_fid_overlay.fib$w_fid
+# define FIB$L_ACCTL fib$r_acctl_overlay.fib$l_acctl
+# define FIB$W_EXCTL fib$r_exctl_overlay.fib$w_exctl
+#endif
+#undef variant_union
+
+
+/* 2005-02-08 SMS. Moved NAM[L] macros here from VMS.C. */
+
+/* Define macros for use with either NAM or NAML. */
+
+#ifdef NAML$C_MAXRSS /* NAML is available. Use it. */
+
+# define NAM_STRUCT NAML
+
+# define FAB_OR_NAML( fab, nam) nam
+# define FAB_OR_NAML_DNA naml$l_long_defname
+# define FAB_OR_NAML_DNS naml$l_long_defname_size
+# define FAB_OR_NAML_FNA naml$l_long_filename
+# define FAB_OR_NAML_FNS naml$l_long_filename_size
+
+# define CC_RMS_NAM cc$rms_naml
+# define FAB_NAM fab$l_naml
+# define NAM_DID naml$w_did
+# define NAM_DVI naml$t_dvi
+# define NAM_ESA naml$l_long_expand
+# define NAM_ESL naml$l_long_expand_size
+# define NAM_ESS naml$l_long_expand_alloc
+# define NAM_FID naml$w_fid
+# define NAM_FNB naml$l_fnb
+# define NAM_RSA naml$l_long_result
+# define NAM_RSL naml$l_long_result_size
+# define NAM_RSS naml$l_long_result_alloc
+# define NAM_MAXRSS NAML$C_MAXRSS
+# define NAM_NOP naml$b_nop
+# define NAM_M_EXP_DEV NAML$M_EXP_DEV
+# define NAM_M_SYNCHK NAML$M_SYNCHK
+# define NAM_B_DEV naml$l_long_dev_size
+# define NAM_L_DEV naml$l_long_dev
+# define NAM_B_DIR naml$l_long_dir_size
+# define NAM_L_DIR naml$l_long_dir
+# define NAM_B_NAME naml$l_long_name_size
+# define NAM_L_NAME naml$l_long_name
+# define NAM_B_TYPE naml$l_long_type_size
+# define NAM_L_TYPE naml$l_long_type
+# define NAM_B_VER naml$l_long_ver_size
+# define NAM_L_VER naml$l_long_ver
+
+#else /* def NAML$C_MAXRSS */ /* NAML is not available. Use NAM. */
+
+# define NAM_STRUCT NAM
+
+# define FAB_OR_NAML( fab, nam) fab
+# define FAB_OR_NAML_DNA fab$l_dna
+# define FAB_OR_NAML_DNS fab$b_dns
+# define FAB_OR_NAML_FNA fab$l_fna
+# define FAB_OR_NAML_FNS fab$b_fns
+
+# define CC_RMS_NAM cc$rms_nam
+# define FAB_NAM fab$l_nam
+# define NAM_DID nam$w_did
+# define NAM_DVI nam$t_dvi
+# define NAM_ESA nam$l_esa
+# define NAM_ESL nam$b_esl
+# define NAM_ESS nam$b_ess
+# define NAM_FID nam$w_fid
+# define NAM_FNB nam$l_fnb
+# define NAM_RSA nam$l_rsa
+# define NAM_RSL nam$b_rsl
+# define NAM_RSS nam$b_rss
+# define NAM_MAXRSS NAM$C_MAXRSS
+# define NAM_NOP nam$b_nop
+# define NAM_M_EXP_DEV NAM$M_EXP_DEV
+# define NAM_M_SYNCHK NAM$M_SYNCHK
+# define NAM_B_DEV nam$b_dev
+# define NAM_L_DEV nam$l_dev
+# define NAM_B_DIR nam$b_dir
+# define NAM_L_DIR nam$l_dir
+# define NAM_B_NAME nam$b_name
+# define NAM_L_NAME nam$l_name
+# define NAM_B_TYPE nam$b_type
+# define NAM_L_TYPE nam$l_type
+# define NAM_B_VER nam$b_ver
+# define NAM_L_VER nam$l_ver
+
+#endif /* def NAML$C_MAXRSS */
+
+
+struct EB_header /* Common header of extra block */
+{ ush tag;
+ ush size;
+ uch data[1];
+};
+
+#ifndef EB_HEADSIZE
+# define EB_HEADSIZE 4
+#endif
+
+/*------ Old style Info-ZIP extra field definitions -----*/
+
+#if (!defined(VAXC) && !defined(_RMS_H) && !defined(__RMS_LOADED))
+
+struct XAB { /* This definition may be skipped */
+ unsigned char xab$b_cod;
+ unsigned char xab$b_bln;
+ short int xabdef$$_fill_1;
+ char *xab$l_nxt;
+};
+
+#endif /* !VAXC && !_RMS_H && !__RMS_LOADED */
+
+#ifndef EB_IZVMS_BCMASK
+# define EB_IZVMS_BCMASK 07 /* 3 bits for compression type */
+#endif
+#ifndef EB_IZVMS_BCSTOR
+# define EB_IZVMS_BCSTOR 0 /* Stored */
+#endif
+#ifndef EB_IZVMS_BC00
+# define EB_IZVMS_BC00 1 /* 0byte -> 0bit compression */
+#endif
+#ifndef EB_IZVMS_BCDEFL
+# define EB_IZVMS_BCDEFL 2 /* Deflated */
+#endif
+
+/*
+ * Extra record format
+ * ===================
+ * signature (2 bytes) = 'I','M'
+ * size (2 bytes)
+ * block signature (4 bytes)
+ * flags (2 bytes)
+ * uncomprssed size(2 bytes)
+ * reserved (4 bytes)
+ * data ((size-12) bytes)
+ * ....
+ */
+
+struct IZ_block /* Extra field block header structure */
+{
+ ush sig;
+ ush size;
+ ulg bid;
+ ush flags;
+ ush length;
+ ulg reserved;
+ uch body[1]; /* The actual size is unknown */
+};
+
+/*
+ * Extra field signature and block signatures
+ */
+
+#define IZ_SIGNATURE "IM"
+#define FABSIG "VFAB"
+#define XALLSIG "VALL"
+#define XFHCSIG "VFHC"
+#define XDATSIG "VDAT"
+#define XRDTSIG "VRDT"
+#define XPROSIG "VPRO"
+#define XKEYSIG "VKEY"
+#define XNAMSIG "VNAM"
+#define VERSIG "VMSV"
+
+/*
+ * Block sizes
+ */
+
+#define FABL (cc$rms_fab.fab$b_bln)
+#define RABL (cc$rms_rab.rab$b_bln)
+#define XALLL (cc$rms_xaball.xab$b_bln)
+#define XDATL (cc$rms_xabdat.xab$b_bln)
+#define XFHCL (cc$rms_xabfhc.xab$b_bln)
+#define XKEYL (cc$rms_xabkey.xab$b_bln)
+#define XPROL (cc$rms_xabpro.xab$b_bln)
+#define XRDTL (cc$rms_xabrdt.xab$b_bln)
+#define XSUML (cc$rms_xabsum.xab$b_bln)
+#define EXTBSL 4 /* Block signature length */
+#define RESL 8 /* Reserved 8 bytes */
+#define EXTHL (EB_HEADSIZE+EXTBSL+RESL)
+
+typedef unsigned char byte;
+
+struct iosb
+{
+ ush status;
+ ush count;
+ ulg spec;
+};
+
+/*------------ PKWARE extra block definitions ----------*/
+
+/* Structure of PKWARE extra header */
+
+#ifdef VMS_ZIP
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __nostandard
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __save
+#pragma __nomember_alignment
+#endif /* __DECC || __DECCXX */
+
+#ifdef VMS_ORIGINAL_PK_LAYOUT
+/* The original order of ATR fields in the PKZIP VMS-extra field leads
+ * to unaligned fields in the PK_info structure representing the
+ * extra field layout. When compiled for Alpha AXP, this results in
+ * some performance (and code size) penalty. It is not allowed to
+ * apply structure padding, since this is explicitely forbidden in
+ * the specification (APPNOTE.TXT) for the PK VMS extra field.
+ */
+typedef struct
+{
+ ush tag_ra; ush len_ra; byte ra[ATR$S_RECATTR];
+ ush tag_uc; ush len_uc; byte uc[ATR$S_UCHAR];
+ ush tag_jr; ush len_jr; byte jr[ATR$S_JOURNAL];
+ ush tag_cd; ush len_cd; byte cd[ATR$S_CREDATE];
+ ush tag_rd; ush len_rd; byte rd[ATR$S_REVDATE];
+ ush tag_ed; ush len_ed; byte ed[ATR$S_EXPDATE];
+ ush tag_bd; ush len_bd; byte bd[ATR$S_BAKDATE];
+ ush tag_rn; ush len_rn; ush rn;
+ ush tag_ui; ush len_ui; byte ui[ATR$S_UIC];
+ ush tag_fp; ush len_fp; byte fp[ATR$S_FPRO];
+ ush tag_rp; ush len_rp; byte rp[ATR$S_RPRO];
+} PK_info_t;
+#else /* !VMS_ORIGINAL_PK_LAYOUT */
+/* The Info-ZIP support for the PK VMS extra field uses a reordered
+ * field layout to achieve ``natural alignment'' of the PK_info structure
+ * members whenever possible. This rearrangement does not violate the
+ * PK's VMS extra field specification and should not break any ``well
+ * behaving'' (PK)Unzip utility. (`Well behaving' means that (PK)Unzip
+ * should use the field tag to identify the ATR$ field rather than
+ * assuming a fixed order of ATR$ fields in the PK VMS extra field.)
+ */
+typedef struct
+{
+ ush tag_ra; ush len_ra; byte ra[ATR$S_RECATTR];
+ ush tag_uc; ush len_uc; byte uc[ATR$S_UCHAR];
+ ush tag_cd; ush len_cd; byte cd[ATR$S_CREDATE];
+ ush tag_rd; ush len_rd; byte rd[ATR$S_REVDATE];
+ ush tag_ed; ush len_ed; byte ed[ATR$S_EXPDATE];
+ ush tag_bd; ush len_bd; byte bd[ATR$S_BAKDATE];
+ ush tag_rn; ush len_rn; ush rn;
+ ush tag_ui; ush len_ui; byte ui[ATR$S_UIC];
+ ush tag_fp; ush len_fp; byte fp[ATR$S_FPRO];
+ ush tag_rp; ush len_rp; byte rp[ATR$S_RPRO];
+ ush tag_jr; ush len_jr; byte jr[ATR$S_JOURNAL];
+} PK_info_t;
+#endif /* ?VMS_ORIGINAL_PK_LAYOUT */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __restore
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __standard
+#endif /* __DECC || __DECCXX */
+
+#endif /* VMS_ZIP */
+
+/* PKWARE "VMS" tag */
+#define PK_SIGNATURE 0x000C
+
+/* Total number of attributes to be saved */
+#define VMS_ATTR_COUNT 11
+#define VMS_MAX_ATRCNT 20
+
+struct PK_field
+{
+ ush tag;
+ ush size;
+ byte value[1];
+};
+
+#define PK_FLDHDR_SIZE 4
+
+struct PK_header
+{
+ ush tag;
+ ush size;
+ ulg crc32;
+ byte data[1];
+};
+
+#define PK_HEADER_SIZE 8
+
+char *vms_file_version( char *s);
+
+#endif /* !__vms_h */
diff --git a/vms/vms_im.c b/vms/vms_im.c
new file mode 100644
index 0000000..001088b
--- /dev/null
+++ b/vms/vms_im.c
@@ -0,0 +1,926 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * vms_im.c (zip) by Igor Mandrichenko Version 2.2-2
+ *
+ * Revision history:
+ * ...
+ * 2.1-1 16-feb-1993 I.Mandrichenko
+ * Get file size from XABFHC and check bytes rest in file before
+ * reading.
+ * 2.1-2 2-mar-1993 I.Mandrichenko
+ * Make code more standard
+ * 2.2 21-jun-1993 I.Mandrichenko
+ * Free all allocated space, use more static storage.
+ * Use memcompress() from bits.c (deflation) for block compression.
+ * To revert to old compression method #define OLD_COMPRESS
+ * 2.2-2 28-sep-1995 C.Spieler
+ * Reorganized code for easier maintance of the two incompatible
+ * flavours (IM style and PK style) VMS attribute support.
+ * Generic functions (common to both flavours) are now collected
+ * in a `wrapper' source file that includes one of the VMS attribute
+ * handlers.
+ * 3.0 23-Oct-2004 Steven Schweda
+ * Changed to maintain compatibility with VMS_PK.C. Note that
+ * reading with sys$read() prevents getting any data past EOF,
+ * regardless of appearances. Moved the VMS_PK_EXTRA test into
+ * here from VMS.C to allow more general automatic dependency
+ * generation.
+ * 17-Feb-2005 Steven Schweda
+ * Added support for ODS5 extended names.
+ */
+
+#ifdef VMS /* For VMS only ! */
+
+#ifndef VMS_PK_EXTRA
+
+#define OLD_COMPRESS /*To use old compression method define it.*/
+
+#ifdef VMS_ZIP
+#undef VMS_ZIP /* do NOT include PK style Zip definitions */
+#endif
+
+#include "vms.h"
+
+#ifndef __LIB$ROUTINES_LOADED
+#include <lib$routines.h>
+#endif
+
+#ifndef UTIL
+
+#define RET_ERROR 1
+#define RET_SUCCESS 0
+#define RET_EOF 0
+
+#define Kbyte 1024
+
+typedef struct XAB *xabptr;
+
+/*
+ * Block sizes
+ */
+
+#define EXTL0 ((FABL + EXTHL)+ \
+ (XFHCL + EXTHL)+ \
+ (XPROL + EXTHL)+ \
+ (XDATL + EXTHL)+ \
+ (XRDTL + EXTHL))
+
+#ifdef OLD_COMPRESS
+#define PAD sizeof(uch)
+#else
+#define PAD 10*sizeof(ush) /* Two extra bytes for compr. header */
+#endif
+
+#define PAD0 (5*PAD) /* Reserve space for the case when
+ * compression fails */
+static int _compress(uch *from, uch *to, int size);
+#ifdef DEBUG
+static void dump_rms_block(uch *p);
+#endif /* DEBUG */
+
+/********************************
+ * Function set_extra_field *
+ ********************************/
+/*
+ | 2004-11-11 SMS.
+ | Changed to use separate storage for ->extra and ->cextra. Zip64
+ | processing may move (reallocate) one and not the other.
+ */
+
+static uch *_compress_block(register struct IZ_block *to,
+ uch *from, int size, char *sig);
+static int get_vms_version(char *verbuf, int len);
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+/*
+ * Get file VMS file attributes and store them into extent fields.
+ * Store VMS version also.
+ * On error leave z intact.
+ */
+{
+ int status;
+ uch *xtra;
+ uch *cxtra;
+ uch *scan;
+ extent extra_l;
+ static struct FAB fab;
+ static struct NAM_STRUCT nam;
+ static struct XABSUM xabsum;
+ static struct XABFHC xabfhc;
+ static struct XABDAT xabdat;
+ static struct XABPRO xabpro;
+ static struct XABRDT xabrdt;
+ xabptr x = (xabptr)NULL, xab_chain = (xabptr)NULL, last_xab = (xabptr)NULL;
+ int nk, na;
+ int i;
+ int rc=RET_ERROR;
+ char verbuf[80];
+ int verlen = 0;
+
+ if (!vms_native)
+ {
+#ifdef USE_EF_UT_TIME
+ /*
+ * A `portable' zipfile entry is created. Create an "UT" extra block
+ * containing UNIX style modification time stamp in UTC, which helps
+ * maintaining the `real' "last modified" time when the archive is
+ * transfered across time zone boundaries.
+ */
+# ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ return ZE_OK; /* skip silently if no valid TZ info */
+# endif
+ if ((xtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+ return ZE_MEM;
+
+ if ((cxtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+ return ZE_MEM;
+
+ /* Fill xtra[] with data. */
+ xtra[ 0] = 'U';
+ xtra[ 1] = 'T';
+ xtra[ 2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ xtra[ 3] = 0;
+ xtra[ 4] = EB_UT_FL_MTIME;
+ xtra[ 5] = (uch) (z_utim->mtime);
+ xtra[ 6] = (uch) (z_utim->mtime >> 8);
+ xtra[ 7] = (uch) (z_utim->mtime >> 16);
+ xtra[ 8] = (uch) (z_utim->mtime >> 24);
+
+ /* Copy xtra[] data into cxtra[]. */
+ memcpy( cxtra, xtra, (EB_HEADSIZE+ EB_UT_LEN( 1)));
+
+ /* Set sizes and pointers. */
+ z->cext = z->ext = (EB_HEADSIZE+ EB_UT_LEN( 1));
+ z->extra = (char *) xtra;
+ z->cextra = (char *) cxtra;
+
+#endif /* USE_EF_UT_TIME */
+
+ return RET_SUCCESS;
+ }
+
+ /*
+ * Initialize RMS control blocks and link them
+ */
+
+ fab = cc$rms_fab;
+ nam = CC_RMS_NAM;
+ xabsum = cc$rms_xabsum;
+ xabdat = cc$rms_xabdat;
+ xabfhc = cc$rms_xabfhc;
+ xabpro = cc$rms_xabpro;
+ xabrdt = cc$rms_xabrdt;
+
+ fab.FAB_NAM = &nam;
+ fab.fab$l_xab = (char*)&xabsum;
+ /*
+ * Open the file and read summary information.
+ */
+
+#ifdef NAML$C_MAXRSS
+
+ fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
+ fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = z->name;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( z->name);
+
+#ifdef NAML$M_OPEN_SPECIAL
+ /* 2007-02-28 SMS.
+ * If processing symlinks as symlinks ("-y"), then $OPEN the
+ * link, not the target file.
+ *
+ * (nam.naml$v_open_special gets us the symlink itself instead of
+ * its target. fab.fab$v_bio is necessary to allow sys$open() to
+ * work. Without it, you get status %x0001860c, "%RMS-F-ORG,
+ * invalid file organization value".)
+ */
+ if (linkput)
+ {
+ nam.naml$v_open_special = 1;
+ fab.fab$v_bio = 1;
+ }
+#endif /* def NAML$M_OPEN_SPECIAL */
+
+ status = sys$open(&fab);
+ if (ERR(status))
+ {
+#ifdef DEBUG
+ printf("set_extra_field: sys$open for file %s:\n error status = %d\n",
+ z->name, status);
+#endif
+ goto err_exit;
+ }
+
+ nk = xabsum.xab$b_nok;
+ na = xabsum.xab$b_noa;
+#ifdef DEBUG
+ printf("%d keys, %d alls\n", nk, na);
+#endif
+
+ /*
+ * Allocate XABKEY and XABALL blocks and link them
+ */
+
+ xabfhc.xab$l_nxt = (char*)&xabdat;
+ xabdat.xab$l_nxt = (char*)&xabpro;
+ xabpro.xab$l_nxt = (char*)&xabrdt;
+ xabrdt.xab$l_nxt = NULL;
+
+ xab_chain = (xabptr)(&xabfhc);
+ last_xab = (xabptr)(&xabrdt);
+
+#define INIT(ptr,size,type,init) \
+ if ( (ptr = (type *)malloc(size)) == NULL ) \
+ { \
+ printf( "set_extra_field: Insufficient memory.\n" ); \
+ goto err_exit; \
+ } \
+ *(ptr) = (init);
+ /*
+ * Allocate and initialize all needed XABKEYs and XABALLs
+ */
+ for (i = 0; i < nk; i++)
+ {
+ struct XABKEY *k;
+ INIT(k, XKEYL, struct XABKEY, cc$rms_xabkey);
+ k->xab$b_ref = i;
+ if (last_xab != NULL)
+ last_xab->xab$l_nxt = (char*)k;
+ last_xab = (xabptr)k;
+ }
+ for (i = 0; i < na; i++)
+ {
+ struct XABALL *a;
+ INIT(a, XALLL, struct XABALL, cc$rms_xaball);
+ a->xab$b_aid = i;
+ if (last_xab != NULL)
+ last_xab->xab$l_nxt = (char*)a;
+ last_xab = (xabptr)a;
+ }
+
+ fab.fab$l_xab = (char*)xab_chain;
+#ifdef DEBUG
+ printf("Dump of XAB chain before $DISPLAY:\n");
+ for (x = xab_chain; x != NULL; x = x->xab$l_nxt)
+ dump_rms_block((uch *)x);
+#endif
+ /*
+ * Get information on the file structure etc.
+ */
+ status = sys$display(&fab, 0, 0);
+ if (ERR(status))
+ {
+#ifdef DEBUG
+ printf("set_extra_field: sys$display for file %s:\n error status = %d\n",
+ z->name, status);
+#endif
+ goto err_exit;
+ }
+
+#ifdef DEBUG
+ printf("\nDump of XAB chain after $DISPLAY:\n");
+ for (x = xab_chain; x != NULL; x = x->xab$l_nxt)
+ dump_rms_block((uch *)x);
+#endif
+
+ fab.fab$l_xab = NULL; /* Keep XABs */
+ status = sys$close(&fab);
+ if (ERR(status))
+ {
+#ifdef DEBUG
+ printf("set_extra_field: sys$close for file %s:\n error status = %d\n",
+ z->name, status);
+#endif
+ goto err_exit;
+ }
+
+ extra_l = EXTL0 + nk * (XKEYL + EXTHL) + na * (XALLL + EXTHL);
+#ifndef OLD_COMPRESS
+ extra_l += PAD0 + (nk+na) * PAD;
+#endif
+
+ if ( (verlen = get_vms_version(verbuf, sizeof(verbuf))) > 0 )
+ {
+ extra_l += verlen + EXTHL;
+#ifndef OLD_COMPRESS
+ extra_l += PAD;
+#endif
+ }
+
+ if ((scan = xtra = (uch *) malloc( extra_l)) == (uch*)NULL)
+ {
+#ifdef DEBUG
+ printf(
+ "set_extra_field: Insufficient memory to allocate extra L buffer\n");
+#endif
+ goto err_exit;
+ }
+
+ if ((cxtra = (uch *) malloc( extra_l)) == (uch*)NULL)
+ {
+#ifdef DEBUG
+ printf(
+ "set_extra_field: Insufficient memory to allocate extra C buffer\n");
+#endif
+ goto err_exit;
+ }
+
+ if (verlen > 0)
+ scan = _compress_block((struct IZ_block *)scan, (uch *)verbuf,
+ verlen, VERSIG);
+
+ /*
+ * Zero all unusable fields to improve compression
+ */
+ fab.fab$b_fns = fab.fab$b_shr = fab.fab$b_dns = fab.fab$b_fac = 0;
+ fab.fab$w_ifi = 0;
+ fab.fab$l_stv = fab.fab$l_sts = fab.fab$l_ctx = 0;
+ fab.fab$l_dna = NULL;
+ fab.fab$l_fna = NULL;
+ fab.fab$l_nam = NULL;
+#ifdef NAML$C_MAXRSS
+ fab.fab$l_naml = NULL;
+#endif /* def NAML$C_MAXRSS */
+ fab.fab$l_xab = NULL;
+
+#ifdef DEBUG
+ dump_rms_block( (uch *)&fab );
+#endif
+ scan = _compress_block((struct IZ_block *)scan, (uch *)&fab, FABL, FABSIG);
+ for (x = xab_chain; x != NULL;)
+ {
+ int bln;
+ char *sig;
+ xabptr next;
+
+ next = (xabptr)(x->xab$l_nxt);
+ x->xab$l_nxt = 0;
+
+ switch (x->xab$b_cod)
+ {
+ case XAB$C_ALL:
+ bln = XALLL;
+ sig = XALLSIG;
+ break;
+ case XAB$C_KEY:
+ bln = XKEYL;
+ sig = XKEYSIG;
+ break;
+ case XAB$C_PRO:
+ bln = XPROL;
+ sig = XPROSIG;
+ break;
+ case XAB$C_FHC:
+ bln = XFHCL;
+ sig = XFHCSIG;
+ break;
+ case XAB$C_DAT:
+ bln = XDATL;
+ sig = XDATSIG;
+ break;
+ case XAB$C_RDT:
+ bln = XRDTL;
+ sig = XRDTSIG;
+ break;
+ default:
+ bln = 0;
+ sig = 0L;
+ break;
+ }
+ if (bln > 0)
+ scan = _compress_block((struct IZ_block *)scan, (uch *)x,
+ bln, sig);
+ x = next;
+ }
+
+ /* Copy xtra[] data into cxtra[]. */
+ memcpy( cxtra, xtra, (scan- xtra));
+
+ /* Set sizes and pointers. */
+ z->cext = z->ext = scan- xtra;
+ z->extra = (char*) xtra;
+ z->cextra = (char*) cxtra;
+
+ rc = RET_SUCCESS;
+
+err_exit:
+ /*
+ * Give up all allocated blocks
+ */
+ for (x = (struct XAB *)xab_chain; x != NULL; )
+ {
+ struct XAB *next;
+ next = (xabptr)(x->xab$l_nxt);
+ if (x->xab$b_cod == XAB$C_ALL || x->xab$b_cod == XAB$C_KEY)
+ free(x);
+ x = next;
+ }
+ return rc;
+}
+
+static int get_vms_version(verbuf, len)
+char *verbuf;
+int len;
+{
+ int i = SYI$_VERSION;
+ int verlen = 0;
+ struct dsc$descriptor version;
+ char *m;
+
+ version.dsc$a_pointer = verbuf;
+ version.dsc$w_length = len - 1;
+ version.dsc$b_dtype = DSC$K_DTYPE_B;
+ version.dsc$b_class = DSC$K_CLASS_S;
+
+ if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
+ return 0;
+
+ /* Cut out trailing spaces "V5.4-3 " -> "V5.4-3" */
+ for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
+ --m;
+ *m = 0;
+
+ /* Cut out release number "V5.4-3" -> "V5.4" */
+ if ((m = strrchr(verbuf, '-')) != NULL)
+ *m = 0;
+ return strlen(verbuf) + 1; /* Transmit ending 0 too */
+}
+
+#define CTXSIG ((ulg)('CtXx'))
+
+typedef struct user_context
+{
+ ulg sig;
+ struct FAB *fab;
+ struct NAM_STRUCT *nam;
+ struct RAB *rab;
+ uzoff_t size;
+ uzoff_t rest;
+ int status;
+} Ctx, *Ctxptr;
+
+Ctx init_ctx =
+{
+ CTXSIG,
+ NULL,
+ NULL,
+ NULL,
+ 0L,
+ 0L,
+ 0
+};
+
+#define CTXL sizeof(Ctx)
+#define CHECK_RAB(_r) ( (_r) != NULL && \
+ (_r) -> rab$b_bid == RAB$C_BID && \
+ (_r) -> rab$b_bln == RAB$C_BLN && \
+ (_r) -> rab$l_ctx != 0 && \
+ (_r) -> rab$l_fab != NULL )
+
+
+#define BLOCK_BYTES 512
+
+/**************************
+ * Function vms_open *
+ **************************/
+struct RAB *vms_open(name)
+ char *name;
+{
+ struct FAB *fab;
+ struct NAM_STRUCT *nam;
+ struct RAB *rab;
+ struct XABFHC *fhc;
+ Ctxptr ctx;
+
+ if ((fab = (struct FAB *) malloc(FABL)) == NULL)
+ return NULL;
+
+ if ((nam =
+ (struct NAM_STRUCT *) malloc( sizeof( struct NAM_STRUCT))) == NULL)
+ {
+ free(fab);
+ return NULL;
+ }
+
+ if ((rab = (struct RAB *) malloc(RABL)) == NULL)
+ {
+ free(fab);
+ free(nam);
+ return NULL;
+ }
+
+ if ((fhc = (struct XABFHC *) malloc(XFHCL)) == (struct XABFHC *)NULL)
+ {
+ free(fab);
+ free(nam);
+ free(rab);
+ return (struct RAB *)NULL;
+ }
+ if ((ctx = (Ctxptr) malloc(CTXL)) == (Ctxptr)NULL)
+ {
+ free(fab);
+ free(nam);
+ free(rab);
+ free(fhc);
+ return (struct RAB *)NULL;
+ }
+ *fab = cc$rms_fab;
+ *nam = CC_RMS_NAM;
+ *rab = cc$rms_rab;
+ *fhc = cc$rms_xabfhc;
+
+ fab->FAB_NAM = nam;
+
+#ifdef NAML$C_MAXRSS
+
+ fab->fab$l_dna = (char *) -1; /* Using NAML for default name. */
+ fab->fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ FAB_OR_NAML( fab, nam)->FAB_OR_NAML_FNA = name;
+ FAB_OR_NAML( fab, nam)->FAB_OR_NAML_FNS = strlen( name);
+
+ fab->fab$b_fac = FAB$M_GET | FAB$M_BIO;
+ fab->fab$l_xab = (char*)fhc;
+
+#ifdef NAML$M_OPEN_SPECIAL
+ /* 2007-02-28 SMS.
+ * If processing symlinks as symlinks ("-y"), then $OPEN the
+ * link, not the target file. (Note that here the required
+ * fab->fab$v_bio flag was set above.)
+ */
+ if (linkput)
+ {
+ nam->naml$v_open_special = 1;
+ }
+#endif /* def NAML$M_OPEN_SPECIAL */
+
+ if (ERR(sys$open(fab)))
+ {
+ sys$close(fab);
+ free(fab);
+ free(nam);
+ free(rab);
+ free(fhc);
+ free(ctx);
+ return (struct RAB *)NULL;
+ }
+
+ rab->rab$l_fab = fab;
+ rab->rab$l_rop = RAB$M_BIO;
+
+ if (ERR(sys$connect(rab)))
+ {
+ sys$close(fab);
+ free(fab);
+ free(nam);
+ free(rab);
+ free(ctx);
+ return (struct RAB *)NULL;
+ }
+
+ *ctx = init_ctx;
+ ctx->fab = fab;
+ ctx->nam = nam;
+ ctx->rab = rab;
+
+ if (fhc->xab$l_ebk == 0)
+ {
+ /* Only known size is all allocated blocks.
+ (This occurs with a zero-length file, for example.)
+ */
+ ctx->size =
+ ctx->rest = ((uzoff_t) fhc->xab$l_hbk)* BLOCK_BYTES;
+ }
+ else
+ {
+ /* Store normal (used) size in ->size.
+ If only one -V, store normal (used) size in ->rest.
+ If -VV, store allocated-blocks size in ->rest.
+ */
+ ctx->size =
+ (((uzoff_t) fhc->xab$l_ebk)- 1)* BLOCK_BYTES+ fhc->xab$w_ffb;
+ if (vms_native < 2)
+ ctx->rest = ctx->size;
+ else
+ ctx->rest = ((uzoff_t) fhc->xab$l_hbk)* BLOCK_BYTES;
+ }
+
+ free(fhc);
+ fab->fab$l_xab = NULL;
+ rab->rab$l_ctx = (unsigned) ctx;
+ return rab;
+}
+
+/**************************
+ * Function vms_close *
+ **************************/
+int vms_close(rab)
+ struct RAB *rab;
+{
+ struct FAB *fab;
+ struct NAM_STRUCT *nam;
+ Ctxptr ctx;
+
+ if (!CHECK_RAB(rab))
+ return RET_ERROR;
+ fab = (ctx = (Ctxptr)(rab->rab$l_ctx))->fab;
+ nam = (ctx = (Ctxptr)(rab->rab$l_ctx))->nam;
+ sys$close(fab);
+
+ free(fab);
+ free(nam);
+ free(rab);
+ free(ctx);
+
+ return RET_SUCCESS;
+}
+
+/**************************
+ * Function vms_rewind *
+ **************************/
+int vms_rewind(rab)
+ struct RAB *rab;
+{
+ Ctxptr ctx;
+
+ int status;
+ if (!CHECK_RAB(rab))
+ return RET_ERROR;
+
+ ctx = (Ctxptr) (rab->rab$l_ctx);
+ if (ERR(status = sys$rewind(rab)))
+ {
+ ctx->status = status;
+ return RET_ERROR;
+ }
+
+ ctx->status = 0;
+ ctx->rest = ctx->size;
+
+ return RET_SUCCESS;
+}
+
+
+#define KByte (2* BLOCK_BYTES)
+#define MAX_READ_BYTES (32* KByte)
+
+/**************************
+ * Function vms_read *
+ **************************/
+size_t vms_read(rab, buf, size)
+struct RAB *rab;
+char *buf;
+size_t size;
+/*
+ * size must be greater or equal to 512 !
+ */
+{
+ int status;
+ Ctxptr ctx;
+
+ ctx = (Ctxptr)rab->rab$l_ctx;
+
+ if (!CHECK_RAB(rab))
+ return 0;
+
+ if (ctx -> rest == 0)
+ return 0; /* Eof */
+
+ /* If request is smaller than a whole block, fail.
+ This really should never happen. (assert()?)
+ */
+ if (size < BLOCK_BYTES)
+ return 0;
+
+ /* 2004-09-27 SMS.
+ Code here now resembles low-level QIO code in VMS_PK.C, but I
+ doubt that sys$read() will actually get past the official EOF.
+ */
+
+ /* Adjust request size as appropriate. */
+ if (size > MAX_READ_BYTES)
+ {
+ /* Restrict request to MAX_READ_BYTES. */
+ size = MAX_READ_BYTES;
+ }
+ else
+ {
+ /* Round odd-ball request up to the next whole block.
+ This really should never happen. (assert()?)
+ */
+ size = (size+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
+ }
+
+ /* Reduce "size" when next (last) read would overrun the EOF,
+ but never below one byte (so we'll always get a nice EOF).
+ */
+ if (size > ctx->rest)
+ size = ctx->rest;
+ if (size == 0)
+ size = 1;
+
+ rab->rab$l_ubf = buf;
+ rab->rab$w_usz = size;
+ status = sys$read(rab);
+
+ if (!ERR(status) && rab->rab$w_rsz > 0)
+ {
+ ctx -> status = 0;
+ ctx -> rest -= rab->rab$w_rsz;
+ return rab->rab$w_rsz;
+ }
+ else
+ {
+ ctx->status = (status==RMS$_EOF ? 0:status);
+ if (status == RMS$_EOF)
+ ctx -> rest = 0;
+ return 0;
+ }
+}
+
+/**************************
+ * Function vms_error *
+ **************************/
+int vms_error(rab)
+ struct RAB *rab;
+{
+ if (!CHECK_RAB(rab))
+ return RET_ERROR;
+ return ((Ctxptr) (rab->rab$l_ctx))->status;
+}
+
+
+#ifdef DEBUG
+static void dump_rms_block(p)
+ uch *p;
+{
+ uch bid, len;
+ int err;
+ char *type;
+ char buf[132];
+ int i;
+
+ err = 0;
+ bid = p[0];
+ len = p[1];
+ switch (bid)
+ {
+ case FAB$C_BID:
+ type = "FAB";
+ break;
+ case XAB$C_ALL:
+ type = "xabALL";
+ break;
+ case XAB$C_KEY:
+ type = "xabKEY";
+ break;
+ case XAB$C_DAT:
+ type = "xabDAT";
+ break;
+ case XAB$C_RDT:
+ type = "xabRDT";
+ break;
+ case XAB$C_FHC:
+ type = "xabFHC";
+ break;
+ case XAB$C_PRO:
+ type = "xabPRO";
+ break;
+ default:
+ type = "Unknown";
+ err = 1;
+ break;
+ }
+ printf("Block @%08X of type %s (%d).", p, type, bid);
+ if (err)
+ {
+ printf("\n");
+ return;
+ }
+ printf(" Size = %d\n", len);
+ printf(" Offset - Hex - Dec\n");
+ for (i = 0; i < len; i += 8)
+ {
+ int j;
+
+ printf("%3d - ", i);
+ for (j = 0; j < 8; j++)
+ if (i + j < len)
+ printf("%02X ", p[i + j]);
+ else
+ printf(" ");
+ printf(" - ");
+ for (j = 0; j < 8; j++)
+ if (i + j < len)
+ printf("%03d ", p[i + j]);
+ else
+ printf(" ");
+ printf("\n");
+ }
+}
+#endif /* DEBUG */
+
+#ifdef OLD_COMPRESS
+# define BC_METHOD EB_IZVMS_BC00
+# define COMP_BLK(to,tos,from,froms) _compress( from,to,froms )
+#else
+# define BC_METHOD EB_IZVMS_BCDEFL
+# define COMP_BLK(to,tos,from,froms) memcompress(to,tos,from,froms)
+#endif
+
+static uch *_compress_block(to,from,size,sig)
+register struct IZ_block *to;
+uch *from;
+int size;
+char *sig;
+{
+ ulg cl;
+ to -> sig = *(ush*)IZ_SIGNATURE;
+ to -> bid = *(ulg*)(sig);
+ to -> flags = BC_METHOD;
+ to -> length = size;
+#ifdef DEBUG
+ printf("\nmemcompr(%d,%d,%d,%d)\n",&(to->body[0]),size+PAD,from,size);
+#endif
+ cl = COMP_BLK( &(to->body[0]), size+PAD, from, size );
+#ifdef DEBUG
+ printf("Compressed to %d\n",cl);
+#endif
+ if (cl >= size)
+ {
+ memcpy(&(to->body[0]), from, size);
+ to->flags = EB_IZVMS_BCSTOR;
+ cl = size;
+#ifdef DEBUG
+ printf("Storing block...\n");
+#endif
+ }
+ return (uch*)(to) + (to->size = cl + EXTBSL + RESL) + EB_HEADSIZE;
+}
+
+#define NBITS 32
+
+static int _compress(from,to,size)
+uch *from,*to;
+int size;
+{
+ int off=0;
+ ulg bitbuf=0;
+ int bitcnt=0;
+ int i;
+
+#define _BIT(val,len) { \
+ if (bitcnt + (len) > NBITS) \
+ while(bitcnt >= 8) \
+ { \
+ to[off++] = (uch)bitbuf; \
+ bitbuf >>= 8; \
+ bitcnt -= 8; \
+ } \
+ bitbuf |= ((ulg)(val))<<bitcnt; \
+ bitcnt += len; \
+ }
+
+#define _FLUSH { \
+ while(bitcnt>0) \
+ { \
+ to[off++] = (uch)bitbuf; \
+ bitbuf >>= 8; \
+ bitcnt -= 8; \
+ } \
+ }
+
+ for (i=0; i<size; i++)
+ {
+ if (from[i])
+ {
+ _BIT(1,1);
+ _BIT(from[i],8);
+ }
+ else
+ _BIT(0,1);
+ }
+ _FLUSH;
+ return off;
+}
+
+#endif /* !UTIL */
+
+#endif /* ndef VMS_PK_EXTRA */
+
+#endif /* VMS */
diff --git a/vms/vms_msg_gen.c b/vms/vms_msg_gen.c
new file mode 100644
index 0000000..4599cb0
--- /dev/null
+++ b/vms/vms_msg_gen.c
@@ -0,0 +1,91 @@
+/*
+ * VMS Message Source File Generator.
+ *
+ * 2007-01-29 SMS.
+ *
+ * Generates a VMS error message source file from data in "ziperr.h".
+ *
+ * On a VMS system, the standard builders should do the work. On a
+ * non-VMS system:
+ *
+ * cc -I. vms/vms_msg_gen.c -o vms_msg_gen
+ * ./vms_msg_gen > vms/zip_msg.msg
+ * rm ./vms_msg_gen
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define GLOBALS /* Include data for ziperrors[] in ziperr.h. */
+#include "ziperr.h"
+
+main()
+{
+ int base_prev;
+ int code_vms;
+ int code_zip;
+ int i;
+
+ char *sev_str[ 8] = {
+ "/WARNING",
+ "/SUCCESS",
+ "/ERROR",
+ "/INFORMATIONAL",
+ "/FATAL",
+ "/??????",
+ "/???????",
+ "/????????"
+ };
+
+ char *text1[] = {
+"! VMS Error Message Source File for Zip",
+"!",
+"! Because the facility code was formally assigned by HP, the .FACILITY",
+"! directive below specifies /SYSTEM. Because the messages are, in",
+"! general, specific to Zip, this file is not compiled with /SHARED.",
+"! For example:",
+"!",
+"! MESSAGE /OBJECT = [.dest]ZIP_MSG.OBJ /NOSYMBOLS [.VMS]ZIP_MSG.MSG",
+"!",
+"! LINK /SHAREABLE = [.dest]ZIP_MSG.EXE [.dest]ZIP_MSG.OBJ",
+"!",
+"!-----------------------------------------------------------------------",
+"",
+".TITLE Info-ZIP Zip Error Messages",
+".FACILITY IZ_ZIP, 1955 /SYSTEM",
+NULL /* End-of-text marker. */
+};
+
+ /* Initialize the .BASE counter. */
+ base_prev = -2;
+
+ /* Put out the header text. */
+ for (i = 0; text1[ i] != NULL; i++)
+ {
+ printf( "%s\n", text1[ i]);
+ }
+ printf( ".IDENT '%s'\n", VMS_MSG_IDENT);
+ printf( "\n");
+
+ /* Put out the error messages. */
+ for (code_zip = 0; code_zip <= ZE_MAXERR; code_zip++)
+ {
+ if ((ziperrors[ code_zip].string != NULL) &&
+ (strlen(ziperrors[ code_zip].string) != 0))
+ {
+ code_vms = 2* code_zip; /* 4-bit left-shift, not 3. */
+ if (code_vms != base_prev+ 1)
+ {
+ printf( ".BASE %d\n", code_vms);
+ }
+ printf( "%-7s %-13s <%s>\n",
+ ziperrors[ code_zip].name,
+ sev_str[ ziperrors[ code_zip].severity & 0x07],
+ ziperrors[ code_zip].string);
+ base_prev = code_vms;
+ }
+ }
+ /* Put out the .END directive. */
+ printf( "\n");
+ printf( ".END\n");
+}
diff --git a/vms/vms_pk.c b/vms/vms_pk.c
new file mode 100644
index 0000000..9aa203d
--- /dev/null
+++ b/vms/vms_pk.c
@@ -0,0 +1,600 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * vms_pk.c by Igor Mandrichenko
+ *
+ * version 2.0 20-Mar-1993
+ * Generates PKWARE version of VMS attributes
+ * extra field according to appnote 2.0.
+ * Uses low level QIO-ACP interface.
+ * version 2.0-1 10-Apr-1993
+ * Save ACLs
+ * version 2.1 24-Aug-1993
+ * By default produce 0x010C extra record ID instead of
+ * PKWARE's 0x000C. The format is mostly compatible with
+ * PKWARE.
+ * Incompatibility (?): zip produces multiple ACE
+ * fields.
+ * version 2.1-1 Clean extra fields in vms_get_attributes().
+ * Fixed bug with EOF.
+ * version 2.1-2 15-Sep-1995, Chr. Spieler
+ * Removed extra fields cleanup from vms_get_attributes().
+ * This is now done in zipup.c
+ * Modified (according to UnZip's vms.[ch]) the fib stuff
+ * for DEC C (AXP,VAX) support.
+ * version 2.2 28-Sep-1995, Chr. Spieler
+ * Reorganized code for easier maintance of the two
+ * incompatible flavours (IM style and PK style) VMS
+ * attribute support. Generic functions (common to
+ * both flavours) are now collected in a `wrapper'
+ * source file that includes one of the VMS attribute
+ * handlers.
+ * Made extra block header conforming to PKware's
+ * specification (extra block header has a length
+ * of four bytes, two bytes for a signature, and two
+ * bytes for the length of the block excluding this
+ * header.
+ * version 2.2-1 19-Oct-1995, Chr. Spieler
+ * Fixed bug in CRC calculation.
+ * Use official PK VMS extra field id.
+ * version 2.2-2 21-Nov-1997, Chr. Spieler
+ * Fixed bug in vms_get_attributes() for directory
+ * entries (access to uninitialized ioctx record).
+ * Removed unused second arg for vms_open().
+ * version 2.2-3 04-Apr-1999, Chr. Spieler
+ * Changed calling interface of vms_get_attributes()
+ * to accept a void pointer as first argument.
+ * version 2.2-4 26-Jan-2002, Chr. Spieler
+ * Modified vms_read() to handle files larger than 2GByte
+ * (up to size limit of "unsigned long", resp. 4GByte).
+ * version 3.0 20-Oct-2004, Steven Schweda.
+ * Changed vms_read() to read all the allocated
+ * blocks in a file, for sure. Changed the default
+ * chunk size from 16K to 32K. Changed to use the
+ * new typedef for the ioctx structure. Moved the
+ * VMS_PK_EXTRA test into here from VMS.C to allow
+ * more general automatic dependency generation.
+ * 08-Feb-2005, SMS.
+ * Changed to accomodate ODS5 extended file names:
+ * NAM structure -> NAM[L], and so on. (VMS.H.)
+ * Added some should-never-appear error messages in
+ * vms_open().
+ */
+
+#ifdef VMS /* For VMS only ! */
+
+#ifdef VMS_PK_EXTRA
+
+#include <ssdef.h>
+
+#ifndef VMS_ZIP
+#define VMS_ZIP
+#endif
+
+#include "crc32.h"
+#include "vms.h"
+#include "vmsdefs.h"
+
+#ifndef ERR
+#define ERR(x) (((x)&1)==0)
+#endif
+
+#ifndef NULL
+#define NULL (void*)(0L)
+#endif
+
+#ifndef UTIL
+
+static PK_info_t PK_def_info =
+{
+ ATR$C_RECATTR, ATR$S_RECATTR, {0},
+ ATR$C_UCHAR, ATR$S_UCHAR, {0},
+ ATR$C_CREDATE, ATR$S_CREDATE, {0},
+ ATR$C_REVDATE, ATR$S_REVDATE, {0},
+ ATR$C_EXPDATE, ATR$S_EXPDATE, {0},
+ ATR$C_BAKDATE, ATR$S_BAKDATE, {0},
+ ATR$C_ASCDATES, sizeof(ush), 0,
+ ATR$C_UIC, ATR$S_UIC, {0},
+ ATR$C_FPRO, ATR$S_FPRO, {0},
+ ATR$C_RPRO, ATR$S_RPRO, {0},
+ ATR$C_JOURNAL, ATR$S_JOURNAL, {0}
+};
+
+/* File description structure for Zip low level I/O */
+typedef struct
+{
+ struct iosb iosb;
+ long vbn;
+ uzoff_t size;
+ uzoff_t rest;
+ int status;
+ ush chan;
+ ush chan_pad; /* alignment member */
+ long acllen;
+ uch aclbuf[ATR$S_READACL];
+ PK_info_t PKi;
+} ioctx_t;
+
+
+/* Forward declarations of public functions: */
+ioctx_t *vms_open(char *file);
+unsigned int vms_read(register ioctx_t *ctx,
+ register char *buf, register unsigned int size);
+int vms_error(ioctx_t *ctx);
+int vms_rewind(ioctx_t *ctx);
+int vms_get_attributes(ioctx_t *ctx, struct zlist far *z,
+ iztimes *z_utim);
+int vms_close(ioctx_t *ctx);
+
+
+#define BLOCK_BYTES 512
+
+
+/*---------------*
+ | vms_open() |
+ *---------------*
+ | This routine opens file for reading fetching its attributes.
+ | Returns pointer to file description structure.
+ */
+
+ioctx_t *vms_open(file)
+char *file;
+{
+ static struct atrdef Atr[VMS_MAX_ATRCNT+1];
+ static struct NAM_STRUCT Nam;
+ static struct fibdef Fib;
+ static struct dsc$descriptor FibDesc =
+ {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,(char *)&Fib};
+ static struct dsc$descriptor_s DevDesc =
+ {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.NAM_DVI[1]};
+ static char EName[NAM_MAXRSS];
+ static char RName[NAM_MAXRSS];
+
+ struct FAB Fab;
+ register ioctx_t *ctx;
+ register struct fatdef *fat;
+ int status;
+ int i;
+ ulg efblk;
+ ulg hiblk;
+
+ if ( (ctx=(ioctx_t *)malloc(sizeof(ioctx_t))) == NULL )
+ return NULL;
+ ctx -> PKi = PK_def_info;
+
+#define FILL_REQ(ix,id,b) { \
+ Atr[ix].atr$l_addr = GVTC &(b); \
+ Atr[ix].atr$w_type = (id); \
+ Atr[ix].atr$w_size = sizeof(b); \
+}
+
+ FILL_REQ(0, ATR$C_RECATTR, ctx->PKi.ra);
+ FILL_REQ(1, ATR$C_UCHAR, ctx->PKi.uc);
+ FILL_REQ(2, ATR$C_REVDATE, ctx->PKi.rd);
+ FILL_REQ(3, ATR$C_EXPDATE, ctx->PKi.ed);
+ FILL_REQ(4, ATR$C_CREDATE, ctx->PKi.cd);
+ FILL_REQ(5, ATR$C_BAKDATE, ctx->PKi.bd);
+ FILL_REQ(6, ATR$C_ASCDATES, ctx->PKi.rn);
+ FILL_REQ(7, ATR$C_JOURNAL, ctx->PKi.jr);
+ FILL_REQ(8, ATR$C_RPRO, ctx->PKi.rp);
+ FILL_REQ(9, ATR$C_FPRO, ctx->PKi.fp);
+ FILL_REQ(10,ATR$C_UIC, ctx->PKi.ui);
+ FILL_REQ(11,ATR$C_ACLLENGTH,ctx->acllen);
+ FILL_REQ(12,ATR$C_READACL, ctx->aclbuf);
+
+ Atr[13].atr$w_type = 0; /* End of ATR list */
+ Atr[13].atr$w_size = 0;
+ Atr[13].atr$l_addr = GVTC NULL;
+
+ /* Initialize RMS structures. We need a NAM[L] to retrieve the FID. */
+ Fab = cc$rms_fab;
+ Nam = CC_RMS_NAM;
+ Fab.FAB_NAM = &Nam; /* FAB has an associated NAM[L]. */
+
+#ifdef NAML$C_MAXRSS
+
+ Fab.fab$l_dna =(char *) -1; /* Using NAML for default name. */
+ Fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNA = file ; /* File name. */
+ FAB_OR_NAML( Fab, Nam).FAB_OR_NAML_FNS = strlen(file);
+ Nam.NAM_ESA = EName; /* expanded filename */
+ Nam.NAM_ESS = sizeof(EName);
+ Nam.NAM_RSA = RName; /* resultant filename */
+ Nam.NAM_RSS = sizeof(RName);
+
+ /* Do $PARSE and $SEARCH here. */
+ status = sys$parse(&Fab);
+
+ if (!(status & 1))
+ {
+ fprintf( stderr,
+ " vms_open(): $parse sts = %%x%08x.\n", status);
+ return NULL;
+ }
+
+#ifdef NAML$M_OPEN_SPECIAL
+ /* 2007-02-28 SMS.
+ * If processing symlinks as symlinks ("-y"), then $SEARCH for the
+ * link, not the target file.
+ */
+ if (linkput)
+ {
+ Nam.naml$v_open_special = 1;
+ }
+#endif /* def NAML$M_OPEN_SPECIAL */
+
+ /* Search for the first file. If none, signal error. */
+ status = sys$search(&Fab);
+
+ if (!(status & 1))
+ {
+ fprintf( stderr,
+ " vms_open(): $search sts = %%x%08x.\n", status);
+ return NULL;
+ }
+
+ /* Initialize Device name length. Note that this points into the
+ NAM[L] to get the device name filled in by the $PARSE, $SEARCH
+ services.
+ */
+ DevDesc.dsc$w_length = Nam.NAM_DVI[0];
+
+ status = sys$assign(&DevDesc,&ctx->chan,0,0);
+
+ if (!(status & 1))
+ {
+ fprintf( stderr,
+ " vms_open(): $assign sts = %%x%08x.\n", status);
+ return NULL;
+ }
+
+ /* Move the FID (and not the DID) into the FIB.
+ 2005=02-08 SMS.
+ Note that only the FID is needed, not the DID, and not the file
+ name. Setting these other items causes failures on ODS5.
+ */
+ Fib.FIB$L_ACCTL = FIB$M_NOWRITE;
+
+ for (i = 0; i < 3; i++)
+ {
+ Fib.FIB$W_FID[ i] = Nam.NAM_FID[ i];
+ Fib.FIB$W_DID[ i] = 0;
+ }
+
+ /* Use the IO$_ACCESS function to return info about the file. */
+ status = sys$qiow( 0, ctx->chan,
+ (IO$_ACCESS| IO$M_ACCESS), &ctx->iosb, 0, 0,
+ &FibDesc, 0, 0, 0, Atr, 0);
+
+ if (ERR(status) || ERR(status = ctx->iosb.status))
+ {
+ vms_close(ctx);
+ fprintf( stderr,
+ " vms_open(): $qiow (access) sts = %%x%08x, iosb sts = %%x%08x.\n",
+ status, ctx->iosb.status);
+ return NULL;
+ }
+
+ fat = (struct fatdef *)&(ctx -> PKi.ra);
+
+#define SWAPW(x) ( (((x)>>16)&0xFFFF) + ((x)<<16) )
+
+ efblk = SWAPW(fat->fat$l_efblk);
+ hiblk = SWAPW(fat->fat$l_hiblk);
+
+ if (efblk == 0)
+ {
+ /* Only known size is all allocated blocks.
+ (This occurs with a zero-length file, for example.)
+ */
+ ctx -> size =
+ ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
+ }
+ else
+ {
+ /* Store normal (used) size in ->size.
+ If only one -V, store normal (used) size in ->rest.
+ If multiple -V, store allocated-blocks size in ->rest.
+ */
+ ctx -> size =
+ (((uzoff_t) efblk)- 1)* BLOCK_BYTES+ fat -> fat$w_ffbyte;
+
+ if (vms_native < 2)
+ ctx -> rest = ctx -> size;
+ else
+ ctx -> rest = ((uzoff_t) hiblk)* BLOCK_BYTES;
+ }
+
+ ctx -> status = SS$_NORMAL;
+ ctx -> vbn = 1;
+ return ctx;
+}
+
+
+#define KByte (2* BLOCK_BYTES)
+#define MAX_READ_BYTES (32* KByte)
+
+/*----------------*
+ | vms_read() |
+ *----------------*
+ | Reads file in (multi-)block-sized chunks into the buffer.
+ | Stops on EOF. Returns number of bytes actually read.
+ | Note: This function makes no sense (and will error) if the buffer
+ | size ("size") is not a multiple of the disk block size (512).
+ */
+
+size_t vms_read( ctx, buf, size)
+ioctx_t *ctx;
+char *buf;
+size_t size;
+{
+ int act_cnt;
+ uzoff_t rest_rndup;
+ int status;
+ size_t bytes_read = 0;
+
+ /* If previous read hit EOF, fail early. */
+ if (ctx -> status == SS$_ENDOFFILE)
+ return 0; /* EOF. */
+
+ /* If no more expected to be read, fail early. */
+ if (ctx -> rest == 0)
+ return 0; /* Effective EOF. */
+
+ /* If request is smaller than a whole block, fail.
+ This really should never happen. (assert()?)
+ */
+ if (size < BLOCK_BYTES)
+ return 0;
+
+ /* Note that on old VMS VAX versions (like V5.5-2), QIO[W] may fail
+ with status %x0000034c (= %SYSTEM-F-IVBUFLEN, invalid buffer
+ length) when size is not a multiple of 512. Thus the requested
+ size is boosted as needed, but the IOSB byte count returned is
+ reduced when it exceeds the actual bytes remaining (->rest).
+ */
+
+ /* Adjust request size as appropriate. */
+ if (size > MAX_READ_BYTES)
+ {
+ /* Restrict request to MAX_READ_BYTES. */
+ size = MAX_READ_BYTES;
+ }
+ else
+ {
+ /* Round odd-ball request up to the next whole block.
+ This really should never happen. (assert()?)
+ */
+ size = (size+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
+ }
+ rest_rndup = (ctx -> rest+ BLOCK_BYTES- 1)& ~(BLOCK_BYTES- 1);
+
+ /* Read (QIOW) until error or "size" bytes have been read. */
+ do
+ {
+ /* Reduce "size" when next (last) read would overrun the EOF,
+ but never below one block (so we'll always get a nice EOF).
+ */
+ if (size > rest_rndup)
+ size = rest_rndup;
+
+ status = sys$qiow( 0, ctx->chan, IO$_READVBLK,
+ &ctx->iosb, 0, 0,
+ buf, size, ctx->vbn, 0, 0, 0);
+
+ /* If initial status was good, use final status. */
+ if ( !ERR(status) )
+ status = ctx->iosb.status;
+
+ if ( !ERR(status) || status == SS$_ENDOFFILE )
+ {
+ act_cnt = ctx->iosb.count;
+ /* Ignore whole-block boost when remainder is smaller. */
+ if (act_cnt > ctx->rest)
+ {
+ act_cnt = ctx->rest;
+ status = SS$_ENDOFFILE;
+ }
+ /* Adjust counters/pointers according to delivered bytes. */
+ size -= act_cnt;
+ buf += act_cnt;
+ bytes_read += act_cnt;
+ ctx->vbn += ctx->iosb.count/ BLOCK_BYTES;
+ }
+
+ } while ( !ERR(status) && (size > 0) );
+
+ if (!ERR(status))
+ {
+ /* Record any successful status as SS$_NORMAL. */
+ ctx -> status = SS$_NORMAL;
+ }
+ else if (status == SS$_ENDOFFILE)
+ {
+ /* Record EOF as SS$_ENDOFFILE. (Ignore error status codes?) */
+ ctx -> status = SS$_ENDOFFILE;
+ }
+
+ /* Decrement bytes-to-read. Return the total bytes read. */
+ ctx -> rest -= bytes_read;
+
+ return bytes_read;
+}
+
+/*-----------------*
+ | vms_error() |
+ *-----------------*
+ | Returns whether last operation on the file caused an error
+ */
+
+int vms_error(ctx)
+ioctx_t *ctx;
+{ /* EOF is not actual error */
+ return ERR(ctx->status) && (ctx->status != SS$_ENDOFFILE);
+}
+
+/*------------------*
+ | vms_rewind() |
+ *------------------*
+ | Rewinds file to the beginning for the next vms_read().
+ */
+
+int vms_rewind(ctx)
+ioctx_t *ctx;
+{
+ ctx -> vbn = 1;
+ ctx -> rest = ctx -> size;
+ return 0;
+}
+
+/*--------------------------*
+ | vms_get_attributes() |
+ *--------------------------*
+ | Malloc a PKWARE extra field and fill with file attributes. Returns
+ | error number of the ZE_??? class.
+ | If the passed ioctx record "FILE *" pointer is NULL, vms_open() is
+ | called to fetch the file attributes.
+ | When `vms_native' is not set, a generic "UT" type timestamp extra
+ | field is generated instead.
+ |
+ | 2004-11-11 SMS.
+ | Changed to use separate storage for ->extra and ->cextra. Zip64
+ | processing may move (reallocate) one and not the other.
+ */
+
+int vms_get_attributes(ctx, z, z_utim)
+ioctx_t *ctx; /* Internal file control structure. */
+struct zlist far *z; /* Zip entry to compress. */
+iztimes *z_utim;
+{
+ byte *p;
+ byte *xtra;
+ byte *cxtra;
+ struct PK_header *h;
+ extent l;
+ int notopened;
+
+ if ( !vms_native )
+ {
+#ifdef USE_EF_UT_TIME
+ /*
+ * A `portable' zipfile entry is created. Create an "UT" extra block
+ * containing UNIX style modification time stamp in UTC, which helps
+ * maintaining the `real' "last modified" time when the archive is
+ * transfered across time zone boundaries.
+ */
+# ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ return ZE_OK; /* skip silently if no valid TZ info */
+# endif
+
+ if ((xtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+ return ZE_MEM;
+
+ if ((cxtra = (uch *) malloc( EB_HEADSIZE+ EB_UT_LEN( 1))) == NULL)
+ return ZE_MEM;
+
+ /* Fill xtra[] with data. */
+ xtra[ 0] = 'U';
+ xtra[ 1] = 'T';
+ xtra[ 2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ xtra[ 3] = 0;
+ xtra[ 4] = EB_UT_FL_MTIME;
+ xtra[ 5] = (byte) (z_utim->mtime);
+ xtra[ 6] = (byte) (z_utim->mtime >> 8);
+ xtra[ 7] = (byte) (z_utim->mtime >> 16);
+ xtra[ 8] = (byte) (z_utim->mtime >> 24);
+
+ /* Copy xtra[] data into cxtra[]. */
+ memcpy( cxtra, xtra, (EB_HEADSIZE+ EB_UT_LEN( 1)));
+
+ /* Set sizes and pointers. */
+ z->cext = z->ext = (EB_HEADSIZE+ EB_UT_LEN( 1));
+ z->extra = (char*) xtra;
+ z->cextra = (char*) cxtra;
+
+#endif /* USE_EF_UT_TIME */
+
+ return ZE_OK;
+ }
+
+ notopened = (ctx == NULL);
+ if ( notopened && ((ctx = vms_open(z->name)) == NULL) )
+ return ZE_OPEN;
+
+ l = PK_HEADER_SIZE + sizeof(ctx->PKi);
+ if (ctx->acllen > 0)
+ l += PK_FLDHDR_SIZE + ctx->acllen;
+
+ if ((xtra = (uch *) malloc( l)) == NULL)
+ return ZE_MEM;
+
+ if ((cxtra = (uch *) malloc( l)) == NULL)
+ return ZE_MEM;
+
+ /* Fill xtra[] with data. */
+
+ h = (struct PK_header *) xtra;
+ h->tag = PK_SIGNATURE;
+ h->size = l - EB_HEADSIZE;
+ p = (h->data);
+
+ /* Copy default set of attributes */
+ memcpy(h->data, (char*)&(ctx->PKi), sizeof(ctx->PKi));
+ p += sizeof(ctx->PKi);
+
+ if ( ctx->acllen > 0 )
+ {
+ struct PK_field *f;
+
+ if (dosify)
+ zipwarn("file has ACL, may be incompatible with PKUNZIP","");
+
+ f = (struct PK_field *)p;
+ f->tag = ATR$C_ADDACLENT;
+ f->size = ctx->acllen;
+ memcpy((char *)&(f->value[0]), ctx->aclbuf, ctx->acllen);
+ p += PK_FLDHDR_SIZE + ctx->acllen;
+ }
+
+
+ h->crc32 = CRCVAL_INITIAL; /* Init CRC register */
+ h->crc32 = crc32(h->crc32, (uch *)(h->data), l - PK_HEADER_SIZE);
+
+ /* Copy xtra[] data into cxtra[]. */
+ memcpy( cxtra, xtra, l);
+
+ /* Set sizes and pointers. */
+ z->ext = z->cext = l;
+ z->extra = (char *) xtra;
+ z->cextra = (char *) cxtra;
+
+ if (notopened) /* close "ctx", if we have opened it here */
+ vms_close(ctx);
+
+ return ZE_OK;
+}
+
+
+int vms_close(ctx)
+ioctx_t *ctx;
+{
+ sys$dassgn(ctx->chan);
+ free(ctx);
+ return 0;
+}
+
+#endif /* !_UTIL */
+
+#endif /* def VMS_PK_EXTRA */
+
+#endif /* VMS */
diff --git a/vms/vmsdefs.h b/vms/vmsdefs.h
new file mode 100644
index 0000000..73d013a
--- /dev/null
+++ b/vms/vmsdefs.h
@@ -0,0 +1,320 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ vmsdefs.h
+
+ Contents of three header files from Joe
+ Meadows' FILE program. Used by vmsmunch
+
+ 06-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved "contents of three header files" from
+ VMSmunch.h to VMSdefs.h .
+
+ 16-Sep-1995 Christian Spieler
+ Added #pragma (no)member_alignment directives
+ to achieve compatibility with DEC C and Alpha AXP
+
+ 05-Oct-1995 Christian Spieler
+ Revised fatdef, fchdef, fjndef to achieve closer
+ compatibility with DEC's system include header files
+ supplied with C version 4.0 and newer.
+
+ 10-Oct-1995 Christian Spieler
+ Use lowercase filenames for vms specific sources
+ (VMSmunch.? -> vmsmunch.?, VMSdefs.h -> vmsdefs.h)
+
+ 15-Dec-1995 Christian Spieler
+ Removed the last "tabs" from the source.
+
+ 24-Jun-1997 Onno van der Linden / Chr. Spieler
+ Modifications to support the VMS port of GNU C 2.x.
+
+ 27-Jul-1999 Chr. Spieler
+ Added Info-ZIP copyright note for identification.
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef __vmsdefs_h
+#define __vmsdefs_h 1
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __nostandard
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __save
+#pragma __nomember_alignment
+#endif /* __DECC || __DECCXX */
+
+#if !(defined(__VAXC) || defined(VAXC)) || defined(__GNUC__)
+#define __struct struct
+#define __union union
+#else
+#define __struct variant_struct
+#define __union variant_union
+#endif /* !(__VAXC || VAXC) || __GNUC__ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*---------------------------------------------------------------------------
+ fatdef.h
+ ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+ in any way. No guarantee is made as to the accuracy of the contents
+ of this header file. This header file was last modified on Sep. 22th,
+ 1987. (Modified to include this statement) */
+
+#define FAT$K_LENGTH 32
+#define FAT$C_LENGTH 32
+#define FAT$S_FATDEF 32
+
+struct fatdef {
+ __union {
+ unsigned char fat$b_rtype; /* record type */
+ __struct {
+ unsigned fat$v_rtype : 4; /* record type subfield */
+ unsigned fat$v_fileorg : 4; /* file organization */
+ } fat$r_rtype_bits;
+ } fat$r_rtype_overlay;
+# define FAT$S_RTYPE 4
+# define FAT$V_RTYPE 0
+# define FAT$C_UNDEFINED 0
+# define FAT$C_FIXED 1
+# define FAT$C_VARIABLE 2
+# define FAT$C_VFC 3
+# define FAT$C_STREAM 4
+# define FAT$C_STREAMLF 5
+# define FAT$C_STREAMCR 6
+# define FAT$S_FILEORG 4
+# define FAT$V_FILEORG 4
+# define FAT$C_SEQUENTIAL 0
+# define FAT$C_RELATIVE 1
+# define FAT$C_INDEXED 2
+# define FAT$C_DIRECT 3
+ __union {
+ unsigned char fat$b_rattrib; /* record attributes */
+ __struct {
+ unsigned fat$v_fortrancc : 1;
+ unsigned fat$v_impliedcc : 1;
+ unsigned fat$v_printcc : 1;
+ unsigned fat$v_nospan : 1;
+ unsigned fat$v_msbrcw : 1;
+ } fat$r_rattrib_bits;
+ } fat$r_rattrib_overlay;
+# define FAT$V_FORTRANCC 0
+# define FAT$M_FORTRANCC 1
+# define FAT$V_IMPLIEDCC 1
+# define FAT$M_IMPLIEDCC 2
+# define FAT$V_PRINTCC 2
+# define FAT$M_PRINTCC 4
+# define FAT$V_NOSPAN 3
+# define FAT$M_NOSPAN 8
+# define FAT$V_MSBRCW 4
+# define FAT$M_MSBRCW 16
+ unsigned short int fat$w_rsize; /* record size in bytes */
+ __union
+ {
+ unsigned long int fat$l_hiblk; /* highest allocated VBN */
+ __struct
+ {
+ unsigned short int fat$w_hiblkh; /* high order word */
+ unsigned short int fat$w_hiblkl; /* low order word */
+ } fat$r_hiblk_fields;
+ } fat$r_hiblk_overlay;
+ __union
+ {
+ unsigned long int fat$l_efblk; /* end of file VBN */
+ __struct
+ {
+ unsigned short int fat$w_efblkh; /* high order word */
+ unsigned short int fat$w_efblkl; /* low order word */
+ } fat$r_efblk_fields;
+ } fat$r_efblk_overlay;
+ unsigned short int fat$w_ffbyte; /* first free byte in EFBLK */
+ unsigned char fat$b_bktsize; /* bucket size in blocks */
+ unsigned char fat$b_vfcsize; /* # of control bytes in VFC record */
+ unsigned short int fat$w_maxrec; /* maximum record size in bytes */
+ unsigned short int fat$w_defext; /* default extend quantity */
+ unsigned short int fat$w_gbc; /* global buffer count */
+ char fat$fill[8];
+ unsigned short int fat$w_versions;
+};
+
+#if !(defined(__VAXC) || defined(VAXC)) || defined(__GNUC__)
+#define fat$b_rtype fat$r_rtype_overlay.fat$b_rtype
+#define fat$v_rtype fat$r_rtype_overlay.fat$r_rtype_bits.fat$v_rtype
+#define fat$v_fileorg fat$r_rtype_overlay.fat$r_rtype_bits.fat$v_fileorg
+#define fat$b_rattrib fat$r_rattrib_overlay.fat$b_rattrib
+#define fat$v_fortrancc fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_fortrancc
+#define fat$v_impliedcc fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_impliedcc
+#define fat$v_printcc fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_printcc
+#define fat$v_nospan fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_nospan
+#define fat$v_msbrcw fat$r_rattrib_overlay.fat$r_rattrib_bits.fat$v_msbrcw
+#define fat$l_hiblk fat$r_hiblk_overlay.fat$l_hiblk
+#define fat$w_hiblkh fat$r_hiblk_overlay.fat$r_hiblk_fields.fat$w_hiblkh
+#define fat$w_hiblkl fat$r_hiblk_overlay.fat$r_hiblk_fields.fat$w_hiblkl
+#define fat$l_efblk fat$r_efblk_overlay.fat$l_efblk
+#define fat$w_efblkh fat$r_efblk_overlay.fat$r_efblk_fields.fat$w_efblkh
+#define fat$w_efblkl fat$r_efblk_overlay.fat$r_efblk_fields.fat$w_efblkl
+#endif /* !(__VAXC || VAXC) || __GNUC__ */
+
+#define __FATDEF_LOADED 1 /* prevent inclusion of DECC's fatdef.h */
+
+/*---------------------------------------------------------------------------
+ fchdef.h
+ ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+ in any way. No guarantee is made as to the accuracy of the contents
+ of this header file. This header file was last modified on Sep. 22th,
+ 1987. (Modified to include this statement) */
+
+#define FCH$V_BADACL 0x00B
+#define FCH$M_BADACL (1 << FCH$V_BADACL)
+#define FCH$V_BADBLOCK 0x00E
+#define FCH$M_BADBLOCK (1 << FCH$V_BADBLOCK)
+#define FCH$V_CONTIG 0x007
+#define FCH$M_CONTIG (1 << FCH$V_CONTIG)
+#define FCH$V_CONTIGB 0x005
+#define FCH$M_CONTIGB (1 << FCH$V_CONTIGB)
+#define FCH$V_DIRECTORY 0x00D
+#define FCH$M_DIRECTORY (1 << FCH$V_DIRECTORY)
+#define FCH$V_ERASE 0x011
+#define FCH$M_ERASE (1 << FCH$V_ERASE)
+#define FCH$V_LOCKED 0x006
+#define FCH$M_LOCKED (1 << FCH$V_LOCKED)
+#define FCH$V_MARKDEL 0x00F
+#define FCH$M_MARKDEL (1 << FCH$V_MARKDEL)
+#define FCH$V_NOBACKUP 0x001
+#define FCH$M_NOBACKUP (1 << FCH$V_NOBACKUP)
+#define FCH$V_NOCHARGE 0x010
+#define FCH$M_NOCHARGE (1 << FCH$V_NOCHARGE)
+#define FCH$V_READCHECK 0x003
+#define FCH$M_READCHECK (1 << FCH$V_READCHECK)
+#define FCH$V_SPOOL 0x00C
+#define FCH$M_SPOOL (1 << FCH$V_SPOOL)
+#define FCH$V_WRITCHECK 0x004
+#define FCH$M_WRITCHECK (1 << FCH$V_WRITCHECK)
+#define FCH$V_WRITEBACK 0x002
+#define FCH$M_WRITEBACK (1 << FCH$V_WRITEBACK)
+
+struct fchdef {
+ __union {
+ int fch$$_fill_1;
+ __struct {
+ unsigned fch$$_fill_31 : 8;
+ unsigned fch$v_vcc_state : 3; /* VCC state bits */
+ unsigned fch$$_fill_32 : 7;
+ unsigned fch$$_alm_state : 2;
+ unsigned fch$v_associated : 1; /* ISO 9660 Associated file */
+ unsigned fch$v_existence : 1; /* ISO 9660 Existence file */
+ unsigned fch$v_fill_6 : 2;
+ } fch$r_fill_1_chunks;
+ __struct {
+ unsigned fch$v_wascontig : 1;
+ unsigned fch$v_nobackup : 1 ;
+ unsigned fch$v_writeback : 1;
+ unsigned fch$v_readcheck : 1;
+ unsigned fch$v_writcheck : 1;
+ unsigned fch$v_contigb : 1;
+ unsigned fch$v_locked : 1;
+ unsigned fch$v_contig : 1;
+ unsigned fch$$_fill_3 : 3;
+ unsigned fch$v_badacl : 1;
+ unsigned fch$v_spool : 1;
+ unsigned fch$v_directory : 1;
+ unsigned fch$v_badblock : 1;
+ unsigned fch$v_markdel : 1;
+ unsigned fch$v_nocharge : 1;
+ unsigned fch$v_erase : 1;
+ unsigned fch$$_fill_4 : 1;
+ unsigned fch$v_shelved : 1;
+ unsigned fch$v_scratch : 1;
+ unsigned fch$v_nomove : 1;
+ unsigned fch$v_noshelvable : 1;
+ } fch$r_fill_1_bits;
+ } fch$r_fch_union;
+};
+
+#if !(defined(__VAXC) || defined(VAXC)) || defined(__GNUC__)
+#define fch$v_vcc_state fch$r_fch_union.fch$r_fill_1_chunks.fch$v_vcc_state
+#define fch$v_associated fch$r_fch_union.fch$r_fill_1_chunks.fch$v_associated
+#define fch$v_existence fch$r_fch_union.fch$r_fill_1_chunks.fch$v_existence
+#define fch$v_wascontig fch$r_fch_union.fch$r_fill_1_bits.fch$v_wascontig
+#define fch$v_nobackup fch$r_fch_union.fch$r_fill_1_bits.fch$v_nobackup
+#define fch$v_writeback fch$r_fch_union.fch$r_fill_1_bits.fch$v_writeback
+#define fch$v_readcheck fch$r_fch_union.fch$r_fill_1_bits.fch$v_readcheck
+#define fch$v_writcheck fch$r_fch_union.fch$r_fill_1_bits.fch$v_writcheck
+#define fch$v_contigb fch$r_fch_union.fch$r_fill_1_bits.fch$v_contigb
+#define fch$v_locked fch$r_fch_union.fch$r_fill_1_bits.fch$v_locked
+#define fch$v_contig fch$r_fch_union.fch$r_fill_1_bits.fch$v_contig
+#define fch$v_badacl fch$r_fch_union.fch$r_fill_1_bits.fch$v_badacl
+#define fch$v_spool fch$r_fch_union.fch$r_fill_1_bits.fch$v_spool
+#define fch$v_directory fch$r_fch_union.fch$r_fill_1_bits.fch$v_directory
+#define fch$v_badblock fch$r_fch_union.fch$r_fill_1_bits.fch$v_badblock
+#define fch$v_markdel fch$r_fch_union.fch$r_fill_1_bits.fch$v_markdel
+#define fch$v_nocharge fch$r_fch_union.fch$r_fill_1_bits.fch$v_nocharge
+#define fch$v_erase fch$r_fch_union.fch$r_fill_1_bits.fch$v_erase
+#define fch$v_shelved fch$r_fch_union.fch$r_fill_1_bits.fch$v_shelved
+#define fch$v_scratch fch$r_fch_union.fch$r_fill_1_bits.fch$v_scratch
+#define fch$v_nomove fch$r_fch_union.fch$r_fill_1_bits.fch$v_nomove
+#define fch$v_noshelvable fch$r_fch_union.fch$r_fill_1_bits.fch$v_noshelvable
+#endif /* !(__VAXC || VAXC) || __GNUC__ */
+
+#define __FCHDEF_LOADED 1 /* prevent inclusion of DECC's fchdef.h */
+
+/*---------------------------------------------------------------------------
+ fjndef.h
+ ---------------------------------------------------------------------------*/
+
+/* This header file was created by Joe Meadows, and is not copyrighted
+ in any way. No guarantee is made as to the accuracy of the contents
+ of this header file. This header file was last modified on Sep. 22th,
+ 1987. (Modified to include this statement) */
+
+#define FJN$M_ONLY_RU 1
+#define FJN$M_RUJNL 2
+#define FJN$M_BIJNL 4
+#define FJN$M_AIJNL 8
+#define FJN$M_ATJNL 16
+#define FJN$M_NEVER_RU 32
+#define FJN$M_JOURNAL_FILE 64
+#define FJN$S_FJNDEF 1
+struct fjndef {
+ unsigned fjn$v_only_ru : 1;
+ unsigned fjn$v_rujnl : 1;
+ unsigned fjn$v_bijnl : 1;
+ unsigned fjn$v_aijnl : 1;
+ unsigned fjn$v_atjnl : 1;
+ unsigned fjn$v_never_ru : 1;
+ unsigned fjn$v_journal_file : 1;
+ unsigned fjn$v_fill_7 : 1;
+} ;
+
+#define __FJNDEF_LOADED 1 /* prevent inclusion of DECC's fjndef.h */
+
+/*---------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __restore
+#endif /* __DECC || __DECCXX */
+
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __standard
+#endif /* __DECC || __DECCXX */
+
+#endif /* !__vmsdefs_h */
diff --git a/vms/vmsmunch.c b/vms/vmsmunch.c
new file mode 100644
index 0000000..8140036
--- /dev/null
+++ b/vms/vmsmunch.c
@@ -0,0 +1,434 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# define module_name VMSMUNCH
+# define module_version "V1.3-4"
+#endif /* 0 */
+
+/*
+ * Modified by:
+ *
+ * v1.3.1 O.v.d.Linden, C. Spieler 04-JUL-1998 14:35
+ * Modified check that decides on the type of definitions for
+ * FIB$W_FID etc. to support GNU C.
+ *
+ * v1.3 Hunter Goatley 14-SEP-1992 08:51
+ * Added definitions of FIB$W_FID, FIB$W_DID, and
+ * FIB$L_ACCTL to allow for the fact that fibdef
+ * contains variant_unions under Alpha.
+ */
+/*---------------------------------------------------------------------------
+
+ vmsmunch.c version 1.2 28 Apr 1992
+
+ This routine is a blatant and unrepentent appropriation of all the nasty
+ and difficult-to-do and complicated VMS shenanigans which Joe Meadows has
+ so magnificently captured in his FILE utility. Not only that, it's even
+ allowed! (see below). But let it be clear at the outset that Joe did all
+ the work; yea, verily, he is truly a godlike unit.
+
+ The appropriations and modifications herein were performed primarily by
+ him known as "Cave Newt," although the Info-ZIP working group probably had
+ their fingers in it somewhere along the line. The idea is to put the raw
+ power of Joe's original routine at the disposal of various routines used
+ by UnZip (and Zip, possibly), not least among them the utime() function.
+ Read on for details...
+
+ 01-SEP-1994 Richard Levitte <levitte@e.kth.se>
+ If one of the fields given to VMSmunch are NULL,
+ do not update the corresponding daytime.
+
+ 18-JUL-1994 Hunter Goatley <goathunter@WKU.EDU>
+ Fixed IO$_ACCESS call.
+
+ 18-Jul-1994 Richard Levitte levitte@e.kth.se
+ Changed VMSmunch() to deassign the channel before
+ returning when an error has occured.
+
+ 02-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved definition of VMStimbuf struct from here
+ to vmsmunch.h
+ ---------------------------------------------------------------------------
+
+ Usage (i.e., "interface," in geek-speak):
+
+ int VMSmunch( char *filename, int action, char *ptr );
+
+ filename the name of the file on which to be operated, obviously
+ action an integer which specifies what action to take
+ ptr pointer to any extra item which may be needed (else NULL)
+
+ The possible values for the action argument are as follows:
+
+ GET_TIMES get the creation and revision dates of filename; ptr
+ must point to an empty VMStimbuf struct, as defined
+ in vmsmunch.h
+ (with room for at least 24 characters, including term.)
+ SET_TIMES set the creation and revision dates of filename (utime
+ option); ptr must point to a valid VMStimbuf struct,
+ as defined in vmsmunch.h
+ GET_RTYPE get the record type of filename; ptr must point to an
+ integer which, on return, is set to the type (as defined
+ in vmsdefs.h: FAT$C_* defines)
+ CHANGE_RTYPE change the record type to that specified by the integer
+ to which ptr points; save the old record type (later
+ saves overwrite earlier ones)
+ RESTORE_RTYPE restore the record type to the previously saved value;
+ or, if none, set it to "fixed-length, 512-byte" record
+ format (ptr not used)
+
+ ---------------------------------------------------------------------------
+
+ Comments from FILE.C, a utility to modify file characteristics:
+
+ Written by Joe Meadows Jr, at the Fred Hutchinson Cancer Research Center
+ BITNET: JOE@FHCRCVAX
+ PHONE: (206) 467-4970
+
+ There are no restrictions on this code, you may sell it, include it
+ with any commercial package, or feed it to a whale.. However, I would
+ appreciate it if you kept this comment in the source code so that anyone
+ receiving this code knows who to contact in case of problems. Note that
+ I do not demand this condition..
+
+ ---------------------------------------------------------------------------*/
+
+
+/* 2004-12-13 SMS.
+ * Disabled the module name macro to accommodate old GNU C which didn't
+ * obey the directive, and thus confused MMS/MMK where the object
+ * library dependencies need to have the correct module name.
+ */
+#if 0
+# if defined(__DECC) || defined(__GNUC__)
+# pragma module module_name module_version
+# else
+# module module_name module_version
+# endif
+#endif /* 0 */
+
+/*****************************/
+/* Includes, Defines, etc. */
+/*****************************/
+
+/* Accomodation for /NAMES = AS_IS with old header files. */
+
+#define sys$asctim SYS$ASCTIM
+#define sys$assign SYS$ASSIGN
+#define sys$bintim SYS$BINTIM
+#define sys$dassgn SYS$DASSGN
+#define sys$parse SYS$PARSE
+#define sys$qiow SYS$QIOW
+#define sys$search SYS$SEARCH
+
+#include "zip.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <iodef.h>
+#include <starlet.h>
+#include <fibdef.h> /* this gets created with the c3.0 compiler */
+
+/*
+ * Under Alpha (DEC C in VAXC mode) and under `good old' VAXC, the FIB unions
+ * are declared as variant_unions. DEC C (Alpha) in ANSI modes and third
+ * party compilers which do not support `variant_union' define preprocessor
+ * symbols to `hide' the "intermediate union/struct" names from the
+ * programmer's API.
+ * We check the presence of these defines and for DEC's FIBDEF.H defining
+ * __union as variant_union to make sure we access the structure correctly.
+ */
+#if defined(fib$w_did) || (defined(__union) && (__union == variant_union))
+# define FIB$W_DID fib$w_did
+# define FIB$W_FID fib$w_fid
+# define FIB$L_ACCTL fib$l_acctl
+#else
+# define FIB$W_DID fib$r_did_overlay.fib$w_did
+# define FIB$W_FID fib$r_fid_overlay.fib$w_fid
+# define FIB$L_ACCTL fib$r_acctl_overlay.fib$l_acctl
+#endif
+
+#include "vms.h"
+#include "vmsmunch.h" /* GET/SET_TIMES, RTYPE, etc. */
+#include "vmsdefs.h" /* fatdef.h, etc. */
+
+static void asctim(char *time, long int binval[2]);
+static void bintim(char *time, long int binval[2]);
+
+/* from <ssdef.h> */
+#ifndef SS$_NORMAL
+# define SS$_NORMAL 1
+# define SS$_BADPARAM 20
+#endif
+
+
+/* On VAX, define Goofy VAX Type-Cast to obviate /standard = vaxc.
+ Otherwise, lame system headers on VAX cause compiler warnings.
+ (GNU C may define vax but not __VAX.)
+*/
+#ifdef vax
+# define __VAX 1
+#endif /* def vax */
+
+#ifdef __VAX
+# define GVTC (unsigned int)
+#else /* def __VAX */
+# define GVTC
+#endif /* def __VAX */
+
+
+/*************************/
+/* Function VMSmunch() */
+/*************************/
+
+int VMSmunch(
+ char *filename,
+ int action,
+ char *ptr )
+{
+
+ /* original file.c variables */
+
+ static struct FAB Fab;
+ static struct NAM_STRUCT Nam;
+ static struct fibdef Fib; /* short fib */
+
+ static struct dsc$descriptor FibDesc =
+ {sizeof(Fib),DSC$K_DTYPE_Z,DSC$K_CLASS_S,(char *)&Fib};
+ static struct dsc$descriptor_s DevDesc =
+ {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,&Nam.NAM_DVI[1]};
+ static struct fatdef Fat;
+ static union {
+ struct fchdef fch;
+ long int dummy;
+ } uchar;
+ static struct fjndef jnl;
+ static long int Cdate[2],Rdate[2],Edate[2],Bdate[2];
+ static short int revisions;
+ static unsigned long uic;
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __save
+#pragma __nomember_alignment
+#endif /* __DECC || __DECCXX */
+ static union {
+ unsigned short int value;
+ struct {
+ unsigned system : 4;
+ unsigned owner : 4;
+ unsigned group : 4;
+ unsigned world : 4;
+ } bits;
+ } prot;
+#if defined(__DECC) || defined(__DECCXX)
+#pragma __member_alignment __restore
+#endif /* __DECC || __DECCXX */
+
+ static struct atrdef Atr[] = {
+ {sizeof(Fat),ATR$C_RECATTR, GVTC &Fat}, /* record attributes */
+ {sizeof(uchar),ATR$C_UCHAR, GVTC &uchar}, /* File characteristics */
+ {sizeof(Cdate),ATR$C_CREDATE, GVTC &Cdate[0]}, /* Creation date */
+ {sizeof(Rdate),ATR$C_REVDATE, GVTC &Rdate[0]}, /* Revision date */
+ {sizeof(Edate),ATR$C_EXPDATE, GVTC &Edate[0]}, /* Expiration date */
+ {sizeof(Bdate),ATR$C_BAKDATE, GVTC &Bdate[0]}, /* Backup date */
+ {sizeof(revisions),ATR$C_ASCDATES, GVTC &revisions}, /* number of revs */
+ {sizeof(prot),ATR$C_FPRO, GVTC &prot}, /* file protection */
+ {sizeof(uic),ATR$C_UIC, GVTC &uic}, /* file owner */
+ {sizeof(jnl),ATR$C_JOURNAL, GVTC &jnl}, /* journal flags */
+ {0,0,0}
+ } ;
+
+ static char EName[NAM_MAXRSS];
+ static char RName[NAM_MAXRSS];
+ static struct dsc$descriptor_s FileName =
+ {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+ static struct dsc$descriptor_s string = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+ static short int DevChan;
+ static short int iosb[4];
+
+ static long int i,status;
+/* static char *retval; */
+
+
+ /* new VMSmunch variables */
+
+ static int old_rtype=FAT$C_FIXED; /* storage for record type */
+
+
+
+/*---------------------------------------------------------------------------
+ Initialize attribute blocks, parse filename, resolve any wildcards, and
+ get the file info.
+ ---------------------------------------------------------------------------*/
+
+ /* Initialize RMS structures. We need a NAM[L] to retrieve the FID. */
+ Fab = cc$rms_fab;
+ Fab.fab$l_fna = filename;
+ Fab.fab$b_fns = strlen(filename);
+ Fab.FAB_NAM = &Nam; /* FAB has an associated NAM[L]. */
+ Nam = CC_RMS_NAM;
+ Nam.NAM_ESA = EName; /* expanded filename */
+ Nam.NAM_ESS = sizeof(EName);
+ Nam.NAM_RSA = RName; /* resultant filename */
+ Nam.NAM_RSS = sizeof(RName);
+
+ /* do $PARSE and $SEARCH here */
+ status = sys$parse(&Fab);
+ if (!(status & 1)) return(status);
+
+ /* search for the first file.. If none signal error */
+ status = sys$search(&Fab);
+ if (!(status & 1)) return(status);
+
+ while (status & 1) {
+ /* initialize Device name length, note that this points into the NAM[L]
+ to get the device name filled in by the $PARSE, $SEARCH services */
+ DevDesc.dsc$w_length = Nam.NAM_DVI[0];
+
+ status = sys$assign(&DevDesc,&DevChan,0,0);
+ if (!(status & 1)) return(status);
+
+ FileName.dsc$a_pointer = Nam.NAM_L_NAME;
+ FileName.dsc$w_length = Nam.NAM_B_NAME+Nam.NAM_B_TYPE+Nam.NAM_B_VER;
+
+ /* Initialize the FIB */
+ for (i=0;i<3;i++) {
+ Fib.FIB$W_FID[i]=Nam.NAM_FID[i];
+ Fib.FIB$W_DID[i]=Nam.NAM_DID[i];
+ }
+
+ /* Use the IO$_ACCESS function to return info about the file */
+ /* Note, used this way, the file is not opened, and the expiration */
+ /* and revision dates are not modified */
+ status = sys$qiow(0,DevChan,IO$_ACCESS,&iosb,0,0,
+ &FibDesc,&FileName,0,0,&Atr,0);
+ if (!(status & 1) || !((status = iosb[0]) & 1)) {
+ sys$dassgn(DevChan);
+ return(status);
+ }
+
+ /*-----------------------------------------------------------------------
+ We have the current information from the file: now see what user
+ wants done with it.
+ -----------------------------------------------------------------------*/
+
+ switch (action) {
+
+ case GET_TIMES: /* non-modifying */
+ asctim(((struct VMStimbuf *)ptr)->modtime, Cdate);
+ asctim(((struct VMStimbuf *)ptr)->actime, Rdate);
+ sys$dassgn(DevChan);
+ return RMS$_NORMAL; /* return to user */
+ break;
+
+ case SET_TIMES:
+ if (((struct VMStimbuf *)ptr)->modtime != (char *)NULL)
+ bintim(((struct VMStimbuf *)ptr)->modtime, Cdate);
+ if (((struct VMStimbuf *)ptr)->actime != (char *)NULL)
+ bintim(((struct VMStimbuf *)ptr)->actime, Rdate);
+ break;
+
+ case GET_RTYPE: /* non-modifying */
+ *(int *)ptr = Fat.fat$v_rtype;
+ sys$dassgn(DevChan);
+ return RMS$_NORMAL; /* return to user */
+ break;
+
+ case CHANGE_RTYPE:
+ old_rtype = Fat.fat$v_rtype; /* save current one */
+ if ((*(int *)ptr < FAT$C_UNDEFINED) ||
+ (*(int *)ptr > FAT$C_STREAMCR))
+ Fat.fat$v_rtype = FAT$C_STREAMLF; /* Unix I/O happy */
+ else
+ Fat.fat$v_rtype = *(int *)ptr;
+ break;
+
+ case RESTORE_RTYPE:
+ Fat.fat$v_rtype = old_rtype;
+ break;
+
+ default:
+ sys$dassgn(DevChan);
+ return SS$_BADPARAM; /* anything better? */
+ }
+
+ /*-----------------------------------------------------------------------
+ Go back and write modified data to the file header.
+ -----------------------------------------------------------------------*/
+
+ /* note, part of the FIB was cleared by earlier QIOW, so reset it */
+ Fib.FIB$L_ACCTL = FIB$M_NORECORD;
+ for (i=0;i<3;i++) {
+ Fib.FIB$W_FID[i]=Nam.NAM_FID[i];
+ Fib.FIB$W_DID[i]=Nam.NAM_DID[i];
+ }
+
+ /* Use the IO$_MODIFY function to change info about the file */
+ /* Note, used this way, the file is not opened, however this would */
+ /* normally cause the expiration and revision dates to be modified. */
+ /* Using FIB$M_NORECORD prohibits this from happening. */
+ status = sys$qiow(0,DevChan,IO$_MODIFY,&iosb,0,0,
+ &FibDesc,&FileName,0,0,&Atr,0);
+ if (!(status & 1) || !((status = iosb[0]) & 1)) {
+ sys$dassgn(DevChan);
+ return(status);
+ }
+
+ status = sys$dassgn(DevChan);
+ if (!(status & 1)) return(status);
+
+ /* look for next file, if none, no big deal.. */
+ status = sys$search(&Fab);
+ }
+ return(status);
+} /* end function VMSmunch() */
+
+
+
+
+
+/***********************/
+/* Function asctim() */
+/***********************/
+
+static void asctim( /* convert 64-bit binval to string, put in time */
+ char *time,
+ long int binval[2] )
+{
+ static struct dsc$descriptor date_str={23,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+ /* dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer */
+
+ date_str.dsc$a_pointer = time;
+ sys$asctim(0, &date_str, binval, 0);
+ time[23] = '\0';
+}
+
+
+
+
+
+/***********************/
+/* Function bintim() */
+/***********************/
+
+static void bintim( /* convert time string to 64 bits, put in binval */
+ char *time,
+ long int binval[2] )
+{
+ static struct dsc$descriptor date_str={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
+
+ date_str.dsc$w_length = strlen(time);
+ date_str.dsc$a_pointer = time;
+ sys$bintim(&date_str, binval);
+}
diff --git a/vms/vmsmunch.h b/vms/vmsmunch.h
new file mode 100644
index 0000000..458ad78
--- /dev/null
+++ b/vms/vmsmunch.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ vmsmunch.h
+
+ A few handy #defines, plus the contents of three header files from Joe
+ Meadows' FILE program. Used by VMSmunch and by various routines which
+ call VMSmunch (e.g., in Zip and UnZip).
+
+ 02-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved definition of VMStimbuf struct from vmsmunch.c
+ to here.
+
+ 06-Apr-1994 Jamie Hanrahan jeh@cmkrnl.com
+ Moved "contents of three header files" (not needed by
+ callers of vmsmunch) to VMSdefs.h .
+
+ 07-Apr-1994 Richard Levitte levitte@e.kth.se
+ Inserted a forward declaration of VMSmunch.
+
+ 17-Sep-1995 Chr. Spieler spieler@linac.ikp.physik.th-darmstadt.de
+ Added wrapper to prevent multiple loading of this file.
+
+ 10-Oct-1995 Chr. Spieler spieler@linac.ikp.physik.th-darmstadt.de
+ Use lowercase names for all VMS specific source files
+
+ 15-Dec-1995 Chr. Spieler spieler@linac.ikp.physik.th-darmstadt.de
+ Removed ALL "tabs" from source file.
+
+ ---------------------------------------------------------------------------*/
+
+#ifndef __vmsmunch_h
+#define __vmsmunch_h 1
+
+#define GET_TIMES 4
+#define SET_TIMES 0
+#define GET_RTYPE 1
+#define CHANGE_RTYPE 2
+#define RESTORE_RTYPE 3
+
+struct VMStimbuf { /* VMSmunch */
+ char *actime; /* VMS revision date, ASCII format */
+ char *modtime; /* VMS creation date, ASCII format */
+};
+
+extern int VMSmunch(char *filename, int action, char *ptr);
+
+#endif /* !__vmsmunch_h */
diff --git a/vms/vmszip.c b/vms/vmszip.c
new file mode 100644
index 0000000..2dae718
--- /dev/null
+++ b/vms/vmszip.c
@@ -0,0 +1,1444 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* 2005-02-14 SMS.
+ Added some ODS5 support.
+ Use longer name structures in NAML, where available.
+ Locate special characters mindful of "^" escapes.
+ Replaced compile-time case preservation (VMS_PRESERVE_CASE macro)
+ with command-line-specified case preservation (vms_case_x
+ variables).
+ Prototyped all functions.
+ Removed "#ifndef UTIL", as no one should be compiling it that way.
+*/
+
+#include "zip.h"
+#include "vmsmunch.h"
+#include "vms.h"
+
+#include <ctype.h>
+#include <time.h>
+#include <unixlib.h>
+
+/* Judge availability of str[n]casecmp() in C RTL.
+ (Note: This must follow a "#include <decc$types.h>" in something to
+ ensure that __CRTL_VER is as defined as it will ever be. DEC C on
+ VAX may not define it itself.)
+*/
+#ifdef __CRTL_VER
+#if __CRTL_VER >= 70000000
+#define HAVE_STRCASECMP
+#endif /* __CRTL_VER >= 70000000 */
+#endif /* def __CRTL_VER */
+
+#ifdef HAVE_STRCASECMP
+#include <strings.h> /* str[n]casecmp() */
+#endif /* def HAVE_STRCASECMP */
+
+#include <dvidef.h>
+#include <lib$routines.h>
+#include <ssdef.h>
+#include <stsdef.h>
+#include <starlet.h>
+
+/* Directory file type with version, and its strlen(). */
+#define DIR_TYPE_VER ".DIR;1"
+#define DIR_TYPE_VER_LEN (sizeof( DIR_TYPE_VER)- 1)
+
+/* Extra malloc() space in names for cutpath(). (May have to change
+ ".FOO]" to "]FOO.DIR;1".)
+*/
+#define DIR_PAD (DIR_TYPE_VER_LEN- 1)
+
+/* Hex digit table. */
+
+char hex_digit[ 16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+/* Character property table for (re-)escaping ODS5 extended file names.
+ Note that this table ignore Unicode, and does not identify invalid
+ characters.
+
+ ODS2 valid characters: 0-9 A-Z a-z $ - _
+
+ ODS5 Invalid characters:
+ C0 control codes (0x00 to 0x1F inclusive)
+ Asterisk (*)
+ Question mark (?)
+
+ ODS5 Invalid characters only in VMS V7.2 (which no one runs, right?):
+ Double quotation marks (")
+ Backslash (\)
+ Colon (:)
+ Left angle bracket (<)
+ Right angle bracket (>)
+ Slash (/)
+ Vertical bar (|)
+
+ Characters escaped by "^":
+ SP ! # % & ' ( ) + , . ; = @ [ ] ^ ` { } ~
+
+ Either "^_" or "^ " is accepted as a space. Period (.) is a special
+ case. Note that un-escaped < and > can also confuse a directory
+ spec.
+
+ Characters put out as ^xx:
+ 7F (DEL)
+ 80-9F (C1 control characters)
+ A0 (nonbreaking space)
+ FF (Latin small letter y diaeresis)
+
+ Other cases:
+ Unicode: "^Uxxxx", where "xxxx" is four hex digits.
+
+ Property table values:
+ Normal escape: 1
+ Space: 2
+ Dot: 4
+ Hex-hex escape: 8
+ -------------------
+ Hex digit: 64
+*/
+
+unsigned char char_prop[ 256] = {
+
+/* NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* SP ! " # $ % & ' ( ) * + , - . / */
+ 2, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 4, 0,
+
+/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, 1, 1, 1, 1,
+
+/* @ A B C D E F G H I J K L M N O */
+ 1, 64, 64, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* P Q R S T U V W X Y Z [ \ ] ^ _ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
+
+/* ` a b c d e f g h i j k l m n o */
+ 1, 64, 64, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+/* p q r s t u v w x y z { | } ~ DEL */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 8,
+
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8
+};
+
+/* The C RTL from OpenVMS 7.0 and newer supplies POSIX compatible versions of
+ * opendir() et al. Thus, we have to use other names in our private code for
+ * directory scanning to prevent symbol name conflicts at link time.
+ * For now, we do not use the library supplied "dirent.h" functions, since
+ * our private implementation provides some functionality which may not be
+ * present in the library versions. For example:
+ * ==> zopendir("DISK:[DIR.SUB1]SUB2.DIR") scans "DISK:[DIR.SUB1.SUB2]".
+ */
+
+typedef struct zdirent {
+ int d_wild; /* flag for wildcard vs. non-wild */
+ struct FAB fab;
+ struct NAM_STRUCT nam;
+ char d_qualwildname[ NAM_MAXRSS+ 1];
+ char d_name[ NAM_MAXRSS+ 1];
+} zDIR;
+
+extern char *label;
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+local int relative_dir_s = 0; /* Relative directory spec. */
+
+/* Local functions */
+local void vms_wild OF((char *, zDIR *));
+local zDIR *zopendir OF((ZCONST char *));
+local char *readd OF((zDIR *));
+local char *strlower OF((char *));
+local char *strupper OF((char *));
+
+/* 2004-09-25 SMS.
+ str[n]casecmp() replacement for old C RTL.
+ Assumes a prehistorically incompetent toupper().
+*/
+#ifndef HAVE_STRCASECMP
+
+int strncasecmp( char *s1, char *s2, size_t n)
+{
+ /* Initialization prepares for n == 0. */
+ char c1 = '\0';
+ char c2 = '\0';
+
+ while (n-- > 0)
+ {
+ /* Set c1 and c2. Convert lower-case characters to upper-case. */
+ if (islower( c1 = *s1))
+ c1 = toupper( c1);
+
+ if (islower( c2 = *s2))
+ c2 = toupper( c2);
+
+ /* Quit at inequality or NUL. */
+ if ((c1 != c2) || (c1 == '\0'))
+ break;
+
+ s1++;
+ s2++;
+ }
+return ((unsigned int) c1- (unsigned int) c2);
+}
+
+#ifndef UINT_MAX
+#define UINT_MAX 4294967295U
+#endif
+
+#define strcasecmp( s1, s2) strncasecmp( s1, s2, UINT_MAX)
+
+#endif /* ndef HAVE_STRCASECMP */
+
+
+/* 2004-09-27 SMS.
+ eat_carets().
+
+ Delete ODS5 extended file name escape characters ("^") in the
+ original buffer.
+ Note that the current scheme does not handle all EFN cases, but it
+ could be made more complicated.
+*/
+
+local void eat_carets( char *str)
+/* char *str; Source pointer. */
+{
+ char *strd; /* Destination pointer. */
+ char hdgt;
+ unsigned char uchr;
+ unsigned char prop;
+
+ /* Skip ahead to the first "^", if any. */
+ while ((*str != '\0') && (*str != '^'))
+ str++;
+
+ /* If no caret was found, quit early. */
+ if (*str != '\0')
+ {
+ /* Shift characters leftward as carets are found. */
+ strd = str;
+ while (*str != '\0')
+ {
+ uchr = *str;
+ if (uchr == '^')
+ {
+ /* Found a caret. Skip it, and check the next character. */
+ uchr = *(++str);
+ prop = char_prop[ uchr];
+ if (prop& 64)
+ {
+ /* Hex digit. Get char code from this and next hex digit. */
+ if (uchr <= '9')
+ {
+ hdgt = uchr- '0'; /* '0' - '9' -> 0 - 9. */
+ }
+ else
+ {
+ hdgt = ((uchr- 'A')& 7)+ 10; /* [Aa] - [Ff] -> 10 - 15. */
+ }
+ hdgt <<= 4; /* X16. */
+ uchr = *(++str); /* Next char must be hex digit. */
+ if (uchr <= '9')
+ {
+ uchr = hdgt+ uchr- '0';
+ }
+ else
+ {
+ uchr = hdgt+ ((uchr- 'A')& 15)+ 10;
+ }
+ }
+ else if (uchr == '_')
+ {
+ /* Convert escaped "_" to " ". */
+ uchr = ' ';
+ }
+ else if (uchr == '/')
+ {
+ /* Convert escaped "/" (invalid Zip) to "?" (invalid VMS). */
+ uchr = '?';
+ }
+ /* Else, not a hex digit. Must be a simple escaped character
+ (or Unicode, which is not yet handled here).
+ */
+ }
+ /* Else, not a caret. Use as-is. */
+ *strd = uchr;
+
+ /* Advance destination and source pointers. */
+ strd++;
+ str++;
+ }
+ /* Terminate the destination string. */
+ *strd = '\0';
+ }
+}
+
+
+/* 2007-05-22 SMS.
+ * explicit_dev().
+ *
+ * Determine if an explicit device name is present in a (VMS) file
+ * specification.
+ */
+local int explicit_dev( char *file_spec)
+{
+ int sts;
+ struct FAB fab; /* FAB. */
+ struct NAM_STRUCT nam; /* NAM[L]. */
+
+ /* Initialize the FAB and NAM[L], and link the NAM[L] to the FAB. */
+ nam = CC_RMS_NAM;
+ fab = cc$rms_fab;
+ fab.FAB_NAM = &nam;
+
+ /* Point the FAB/NAM[L] fields to the actual name and default name. */
+
+#ifdef NAML$C_MAXRSS
+
+ fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
+ fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ /* File name. */
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = file_spec;
+ FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen( file_spec);
+
+ nam.NAM_NOP = NAM_M_SYNCHK; /* Syntax-only analysis. */
+ sts = sys$parse( &fab, 0, 0); /* Parse the file spec. */
+
+ /* Device found = $PARSE success and "device was explicit" flag. */
+ return (((sts& STS$M_SEVERITY) == STS$M_SUCCESS) &&
+ ((nam.NAM_FNB& NAM_M_EXP_DEV) != 0));
+}
+
+
+/* 2005-02-04 SMS.
+ find_dir().
+
+ Find directory boundaries in an ODS2 or ODS5 file spec.
+ Returns length (zero if no directory, negative if error),
+ and sets "start" argument to first character (typically "[") location.
+
+ No one will care about the details, but the return values are:
+
+ 0 No dir.
+ -2 [, no end. -3 <, no end.
+ -4 [, multiple start. -5 <, multiple start.
+ -8 ], no start. -9 >, no start.
+ -16 ], wrong end. -17 >, wrong end.
+ -32 ], multiple end. -33 >, multiple end.
+
+ Note that the current scheme handles only simple EFN cases, but it
+ could be made more complicated.
+*/
+int find_dir( char *file_spec, char **start)
+{
+ char *cp;
+ char chr;
+
+ char *end_tmp = NULL;
+ char *start_tmp = NULL;
+ int lenth = 0;
+
+ for (cp = file_spec; cp < file_spec+ strlen( file_spec); cp++)
+ {
+ chr = *cp;
+ if (chr == '^')
+ {
+ /* Skip ODS5 extended name escaped characters. */
+ cp++;
+ /* If escaped char is a hex digit, skip the second hex digit, too. */
+ if (char_prop[ (unsigned char) *cp]& 64)
+ cp++;
+ }
+ else if (chr == '[')
+ {
+ /* Found start. */
+ if (start_tmp == NULL)
+ {
+ /* First time. Record start location. */
+ start_tmp = cp;
+ /* Error if no end. */
+ lenth = -2;
+ }
+ else
+ {
+ /* Multiple start characters. */
+ lenth = -4;
+ break;
+ }
+ }
+ else if (chr == '<')
+ {
+ /* Found start. */
+ if (start_tmp == NULL)
+ {
+ /* First time. Record start location. */
+ start_tmp = cp;
+ /* Error if no end. */
+ lenth = -3;
+ }
+ else
+ {
+ /* Multiple start characters. */
+ lenth = -5;
+ break;
+ }
+ }
+ else if (chr == ']')
+ {
+ /* Found end. */
+ if (end_tmp == NULL)
+ {
+ /* First time. */
+ if (lenth == 0)
+ {
+ /* End without start. */
+ lenth = -8;
+ break;
+ }
+ else if (lenth != -2)
+ {
+ /* Wrong kind of end. */
+ lenth = -16;
+ break;
+ }
+ /* End ok. Record end location. */
+ end_tmp = cp;
+ lenth = end_tmp+ 1- start_tmp;
+ /* Could break here, ignoring excessive end characters. */
+ }
+ else
+ {
+ /* Multiple end characters. */
+ lenth = -32;
+ break;
+ }
+ }
+ else if (chr == '>')
+ {
+ /* Found end. */
+ if (end_tmp == NULL)
+ {
+ /* First time. */
+ if (lenth == 0)
+ {
+ /* End without start. */
+ lenth = -9;
+ break;
+ }
+ else if (lenth != -3)
+ {
+ /* Wrong kind of end. */
+ lenth = -17;
+ break;
+ }
+ /* End ok. Record end location. */
+ end_tmp = cp;
+ lenth = end_tmp+ 1- start_tmp;
+ /* Could break here, ignoring excessive end characters. */
+ }
+ else
+ {
+ /* Multiple end characters. */
+ lenth = -33;
+ break;
+ }
+ }
+ }
+
+ /* If both start and end were found,
+ then set result pointer where safe.
+ */
+ if (lenth > 0)
+ {
+ if (start != NULL)
+ {
+ *start = start_tmp;
+ }
+ }
+ return lenth;
+}
+
+
+/* 2005-02-08 SMS.
+ file_sys_type().
+
+ Determine the file system type for the (VMS) path name argument.
+*/
+local int file_sys_type( char *path)
+{
+ int acp_code;
+
+#ifdef DVI$C_ACP_F11V5
+
+/* Should know about ODS5 file system. Do actual check.
+ (This should be non-VAX with __CRTL_VER >= 70200000.)
+*/
+
+ int sts;
+
+ struct dsc$descriptor_s dev_descr =
+ { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0 };
+
+ /* Load path argument into device descriptor. */
+ dev_descr.dsc$a_pointer = path;
+ dev_descr.dsc$w_length = strlen( dev_descr.dsc$a_pointer);
+
+ /* Get filesystem type code.
+ (Text results for this item code have been unreliable.)
+ */
+ sts = lib$getdvi( &((int) DVI$_ACPTYPE), 0, &dev_descr, &acp_code, 0, 0);
+
+ if ((sts & STS$M_SUCCESS) != STS$K_SUCCESS)
+ {
+ acp_code = -1;
+ }
+
+#else /* def DVI$C_ACP_F11V5 */
+
+/* Too old for ODS5 file system. Must be ODS2. */
+
+ acp_code = DVI$C_ACP_F11V2;
+
+#endif /* def DVI$C_ACP_F11V5 */
+
+ return acp_code;
+}
+
+/*---------------------------------------------------------------------------
+
+ _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
+ fwild() and fnext() routines (originally written by Martin Minow, poss-
+ ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
+ Roelofs and are still in the public domain. Routines approximate the
+ behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
+
+ 2005-01-04 SMS.
+ Changed to use NAML instead of NAM, where available.
+
+ ---------------------------------------------------------------------------*/
+
+static char wild_version_part[10]="\0";
+
+local void vms_wild( char *p, zDIR *d)
+{
+ /*
+ * Do wildcard setup.
+ */
+ /* Set up the FAB and NAM[L] blocks. */
+ d->fab = cc$rms_fab; /* Initialize FAB. */
+ d->nam = CC_RMS_NAM; /* Initialize NAM[L]. */
+
+ d->fab.FAB_NAM = &d->nam; /* FAB -> NAM[L] */
+
+#ifdef NAML$C_MAXRSS
+
+ d->fab.fab$l_dna =(char *) -1; /* Using NAML for default name. */
+ d->fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
+
+#endif /* def NAML$C_MAXRSS */
+
+ /* Argument file name and length. */
+ d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = p;
+ d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = strlen(p);
+
+#define DEF_DEVDIR "SYS$DISK:[]"
+
+ /* Default file spec and length. */
+ d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNA = DEF_DEVDIR;
+ d->FAB_OR_NAML( fab, nam).FAB_OR_NAML_DNS = sizeof( DEF_DEVDIR)- 1;
+
+ d->nam.NAM_ESA = d->d_qualwildname; /* qualified wild name */
+ d->nam.NAM_ESS = NAM_MAXRSS; /* max length */
+ d->nam.NAM_RSA = d->d_name; /* matching file name */
+ d->nam.NAM_RSS = NAM_MAXRSS; /* max length */
+
+ /* parse the file name */
+ if (sys$parse(&d->fab) != RMS$_NORMAL)
+ return;
+ /* Does this replace d->fab.fab$l_fna with a new string in its own space?
+ I sure hope so, since p is free'ed before this routine returns. */
+
+ /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
+ * and set wild-flag */
+ d->d_qualwildname[d->nam.NAM_ESL] = '\0';
+ d->d_wild = (d->nam.NAM_FNB & NAM$M_WILDCARD)? 1 : 0; /* not used... */
+#ifdef DEBUG
+ fprintf(mesg, " incoming wildname: %s\n", p);
+ fprintf(mesg, " qualified wildname: %s\n", d->d_qualwildname);
+#endif /* DEBUG */
+}
+
+local zDIR *zopendir( ZCONST char *n)
+/* ZCONST char *n; directory to open */
+/* Start searching for files in the VMS directory n */
+{
+ char *c; /* scans VMS path */
+ zDIR *d; /* malloc'd return value */
+ int m; /* length of name */
+ char *p; /* malloc'd temporary string */
+
+ if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL ||
+ (p = malloc((m = strlen(n)) + 4)) == NULL) {
+ if (d != NULL) free((zvoid *)d);
+ return NULL;
+ }
+ /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
+ If latter, convert to former.
+ 2005-01-31 SMS. Changed to require ";1", as VMS does, which
+ simplified the code slightly, too. Note that ODS5 allows ".DIR" in
+ any case (upper, lower, mixed).
+ */
+ if ((m > 0) && (*(c = strcpy(p,n)+m-1) != ']'))
+ {
+ if ((c- p < DIR_TYPE_VER_LEN) ||
+ strcasecmp((c+ 1- DIR_TYPE_VER_LEN), DIR_TYPE_VER))
+ {
+ free((zvoid *)d); free((zvoid *)p);
+ return NULL;
+ }
+ c -= 4; /* The "D". */
+ *c-- = '\0'; /* terminate at "DIR;1" */
+ *c = ']'; /* "." --> "]" */
+
+ /* Replace the formerly last "]" with ".".
+ For ODS5, ignore "^]".
+ */
+ while ((c > p) && ((*--c != ']') || (*(c- 1) == '^')))
+ ;
+ *c = '.'; /* "]" --> "." */
+ }
+ strcat(p, "*.*");
+ strcat(p, wild_version_part);
+ vms_wild(p, d); /* set up wildcard */
+ free((zvoid *)p);
+ return d;
+}
+
+local char *readd( zDIR *d)
+/* zDIR *d; directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ int r; /* return code */
+
+ do {
+ d->fab.fab$w_ifi = 0; /* internal file index: what does this do? */
+/*
+ 2005-02-04 SMS.
+
+ From the docs:
+
+ Note that you must close the file before invoking the Search
+ service (FAB$W_IFI must be 0).
+
+ The same is true for PARSE. Most likely, it's cleared by setting
+ "fab = cc$rms_fab", and left that way, so clearing it here may very
+ well be pointless. (I think it is, and I've never seen it explicitly
+ cleared elsewhere, but I haven't tested it everywhere either.)
+*/
+ /* get next match to possible wildcard */
+ if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
+ {
+ d->d_name[d->nam.NAM_RSL] = '\0'; /* null terminate */
+ return (char *)d->d_name; /* OK */
+ }
+ } while (r == RMS$_PRV);
+ return NULL;
+}
+
+
+int wild( char *p)
+/* char *p; path/pattern to match */
+/* Expand the pattern based on the contents of the file system.
+ Return an error code in the ZE_ class.
+ Note that any command-line file argument may need wildcard expansion,
+ so all user-specified constituent file names pass through here.
+*/
+{
+ zDIR *d; /* stream for reading directory */
+ char *e; /* name found in directory */
+ int f; /* true if there was a match */
+
+ int dir_len; /* Length of the directory part of the name. */
+ char *dir_start; /* First character of the directory part. */
+
+ /* special handling of stdin request */
+ if (strcmp(p, "-") == 0) /* if compressing stdin */
+ return newname(p, 0, 0);
+
+ /* Determine whether this name has an absolute or relative directory
+ spec. It's relative if there is no directory, or if the directory
+ has a leading dot ("[.").
+ */
+ dir_len = find_dir( p, &dir_start);
+ relative_dir_s = ((dir_len <= 0)? 1 : (dir_start[ 1] == '.'));
+
+ /* Search given pattern for matching names */
+ if ((d = (zDIR *)malloc(sizeof(zDIR))) == NULL)
+ return ZE_MEM;
+ vms_wild(p, d); /* pattern may be more than just directory name */
+
+ /*
+ * Save version specified by user to use in recursive drops into
+ * subdirectories.
+ */
+ strncpy(wild_version_part, d->nam.NAM_L_VER, d->nam.NAM_B_VER);
+ wild_version_part[d->nam.NAM_B_VER] = '\0';
+
+ f = 0;
+ while ((e = readd(d)) != NULL) /* "dosmatch" is already built in */
+ if (procname(e, 0) == ZE_OK)
+ f = 1;
+ free(d);
+
+ /* Done */
+ return f ? ZE_OK : ZE_MISS;
+}
+
+int procname( char *n, int caseflag)
+/* char *n; name to process */
+/* int caseflag; true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ zDIR *d; /* directory stream from zopendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s)
+#if defined(__TURBOC__) || defined(VMS) || defined(__WATCOMC__)
+ /* For these 3 compilers, stat() succeeds on wild card names! */
+ || isshexp(n)
+#endif
+ )
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ if (caseflag) {
+ p = malloc(strlen(n) + 1);
+ if (p != NULL)
+ strcpy(p, n);
+ } else
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ if (dirnames && (m = newname(n, 1, caseflag)) != ZE_OK) {
+ return m;
+ }
+ /* recurse into directory */
+ if (recurse && (d = zopendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if ((m = procname(e, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ free(d);
+ return m;
+ }
+ }
+ free(d);
+ }
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+/* 2004-09-24 SMS.
+ Cuter strlower() and strupper() functions.
+*/
+
+local char *strlower( char *s)
+/* Convert all uppercase letters to lowercase in string s */
+{
+ for ( ; *s != '\0'; s++)
+ if (isupper( *s))
+ *s = tolower( *s);
+
+ return s;
+}
+
+local char *strupper( char *s)
+/* Convert all lowercase letters to uppercase in string s */
+{
+ for ( ; *s != '\0'; s++)
+ if (islower( *s))
+ *s = toupper( *s);
+
+ return s;
+}
+
+char *ex2in( char *x, int isdir, int *pdosflag)
+/* char *x; external file name */
+/* int isdir; input: x is a directory */
+/* int *pdosflag; output: force MSDOS file attributes? */
+
+/* Convert the external file name to a zip file name, returning the
+ malloc'ed string or NULL if not enough memory.
+
+ 2005-02-09 SMS.
+ Added some ODS5 support.
+
+ Note that if we were really clever, we'd save the truncated original
+ file name for later use as "iname", instead of running the de-escaped
+ product back through in2ex() to recover it later.
+
+ 2005-11-13 SMS.
+ Changed to translate "[..." into enough "/" characters to cause
+ in2ex() to reconstruct it. This should not be needed, however, as
+ pattern matching really should avoid ex2in() and in2ex().
+*/
+{
+ char *n; /* Internal file name (malloc'ed). */
+ char *nn; /* Temporary "n"-like pointer. */
+ char *ext_dir_and_name; /* External dir]name (less "dev:["). */
+ char chr; /* Temporary character storage. */
+ int dosflag;
+ int down_case; /* Resultant down-case flag. */
+ int dir_len; /* Directory spec length. */
+ int ods_level; /* File system type. */
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Locate the directory part of the external name. */
+ dir_len = find_dir( x, &ext_dir_and_name);
+ if (dir_len <= 0)
+ {
+ /* Directory not found. Use whole external name. */
+ ext_dir_and_name = x;
+ }
+ else if (pathput)
+ {
+ /* Include directory. */
+ if (ext_dir_and_name[ 1] == '.')
+ {
+ /* Relative path. If not a directory-depth wildcard, then drop
+ first "[." (or "<."). If "[..." (or "<..."), then preserve all
+ characters, including the first "[" (or "<") for special
+ handling below.
+ */
+ if ((ext_dir_and_name[ 2] != '.') || (ext_dir_and_name[ 3] != '.'))
+ {
+ /* Normal relative path. Drop first "[." (or "<."). */
+ dir_len -= 2;
+ ext_dir_and_name += 2;
+ }
+ }
+ else
+ {
+ /* Absolute path. Skip first "[" (or "<"). */
+ dir_len -= 1;
+ ext_dir_and_name += 1;
+
+ /* 2007-04-26 SMS.
+ Skip past "000000." or "000000]" (or "000000>"), which should
+ not be stored in the archive. This arises, for example, with
+ "zip -r archive [000000]foo.dir"
+ */
+#define MFD "000000"
+
+ if ((strncmp( ext_dir_and_name, MFD, strlen( MFD)) == 0) &&
+ ((ext_dir_and_name[ 6] == '.') ||
+ (ext_dir_and_name[ 6] == ']') ||
+ (ext_dir_and_name[ 6] == '>')))
+ {
+ dir_len -= 7;
+ ext_dir_and_name += 7;
+ }
+ }
+ }
+ else
+ {
+ /* Junking paths. Skip the whole directory spec. */
+ ext_dir_and_name += dir_len;
+ dir_len = 0;
+ }
+
+ /* Malloc space for internal name and copy it. */
+ if ((n = malloc(strlen( ext_dir_and_name)+ 1)) == NULL)
+ return NULL;
+ strcpy( n, ext_dir_and_name);
+
+ /* Convert VMS directory separators (".") to "/". */
+ if (dir_len > 0)
+ {
+ for (nn = n; nn < n+ dir_len; nn++)
+ {
+ chr = *nn;
+ if (chr == '^')
+ {
+ /* Skip ODS5 extended name escaped characters. */
+ nn++;
+ /* If escaped char is a hex digit, skip the second hex digit, too. */
+ if (char_prop[ (unsigned char) *nn]& 64)
+ nn++;
+ }
+ else if ((chr == '.') || ((nn == n) && ((chr == '[') || (chr == '<'))))
+ {
+ /* Convert VMS directory separator (".", or initial "[" or "<"
+ of "[..." or "<...") to "/".
+ */
+ *nn = '/';
+ }
+ }
+ /* Replace directory end character (typically "]") with "/". */
+ n[ dir_len- 1] = '/';
+ }
+
+ /* If relative path, then strip off the current directory. */
+ if (relative_dir_s)
+ {
+ char cwd[ NAM_MAXRSS+ 1];
+ char *cwd_dir_only;
+ char *q;
+ int cwd_dir_only_len;
+
+ q = getcwd( cwd, (sizeof( cwd)- 1));
+
+ /* 2004-09-24 SMS.
+ With SET PROCESSS /PARSE = EXTENDED, getcwd() can return a
+ mixed-case result, confounding the comparisons below with an
+ all-uppercase name in "n". Always use a case-insensitive
+ comparison around here.
+ */
+
+ /* Locate the directory part of the external name. */
+ dir_len = find_dir( q, &cwd_dir_only);
+ if (dir_len > 0)
+ {
+ /* Skip first "[" (or "<"). */
+ cwd_dir_only++;
+ /* Convert VMS directory separators (".") to "/". */
+ for (q = cwd_dir_only; q < cwd_dir_only+ dir_len; q++)
+ {
+ chr = *q;
+ if (chr == '^')
+ {
+ /* Skip ODS5 extended name escaped characters. */
+ q++;
+ /* If escaped char is a hex digit, skip the second hex digit, too. */
+ if (char_prop[ (unsigned char) *q]& 64)
+ q++;
+ }
+ else if (chr == '.')
+ {
+ /* Convert VMS directory separator (".") to "/". */
+ *q = '/';
+ }
+ }
+ /* Replace directory end character (typically "]") with "/". */
+ cwd_dir_only[ dir_len- 2] = '/';
+ }
+
+ /* If the slash-converted cwd matches the front of the internal
+ name, then shuffle the remainder of the internal name to the
+ beginning of the internal name storage.
+
+ Because we already know that the path is relative, this test may
+ always succeed.
+ */
+ cwd_dir_only_len = strlen( cwd_dir_only);
+ if (strncasecmp( n, cwd_dir_only, cwd_dir_only_len) == 0)
+ {
+ nn = n+ cwd_dir_only_len;
+ q = n;
+ while (*q++ = *nn++);
+ }
+ } /* (relative_dir_s) */
+
+ /* 2007-05-22 SMS.
+ * If a device name is present, assume that it's a real (VMS) file
+ * specification, and do down-casing according to the ODS2 or ODS5
+ * down-casing policy. If no device name is present, assume that it's
+ * a pattern ("-i", ...), and do no down-casing here. (Case
+ * sensitivity in patterns is handled elsewhere.)
+ */
+ if (explicit_dev( x))
+ {
+ /* If ODS5 is possible, do complicated down-case check.
+
+ Note that the test for ODS2/ODS5 is misleading and over-broad.
+ Here, "ODS2" includes anything from DVI$C_ACP_F11V1 (=1, ODS1) up
+ to (but not including) DVI$C_ACP_F11V5 (= 11, DVI$C_ACP_F11V5),
+ while "ODS5" includes anything from DVI$C_ACP_F11V5 on up. See
+ DVIDEF.H.
+ */
+
+#if defined( DVI$C_ACP_F11V5) && defined( NAML$C_MAXRSS)
+
+ /* Check options and/or ODS level for down-case or preserve case. */
+ down_case = 0; /* Assume preserve case. */
+ if ((vms_case_2 <= 0) && (vms_case_5 < 0))
+ {
+ /* Always down-case. */
+ down_case = 1;
+ }
+ else if ((vms_case_2 <= 0) || (vms_case_5 < 0))
+ {
+ /* Down-case depending on ODS level. (Use (full) external name.) */
+ ods_level = file_sys_type( x);
+
+ if (ods_level > 0)
+ {
+ /* Valid ODS level. (Name (full) contains device.)
+ * Down-case accordingly.
+ */
+ if (((ods_level < DVI$C_ACP_F11V5) && (vms_case_2 <= 0)) ||
+ ((ods_level >= DVI$C_ACP_F11V5) && (vms_case_5 < 0)))
+ {
+ /* Down-case for this ODS level. */
+ down_case = 1;
+ }
+ }
+ }
+
+#else /* defined( DVI$C_ACP_F11V5) && defined( NAML$C_MAXRSS) */
+
+/* No case-preserved names are possible (VAX). Do simple down-case check. */
+
+ down_case = (vms_case_2 <= 0);
+
+#endif /* defined( DVI$C_ACP_F11V5) && defined( NAML$C_MAXRSS) [else] */
+
+ /* If down-casing, convert to lower case. */
+ if (down_case != 0)
+ {
+ strlower( n);
+ }
+ }
+
+ /* Remove simple ODS5 extended file name escape characters. */
+ eat_carets( n);
+
+ if (isdir)
+ {
+ if (strcasecmp( (nn = n+ strlen( n)- DIR_TYPE_VER_LEN), DIR_TYPE_VER))
+ error("directory not version 1");
+ else
+ if (pathput)
+ strcpy( nn, "/");
+ else
+ *n = '\0'; /* directories are discarded with zip -rj */
+ }
+ else if (vmsver == 0)
+ {
+ /* If not keeping version numbers, truncate the name at the ";".
+ (No escaped characters are expected in the version.)
+ */
+ if ((ext_dir_and_name = strrchr( n, ';')) != NULL)
+ *ext_dir_and_name = '\0';
+ }
+ else if (vmsver > 1)
+ {
+ /* Keeping version numbers, but as ".nnn", not ";nnn". */
+ if ((ext_dir_and_name = strrchr( n, ';')) != NULL)
+ *ext_dir_and_name = '.';
+ }
+
+ /* Remove a type-less dot. */
+ /* (Note that currently "name..ver" is not altered.) */
+ if ((ext_dir_and_name = strrchr( n, '.')) != NULL)
+ {
+ if (ext_dir_and_name[ 1] == '\0') /* "name." -> "name" */
+ *ext_dir_and_name = '\0';
+ else if (ext_dir_and_name[ 1] == ';') /* "name.;ver" -> "name;ver" */
+ {
+ char *f = ext_dir_and_name+ 1;
+ while (*ext_dir_and_name++ = *f++);
+ }
+ }
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+
+ return n;
+}
+
+
+char *in2ex( char *n)
+/* char *n; internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+ char *t; /* scans name */
+ int i;
+ char chr;
+ char *endp;
+ char *last_slash;
+ char *versionp;
+
+#ifdef NAML$C_MAXRSS
+
+ char buf[ NAML$C_MAXRSS+ 1];
+ unsigned char prop;
+ unsigned char uchr;
+ char *last_dot;
+
+#endif /* def NAML$C_MAXRSS */
+
+ /* Locate the last slash. */
+ last_slash = strrchr( n, '/');
+
+/* If ODS5 is possible, replace escape carets in name. */
+
+#ifdef NAML$C_MAXRSS
+
+ endp = n+ strlen( n);
+
+ /* Locate the version delimiter, if one is expected. */
+ if (vmsver == 0)
+ { /* No version expected. */
+ versionp = endp;
+ }
+ else
+ {
+ if (vmsver > 1)
+ { /* Expect a dot-version, ".nnn". Locate the version ".".
+ Temporarily terminate at this dot to allow the last-dot search
+ below to find the last non-version dot.
+ */
+ versionp = strrchr( n, '.');
+ if (versionp != NULL) /* Can't miss. */
+ {
+ *versionp = '\0';
+ }
+ }
+ else
+ { /* Expect a semi-colon-version, ";nnn". Locate the ";". */
+ versionp = strrchr( n, ';');
+ }
+ if ((versionp == NULL) || (versionp < last_slash))
+ { /* If confused, and the version delimiter was not in the name,
+ then ignore it.
+ */
+ versionp = endp;
+ }
+ }
+
+ /* No escape needed for the last dot, if it's part of the file name.
+ All dots in a directory must be escaped.
+ */
+ last_dot = strrchr( n, '.');
+
+ if ((last_dot != NULL) && (last_slash != NULL) && (last_dot < last_slash))
+ {
+ last_dot = last_slash;
+ }
+
+ /* Replace the version dot if necessary. */
+ if ((vmsver > 1) && (versionp != NULL) && (versionp < endp))
+ {
+ *versionp = '.';
+ }
+
+ /* Add ODS5 escape sequences. Leave "/" and "?" for later.
+ The name here looks (roughly) like: dir1/dir2/a.b
+ */
+ t = n;
+ x = buf;
+ while (uchr = *t++)
+ {
+ /* Characters in the version do not need escaping. */
+ if (t <= versionp)
+ {
+ prop = char_prop[ uchr]& 31;
+ if (prop)
+ {
+ if (prop& 4)
+ { /* Dot. */
+ if (t < last_dot)
+ {
+ /* Dot which must be escaped. */
+ *x++ = '^';
+ }
+ }
+ else if (prop& 8)
+ {
+ /* Character needing hex-hex escape. */
+ *x++ = '^';
+ *x++ = hex_digit[ uchr>> 4];
+ uchr = hex_digit[ uchr& 15];
+ }
+ else
+ {
+ /* Non-dot character which must be escaped (and simple works).
+ "?" gains the caret but remains "?" until later.
+ ("/" remains (unescaped) "/".)
+ */
+ *x++ = '^';
+ if (prop& 2)
+ {
+ /* Escaped space (represented as "^_"). */
+ uchr = '_';
+ }
+ }
+ }
+ }
+ *x++ = uchr;
+ }
+ *x = '\0';
+
+ /* Point "n" to altered name buffer, and re-find the last slash. */
+ n = buf;
+ last_slash = strrchr( n, '/');
+
+#endif /* def NAML$C_MAXRSS */
+
+ if ((t = last_slash) == NULL)
+ {
+ if ((x = malloc(strlen(n) + 1 + DIR_PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+ }
+ else
+ {
+ if ((x = malloc(strlen(n) + 3 + DIR_PAD)) == NULL)
+ return NULL;
+
+ /* Begin with "[". */
+ x[ 0] = '[';
+ i = 1;
+ if (*n != '/')
+ {
+ /* Relative path. Add ".". */
+ x[ i++] = '.';
+ }
+ else
+ {
+ /* Absolute path. Skip leading "/". */
+ n++;
+ }
+ strcpy( (x+ i), n);
+
+ /* Place the final ']'. Remember where the name starts. */
+ *(t = x + i + (t - n)) = ']';
+ last_slash = t;
+
+ /* Replace "/" with ".", and "?" with (now escaped) "/", in the
+ directory part of the name.
+ */
+ while (--t > x)
+ {
+ chr = *t;
+ if (chr == '/')
+ {
+ *t = '.';
+ }
+ else if (chr == '?')
+ {
+ *t = '/';
+ }
+ }
+
+ /* Replace "?" with (now escaped) "/", in the non-directory part of
+ the name.
+ */
+ while ((chr = *(++last_slash)) != '\0')
+ {
+ if (chr == '?')
+ {
+ *last_slash = '/';
+ }
+ }
+ }
+
+/* If case preservation is impossible (VAX, say), and down-casing, then
+ up-case. If case preservation is possible and wasn't done, then
+ there's no way to ensure proper restoration of original case, so
+ don't try. This may differ from pre-3.0 behavior.
+*/
+#ifndef NAML$C_MAXRSS
+
+ if (vms_case_2 <= 0)
+ {
+ strupper( x);
+ }
+
+#endif /* ndef NAML$C_MAXRSS */
+
+ return x;
+}
+
+void stamp( char *f, ulg d)
+/* char *f; name of file to change */
+/* ulg d; dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year;
+ char timbuf[24];
+ static ZCONST char *month[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+ "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
+ struct VMStimbuf {
+ char *actime; /* VMS revision date, ASCII format */
+ char *modtime; /* VMS creation date, ASCII format */
+ } ascii_times;
+
+ ascii_times.actime = ascii_times.modtime = timbuf;
+
+ /* Convert DOS time to ASCII format for VMSmunch */
+ tm_sec = (int)(d << 1) & 0x3e;
+ tm_min = (int)(d >> 5) & 0x3f;
+ tm_hour = (int)(d >> 11) & 0x1f;
+ tm_mday = (int)(d >> 16) & 0x1f;
+ tm_mon = ((int)(d >> 21) & 0xf) - 1;
+ tm_year = ((int)(d >> 25) & 0x7f) + 1980;
+ sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", tm_mday, month[tm_mon],
+ tm_year, tm_hour, tm_min, tm_sec);
+
+ /* Set updated and accessed times of f */
+ if (VMSmunch(f, SET_TIMES, (char *)&ascii_times) != RMS$_NMF)
+ zipwarn("can't set zipfile time: ", f);
+}
+
+ulg filetime( char *f, ulg *a, zoff_t *n, iztimes *t)
+/* char *f; name of file to get info on */
+/* ulg *a; return value: file attributes */
+/* zoff_t *n; return value: file size */
+/* iztimes *t; return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert to a malloc string dump FNMAX - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (strcmp(f, "-") == 0) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+ free(name);
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if ((s.st_mode & S_IFDIR) != 0) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1;
+ if (t != NULL) {
+ t->atime = s.st_mtime;
+#ifdef USE_MTIME
+ t->mtime = s.st_mtime; /* Use modification time in VMS */
+#else
+ t->mtime = s.st_ctime; /* Use creation time in VMS */
+#endif
+ t->ctime = s.st_ctime;
+ }
+
+#ifdef USE_MTIME
+ return unix2dostime((time_t *)&s.st_mtime); /* Use modification time in VMS */
+#else
+ return unix2dostime((time_t *)&s.st_ctime); /* Use creation time in VMS */
+#endif
+}
+
+int deletedir( char *d)
+/* char *d; directory to delete */
+
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
+ int r, len;
+ char *s; /* malloc'd string for system command */
+
+ len = strlen(d);
+ if ((s = malloc(len + 34)) == NULL)
+ return 127;
+
+ system(strcat(strcpy(s, "set prot=(o:rwed) "), d));
+ r = delete(d);
+ free(s);
+ return r;
+}
diff --git a/vms/zip.opt b/vms/zip.opt
new file mode 100644
index 0000000..7a4a872
--- /dev/null
+++ b/vms/zip.opt
@@ -0,0 +1 @@
+Ident = "Zip 3.0"
diff --git a/vms/zip_cli.cld b/vms/zip_cli.cld
new file mode 100644
index 0000000..38fc421
--- /dev/null
+++ b/vms/zip_cli.cld
@@ -0,0 +1,168 @@
+ Module ZIP_CLITABLE
+ Ident "03-001"
+
+Define Verb ZIP
+ Parameter P1, Label=ZIPFILE, Prompt="Zip file"
+ Parameter P2, Label=INFILE, VALUE(list), Prompt="Files to Zip"
+ Qualifier DELETE, NonNegatable
+ Qualifier FRESHEN, NonNegatable
+ Qualifier MOVE, NonNegatable
+ Qualifier UPDATE, NonNegatable
+ Qualifier EXCLUDE, NonNegatable, VALUE(required,list)
+ Qualifier INCLUDE, NonNegatable, VALUE(required,list)
+ Qualifier EXLIST, NonNegatable, VALUE(type=$FILE,required)
+ Qualifier INLIST, NonNegatable, VALUE(type=$FILE,required)
+ Qualifier ADJUST_OFFSETS, NonNegatable
+ Qualifier APPEND, NonNegatable
+ Qualifier BATCH, NonNegatable, VALUE(type=$FILE)
+ Qualifier BEFORE, NonNegatable, VALUE(type=$DATETIME)
+ Qualifier COMMENTS, NonNegatable,
+ VALUE(list,type=COMMENTS_KEYWORDS)
+ Qualifier COMPRESSION, NonNegatable, VALUE(type=COMPRESS_OPTS)
+ Qualifier COPY_ENTRIES, NonNegatable
+ Qualifier DESCRIPTORS, NonNegatable
+ Qualifier DIFFERENCE, NonNegatable
+ Qualifier DIRNAMES, Negatable, Default
+ Qualifier DISPLAY, NonNegatable,
+ VALUE(type=DISPLAY_KEYWORDS, required, list)
+ Qualifier DOT_VERSION, NonNegatable
+ Qualifier ENCRYPT, Negatable, VALUE
+ Qualifier EXTRA_FIELDS, Negatable, VALUE(type=EXTRA_OPTS)
+ Qualifier FILESYNC, NonNegatable
+ Qualifier FIX_ARCHIVE, NonNegatable, VALUE(type=FIX_OPTS)
+ Qualifier FULL_PATH, Negatable, Default
+ Qualifier GROW, NonNegatable
+ Qualifier HELP, NonNegatable, VALUE(type=HELP_OPTS)
+ Qualifier JUNK, NonNegatable
+ Qualifier KEEP_VERSION, Negatable
+ Qualifier LATEST, NonNegatable
+ Qualifier LEVEL, VALUE(type=$NUMBER,required)
+ Qualifier LICENSE, NonNegatable
+ Qualifier LOG_FILE, NonNegatable,
+ VALUE(list, required, type=LOG_OPTS)
+ Qualifier MUST_MATCH, NonNegatable
+ Qualifier OUTPUT, VALUE(required,type=$FILE)
+ Qualifier PATTERN_CASE, NonNegatable, VALUE(type=PATT_CASE_OPTS)
+ Qualifier PAUSE, Negatable
+ Qualifier PKZIP, Negatable
+ Qualifier PRESERVE_CASE, Negatable,
+ VALUE(type=PRES_CASE_OPTS, list)
+ Qualifier QUIET, NonNegatable
+ Qualifier RECURSE, Negatable, VALUE(type=RECURSE_OPTS)
+ Qualifier SHOW, NonNegatable,
+ VALUE(type=SHOW_KEYWORDS, required, list)
+ Qualifier SINCE, NonNegatable, VALUE(type=$DATETIME)
+ Qualifier SPLIT, NonNegatable,
+ VALUE(list, required, type=SPLIT_OPTS)
+ Qualifier STORE_TYPES, NonNegatable, VALUE(required,list)
+ Qualifier SYMLINKS, NonNegatable
+ Qualifier TEMP_PATH, VALUE(required,type=$FILE)
+ Qualifier TEST, NonNegatable, VALUE(type=TEST_OPTS)
+ Qualifier TRANSLATE_EOL, NonNegatable,
+ VALUE(type=EOL_KEYWORDS)
+ Qualifier UNSFX, NonNegatable
+ Qualifier VERBOSE, NonNegatable,
+ VALUE(type=VERBOSE_OPTS, list)
+ Qualifier VMS, NonNegatable, VALUE(type=VMS_OPTS)
+ Qualifier WILDCARD, VALUE(type=WILDCARD_OPTS)
+ Qualifier YYZ_ZIP, NonNegatable, Default
+ Qualifier ZIP64, NonNegatable
+
+ Disallow COPY_ENTRIES and (DELETE or FRESHEN or UPDATE)
+ Disallow DELETE and (COPY_ENTRIES or FRESHEN or UPDATE)
+ Disallow FRESHEN and (COPY_ENTRIES or DELETE or UPDATE)
+ Disallow UPDATE and (COPY_ENTRIES or DELETE or FRESHEN)
+ Disallow DIFFERENCE and (neg OUTPUT)
+ Disallow DIFFERENCE and
+ (FIX_ARCHIVE.NORMAL or FIX_ARCHIVE.FULL or
+ COPY_ENTRIES or DELETE)
+ Disallow APPEND and GROW
+ Disallow FIX_ARCHIVE.NORMAL and FIX_ARCHIVE.FULL
+ Disallow (FIX_ARCHIVE.NORMAL or FIX_ARCHIVE.FULL) and
+ (neg OUTPUT)
+ Disallow TRANSLATE_EOL.LF and TRANSLATE_EOL.CRLF
+ Disallow FULL_PATH and JUNK
+ Disallow RECURSE.PATH and RECURSE.FILENAMES
+ Disallow (neg EXTRA_FIELDS) and
+ (KEEP_EXISTING or EXTRA_FIELDS.NORMAL)
+
+Define Type PATT_CASE_OPTS
+ Keyword BLIND
+ Keyword SENSITIVE, DEFAULT
+
+Define Type COMMENTS_KEYWORDS
+ Keyword ARCHIVE, DEFAULT
+ Keyword FILES
+ Keyword ZIP_FILE
+
+Define Type COMPRESS_OPTS
+ Keyword BZIP2
+ Keyword DEFLATE, DEFAULT
+ Keyword STORE
+
+Define Type DISPLAY_KEYWORDS
+ Keyword BYTES
+ Keyword COUNTS
+ Keyword DOTS, VALUE
+ Keyword GLOBALDOTS
+ Keyword USIZE
+ Keyword VOLUME
+
+Define Type EOL_KEYWORDS
+ Keyword LF, DEFAULT
+ Keyword CRLF
+
+Define Type EXTRA_OPTS
+ Keyword NORMAL, DEFAULT
+ Keyword KEEP_EXISTING
+
+Define Type FIX_OPTS
+ Keyword NORMAL, DEFAULT
+ Keyword FULL
+
+Define Type HELP_OPTS
+ Keyword NORMAL, DEFAULT
+ Keyword EXTENDED
+
+Define Type LOG_OPTS
+ Keyword APPEND, Negatable
+ Keyword INFORMATIONAL, Negatable
+ Keyword FILE, NonNegatable, VALUE(required, type=$FILE)
+
+Define Type PRES_CASE_OPTS
+ Keyword NOODS2
+ Keyword NOODS5
+ Keyword ODS2
+ Keyword ODS5
+
+Define Type RECURSE_OPTS
+ Keyword PATH, DEFAULT
+ Keyword FILENAMES
+
+Define Type SHOW_KEYWORDS
+ Keyword COMMAND
+ Keyword DEBUG
+ Keyword FILES
+ Keyword OPTIONS
+
+Define Type SPLIT_OPTS
+ Keyword BELL, Negatable
+ Keyword PAUSE, Negatable
+ Keyword SIZE, VALUE(required)
+ Keyword VERBOSE, Negatable
+
+Define Type TEST_OPTS
+ Keyword UNZIP, VALUE(required)
+
+Define Type VERBOSE_OPTS
+ Keyword NORMAL, DEFAULT
+ Keyword MORE
+ Keyword DEBUG
+ Keyword COMMAND
+
+Define Type VMS_OPTS
+ Keyword ALL
+
+Define Type WILDCARD_OPTS
+ Keyword NOSPAN
+
diff --git a/vms/zip_cli.help b/vms/zip_cli.help
new file mode 100644
index 0000000..1bb39c2
--- /dev/null
+++ b/vms/zip_cli.help
@@ -0,0 +1,1636 @@
+.!
+.! File: ZIP_CLI.HELP
+.!
+.! Author: Christian Spieler
+.!
+.! Date: 05 Dec 95 (orig. ZIP.RNH, 22 Oct 91)
+.!
+.! Description:
+.!
+.! TPU-processable source file to produce VMS on-line help for
+.! portable Zip. Adapted from ZIP.RNH, originally based on
+.! ZIP.MAN (now MANUAL).
+.!
+.! To build:
+.! $ EDIT /TPU/NOSECTION/NODISPLAY/COMMAND=CVTHELP.TPU ZIP_CLI.HELP
+.! $ RUNOFF /OUT=ZIP_CLI.HLP ZIP_CLI.RNH
+.! $ LIBR /HELP/INSERT libr ZIP_CLI
+.!
+.! Modification history:
+.!
+.! 01-001 Christian Spieler 05-DEC-1995 02:02
+.! Genesis.
+.! 01-002 Christian Spieler 20-JAN-1996 03:09
+.! Modified /LICENSE and /VERBOSE descriptions.
+.! 01-003 Christian Spieler 11-FEB-1996 23:09
+.! Added /[NO]EXTRA_FIELDS description.
+.! 01-004 Christian Spieler 11-MAR-1996 20:08
+.! Removed /ENCRYPT=VERIFY option.
+.! 01-005 Christian Spieler 11-MAY-1996 23:08
+.! Corrected/enhanced info about how to get help on UNIX options.
+.! 01-006 Christian Spieler 21-JUL-1997 22:26
+.! Updated for new options of Zip 2.2.
+.! 01-006 Christian Spieler 14-OCT-1997 22:04
+.! Cleanups for Zip 2.2 release (no version change).
+.! 01-007 Steven Schweda 15-MAY-2007
+.! Zip 3.0.
+.! 01-007 Ed Gordon 15-MAY-2007
+.! Minor updates to Zip 3.0 help.
+.!
+<INIT>
+<MAIN>
+ZIP
+
+Zip is a compression and file packaging utility for several operating
+systems, including UNIX, VMS, MSDOS, OS/2, Windows 9x/NT/XP, Minix,
+Atari, Macintosh, Amiga, and Acorn RISC OS. It is analogous to a
+combination of tar and compress and is compatible with PKZIP (Phil
+Katz's ZIP) for MSDOS systems.
+
+Zip is useful for packaging a set of files for distribution, for
+archiving files, and for saving disk space by temporarily compressing
+unused files or directories. A companion program, UnZip, unpacks Zip
+archives.
+
+For brief help on Zip or UnZip, run the program without specifying any
+parameters on the command line.
+
+This description covers the Zip program which uses a VMS-style CLI
+command line. The VMS CLI Zip program also accepts UNIX-style "-opt"
+options, but a separate Zip program is available which provides only a
+UNIX-style command line, and it has its own documentation. Refer to
+the Zip installation instructions for details.
+
+<FORMAT>
+ZIP [/options] archive inpath, inpath ...
+
+.!
+
+<TOPIC>
+Basic_Usage
+
+<FORMAT>
+ZIP [/options] archive inpath, inpath ...
+
+The default action of Zip is to add or replace entries in "archive" from
+the list of "inpath" file specifications, which can include directories
+and file names with VMS-style wildcards. If /BATCH is specified, Zip
+will read file specifications from a list file or from SYS$INPUT
+(stdin).
+
+With SET PROCESS /PARSE_STYLE = EXTENDED (available on recent non-VAX
+systems), Zip preserves the case of the command line. Otherwise, mixed-
+or upper-case arguments (file names) must be quoted. Examples in this
+document generally do not show this quotation, so VAX and /PARSE_STYLE =
+TRADITIONAL users (that is, troglodytes) will need to add quotation
+where needed when working with these examples.
+
+General
+
+Zip reads one or more files, compresses the data (normally), and stores
+the compressed information into a single Zip archive file, along with
+information about each file (name, path, date and time of last
+modification, protection, and check information to verify file
+integrity). On a VMS system, Zip can also save VMS/RMS file attributes,
+allowing UnZip to restore the files without loss of important file
+attributes. Zip can pack an entire directory structure into a Zip
+archive with a single command.
+
+Compression
+
+Compression ratios of 2:1 to 3:1 are common for text files. Zip has one
+standard compression method ("deflate") and can also store files without
+compression. Zip (and UnZip) may be built with optional support for the
+bzip2 compression method. Then, the user may select bzip2 compression
+instead of the default "deflate" method. Zip automatically chooses
+simple storage over compression for a file, if the specified compression
+method does not actually compress the data in that file.
+
+Compatibility
+
+Zip and UnZip can work with archives produced by PKZIP (supporting most
+PKZIP features up to PKZIP version 4.6), and PKZIP and PKUNZIP can work
+with archives produced by Zip (with some exceptions, notably streamed
+archives, but recent changes in the .ZIP file standard may facilitate
+better compatibility). Zip version 3.0 is compatible with PKZIP 2.04
+and also supports the Zip64 extensions of PKZIP 4.5 which allows
+archives as well as files to exceed the previous 2 GB limit (4 GB in
+some cases). Zip also supports bzip2 compression if the bzip2 library
+is included when Zip is built. Note that PKUNZIP 1.10 cannot extract
+files produced by PKZIP 2.04 or Zip 3.0. You must use PKUNZIP 2.04g or
+UnZip 5.0p1 (or later versions) to extract them.
+
+Large Archives and Zip64
+
+Where the operating system and C run-time support allow, Zip 3.0 and
+UnZip 6.0 (and later versions) support large files (input and archive),
+using the Zip64 extensions to the original .ZIP file format. On VMS,
+this genarally means non-VAX systems with VMS V7.2 or later (perhaps
+requiring a C RTL ECO before VMS V7.3-2).
+
+Zip automatically uses the Zip64 extensions when a file 4 GB or larger
+is added to an archive, an archive containing a Zip64 entry is updated
+(if the resulting archive still needs Zip64), the size of the archive
+will exceed 4 GB, or when the number of entries in the archive will
+exceed about 64K. Zip64 is also used for archives streamed to a
+non-seekable output device. You must use a 4.5 compatible UnZip to
+extract files using the Zip64 extensions such as UnZip 6.0 or later.
+
+In addition, streamed archives, entries encrypted with standard
+encryption, or split archives created with the pause option may not be
+compatible with PKZIP as data descriptors are used, and PKZIP at the
+time of this writing does not support data descriptors (but recent
+changes in the PKWare published .ZIP file standard now include some
+support for the data descriptor format Zip uses).
+
+<TOPIC>
+More_Usage
+
+Here is a very simple example of Zip use:
+
+<LITERAL>
+| zip stuff.zip *.*
+<LARETIL>
+
+This will create the Zip archive "stuff.zip" (assuming it does not
+already exist) and put all the (non-directory) files (";0") from the
+current default directory into "stuff.zip" in a compressed form. The
+archive is opened using a default file specification of
+"SYS$DISK:[].zip", so specifying "stuff" as the archive name would also
+create (or use an existing) "stuff.zip", but specifying "stuff.other"
+would give you that name. In general, Zip doesn't care about the type
+in the file specification, but for split archives (archives split over
+multiple files), the user should normally specify a type-less name,
+because Zip will normally generate sequentially numbered types ".z01",
+".z02", and so on for the early splits, and then the required ".zip" for
+the last split. These file types are required by the Zip standard for
+split archives.
+
+Standard VMS wildcard expansion ($SEARCH) is used to interpret the
+"inpath" file and directory specifications, like the "*.*" in this
+example.
+
+On VMS, the most natural way to archive an entire directory tree is to
+use a directory-depth wildcard ("[...]"). For example:
+
+<LITERAL>
+| zip foo [...]*.*
+<LARETIL>
+
+This will create the file "foo.zip" containing all the files (";0") and
+directories in and below the current default directory. A more
+UNIX-like way to do this would be to use the /RECURSE option:
+
+<LITERAL>
+| zip /recurse foo *.*
+<LARETIL>
+
+Zip avoids including its own output files when selecting files to
+include in the archive, so it should be safe, as in this case, to create
+the archive in the same drectory as the input files.
+
+One or more specific files, directories, or subdirectories may also be
+specified:
+
+<LITERAL>
+| zip foo.zip readme.txt, [www...]*.*, [.ftp...]*.*, -
+| [.src]*.h, [.src]*.c
+<LARETIL>
+
+For security reasons, paths in Zip archives are always stored as
+relative paths, so some care is needed when creating an archive so that
+it will create the intended directory structure when UnZip is used to
+unpack it.
+
+To use /RECURSE with a specific directory, the name of the directory
+file itself must be specified:
+
+<LITERAL>
+| zip /recurse foo.zip [000000]www.dir, ftp.dir
+<LARETIL>
+
+You may want to make an archive that contains the files in [.foo], but
+not record the directory name, "foo". You can use the /JUNK (junk path)
+option to leave off the path:
+
+<LITERAL>
+| zip /junk foo [.foo]*.*
+<LARETIL>
+
+If you are short on disk space, you might not have enough room to hold
+both the original directory and the corresponding compressed Zip
+archive. In this case, you can create the archive in steps, and use the
+-m option. For example, if [.foo] contains the subdirectories [.tom],
+[.dick], and [.harry], you could:
+
+<LITERAL>
+| zip /move foo [.foo.tom...]*.*
+| zip /move foo [.foo.dick...]*.*
+| zip /move foo [.foo.harry...]*.*
+<LARETIL>
+
+The first command would create foo.zip, and the next two would add to
+it. The /MOVE option will cause Zip to delete all files added to the
+archive after making or updating foo.zip. No deletions will be done
+until the Zip operation has completed with no errors. This option is
+obviously dangerous and should be used with care, but it does reduce the
+need for free disk space. When /MOVE is used, the /TEST option is
+recommended and will test the resulting archive before deleting the
+input files.
+
+If a file specification list is too long to fit conveniently on the Zip
+command line, the /BATCH option can be used to cause Zip to read a list
+of file specifications from a file or from SYS$INPUT (stdin). If a DCL
+command procedure is used, the names can be specified in the procedure:
+
+<LITERAL>
+| $ zip foo /batch
+| $ deck
+| file_spec_1
+| file_spec_2
+| file_spec_3
+| $ eod
+<LARETIL>
+
+The file specifications can also be put into a separate file, and fed
+into Zip by specifying that file as "/BATCH = list_file", or by
+explicitly defining SYS$INPUT, or by using PIPE. For example, with the
+list in foo.zfl:
+<LITERAL>
+| zip foo /batch = foo.zfl
+<LARETIL>
+or:
+<LITERAL>
+| define /user_mode sys$input foo.zfl
+| zip foo /batch
+<LARETIL>
+or:
+<LITERAL>
+| pipe type foo.zfl | zip foo /batch
+<LARETIL>
+
+If Zip is not able to read a file, it issues a warning but continues.
+See the /MUST_MATCH option for more on how Zip handles patterns that are
+not matched and files that are not readable. If some files were
+skipped, a warning is issued at the end of the Zip operation noting how
+many files were read and how many skipped.
+<TOPIC>
+Environment
+
+A user can specify default command-line options and arguments by
+defining an "environment variable" (that is, a logical name or DCL
+symbol), "ZIP_OPTS" or "ZIPOPT", to specify them. If both "ZIP_OPTS"
+and "ZIPOPT" are specified, the definition of "ZIPOPT" prevails.
+
+UNIX-style command-line options are required in these variables, even
+for the VMS CLI Zip program. For details, see the help topic
+UNIX_Options, or the separate Zip help for the UNIX-style command line.
+
+The C RTL function getenv() is used to sense these variables, so its
+behavior determines what happens if both a logical name and a symbol are
+defined. As of VMS V7.3, a logical name supercedes a symbol.
+
+The "zip /VERBOSE" report should show the perceived settings of these
+variables.
+
+For example, the following will cause Zip to skip directories, include
+VMS portable attribute information, and perform all operations at
+quiet-level 1 by default:
+
+<LITERAL>
+| $ define ZIP_OPTS "-qDV"
+<LARETIL>
+
+Note that the quotation marks here are required to preserve lowercase
+options (opposite of the command-line behavior).
+
+<TOPIC>
+Exit_Status
+
+On VMS, Zip's UNIX-style exit values are mapped into VMS-style status
+codes with facility code 1955 = %x7A3, and with the inhibit-message
+(%x10000000) and facility-specific (%x00008000) bits set:
+
+<LITERAL>
+| %x17A38001 normal exit
+| %x17A38000+ 16* Zip_error_code warnings
+| %x17A38002+ 16* Zip_error_code normal errors
+| %x17A38004+ 16* Zip_error_code fatal errors
+<LARETIL>
+
+Note that multiplying the UNIX-style Zip error code by 16 places it
+conveniently in the hexadecimal representation of the VMS exit code,
+"__" in %x17A38__s, where "s" is the severity code. For example, a
+truncated archive might cause Zip error code 2, which would be
+transformed into the VMS exit status %x17A38024.
+
+The Zip VMS exit codes include severity values which approximate those
+defined by PKWARE, as shown in the following table:
+
+<LITERAL0>
+| VMS Zip err
+|severity code Error description
+|---------+---------+----------------------------------------------
+|Success 0 (OK) Normal; no errors or warnings detected.
+|Fatal 2 (EOF) Unexpected end of archive.
+|Error 3 (FORM) A generic error in the archive format
+| was detected. Processing may have completed
+| successfully anyway; some broken archives
+| created by other archivers have simple work-
+| arounds.
+|Fatal 4 (MEM) Zip was unable to allocate memory for
+| one or more buffers during program initializ-
+| ation.
+|Fatal 5 (LOGIC) A severe error in the archive format
+| was detected. Processing probably failed
+| immediately.
+|Error 6 (BIG) Entry too large to split, read, or
+| write.
+|Error 7 (NOTE) Invalid comment format.
+|Fatal 8 (TEST) Zip -T failed or out of memory.
+|Error 9 (ABORT) The user aborted zip prematurely
+| with control-C (or equivalent).
+|Fatal 10 (TEMP) Zip encountered an error while using
+| a tempfile.
+|Fatal 11 (READ) Read or seek error.
+|Warning 12 (NONE) Zip has nothing to do.
+|Error 13 (NAME) Missing or empty zip file.
+|Fatal 14 (WRITE) Error writing to a file.
+|Fatal 15 (CREAT) Zip was unable to create a file to
+| write to.
+|Error 16 (PARMS) Bad command line parameters.
+|Error 18 (OPEN) Zip could not open a specified file
+| to read.
+|Fatal 19 (COMPERR) Zip was built with options not
+| supported on this system.
+|Fatal 20 (ZIP64) Attempt to read unsupported Zip64
+| archive.
+<0LARETIL>
+
+<TOPIC>
+File_Names
+
+Zip deals with file names in the system file system and with file names
+in Zip archives. File names in a Zip archive are stored in a UNIX-like
+path-name format. For example, a VMS file specification like this:
+
+<LITERAL>
+[.zip30.vms]descrip.mms
+<LARETIL>
+
+could appear in a Zip archive as:
+
+<LITERAL>
+zip30/vms/descrip.mms
+<LARETIL>
+
+For security reasons, paths in Zip archives are always stored as
+relative paths, so an absolute VMS directory specification will be
+transformed to a relative path in the archive (that is, no leading "/").
+For example, the following absolute directory specification would give
+the same archive path as the previous (relative) example:
+
+<LITERAL>
+[zip30.vms]descrip.mms
+<LARETIL>
+
+Also, device names are dropped, so the following file specification
+would also give the same archive path:
+
+<LITERAL>
+sys$sysdevice:[zip30.vms]descrip.mms
+<LARETIL>
+
+If an archive is intended for use with PKUNZIP under MSDOS, then the
+/PKZIP option should be used to attempt to adjust the names and paths to
+conform to MSDOS character-set and length limitations, to store only the
+MSDOS file attributes (just the owner:write attribute from VMS), and to
+mark the entry as made under MSDOS (even though it wasn't).
+
+Note that file specifications in the file system must be specified using
+VMS notation, but file names in an archive must be specified using the
+UNIX-like notation used in the archive. For example, where a BACKUP
+command might look like this:
+
+<LITERAL>
+$ back [.zip30...]*.* /excl = [...vms]*.c stuff.bck /save
+<LARETIL>
+
+a corresponding Zip command might look like this:
+
+<LITERAL>
+$ zip /exclude = "*/vms/*.c" stuff.zip [.zip30...]*.*
+<LARETIL>
+
+because the files to be added to the Zip archive are specified using VMS
+file specifications, but the /EXCLUDE option excludes names based
+on their archive path/file names. Options dealing with archive names
+include /COPY_ENTRIES, /DELETE, /EXCLUDE, /INCLUDE, and
+/RECURSE=FILENAMES.
+
+Note that a UNIX-like path specification must be quoted, or else the
+slashes ("/") will confuse the command-line interpreter, causing errors
+like "%CLI-W-IVQUAL, unrecognized qualifier - check validity, spelling,
+and placement".
+
+Note: By default, on VMS, archive name pattern matching (/COPY_ENTRIES,
+/DELETE, /EXCLUDE, /INCLUDE, and /RECURSE=FILENAMES) is case sensitive,
+even when the file system is not case sensitive (or even case
+preserving). This allows accurate matching of mixed-case names in an
+archive which may have been created on a system with a case sensitive
+file system, but it can involve extra effort on VMS, where it may be
+necessary to use unnatural case names (or the same names in multiple
+cases, like "*.obj *.OBJ") for this kind of pattern matching to give the
+desired behavior. If completely case-blind pattern matching behavior is
+desired, specify the /PATTERN_CASE=BLIND option.
+<TOPIC>
+Modes_of_Operation
+
+Zip supports two distinct types of command modes, external and
+internal. The external modes (update, grow, and freshen) read files
+from the file system (as well as from an existing archive) while the
+internal modes (delete and copy) operate exclusively on entries in an
+existing archive.
+
+<LITERAL>
+ /UPDATE
+<LARETIL>
+
+Update existing entries and add new files. If the archive does not
+exist, create it. This is the default mode, so /UPDATE is optional.
+
+<LITERAL>
+ /GROW
+<LARETIL>
+
+Grow (append to) the specified Zip archive, instead of creating a new
+one. If this operation fails, Zip attempts to restore the archive to
+its original state. If the restoration fails, the archive might become
+corrupted. This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+
+<LITERAL>
+ /FRESHEN
+<LARETIL>
+
+Update existing entries in an existing archive. Does not add new files
+to the archive.
+
+<LITERAL>
+ /DELETE
+<LARETIL>
+
+Delete entries from an existing archive.
+
+<LITERAL>
+ /COPY_ENTRIES
+<LARETIL>
+
+Select entries in an existing archive and copy them to a new archive.
+Copy mode is like update mode, but entries in the existing archive are
+selected by command line patterns rather than files from the file system
+and it uses the /OUTPUT option to write the resulting archive to a new
+file rather than updating the existing archive, leaving the original
+archive unchanged.
+
+<LITERAL>
+ /DIFFERENCE
+<LARETIL>
+
+Create an incremental backup-style archive, where the resulting archive
+will contain all new and changed files since the original archive was
+created. For this to work, the input file list and current directory
+must be the same as during the original Zip operation.
+
+For example, if the existing archive was created using
+
+<LITERAL>
+zip foo_full.zip [.foo...]*.*
+<LARETIL>
+
+from just above the foo directory, then the command (also from just
+above the foo directory):
+
+<LITERAL>
+zip /difference /output = foo_incr.zip foo_full.zip [.foo...]*.*
+<LARETIL>
+
+creates the archive foo_incr.zip with just the files not in foo_full.zip
+and the files where the size or date-time of the files does not match
+that in foo_full.zip. Note that in the "ZIP /DIFFERENCE" operation, the
+original full archive is specified as the input archive, and the /OUTPUT
+option is used to specify the new (incremental) output archive.
+
+<LITERAL>
+ /FILESYNC
+<LARETIL>
+
+Delete entries in the archive that do not match files on the OS.
+Normally files already in an archive that are not updated remain
+in the archive unchanged. The /FILESYNC option deletes files in
+the archive that are not matched during the directory scan,
+resulting in the archive being updated having the same contents
+as a new archive would. If much of the archive will remain
+unchanged, this can be faster than creating a new archive as
+copying entries is faster than compressing and adding new files.
+
+Normally, when updating an archive using relative file specifications
+("[]", "[.xxx]", and so on), it helps to have the same default directory
+as when the archive was created, but this is not a strict requirement.
+
+<TOPIC>
+Self_Extracting_Archives
+
+A self-extracting archive (SFX) comprises a normal Zip archive appended
+to a special UnZip program (such as UNZIPSFX_CLI.EXE) for the intended
+target system.
+
+The UnZip distribution includes a VMS command procedure,
+[,vms]makesfx.com, which can be used directly or adapted to create an
+SFX archive from a normal Zip archive.
+
+The .ZIP file format includes offsets to data structures in the archive,
+and these offsets are measured from the start of the archive file.
+Appending an archive to an UnZip SFX executable effectively moves the
+start of the archive file. That makes the original offsets wrong, and
+that will cause the UnZip SFX program to emit warning messages when it
+tries to unpack the archive. Zip /ADJUST_OFFSETS can be used to adjust
+these offsets in a self-extracting archive. For example, to adjust the
+offsets in foo.sfx_exe:
+
+<LITERAL>
+| zip /adjust_offsets foo.sfx_exe
+<LARETIL>
+
+Similarly, the UnZip SFX program can be removed from a self-extracting
+archive (and the offsets in the archive restored) using the /UNSFX
+option. For example:
+
+<LITERAL>
+| zip /unsfx foo.sfx_exe
+<LARETIL>
+
+Note that a self-extracting archive contains a normal Zip archive, and a
+normal UnZip program can be used to expand it in the normal way. You
+may get a warning about extra bytes at the beginning of the archive (the
+UnZip SFX program), but UnZip should work properly after that. This
+allows data in a self-extracting archive to be accessed on any system,
+not just the target system where its embedded UnZip SFX program runs.
+
+<TOPIC>
+Split_Archives
+
+Beginning with version 3.0, Zip supports split archives. A split
+archive is one which is divided into multiple files, usually to allow it
+to be stored on multiple storage media (floppy diskettes, CD-ROMs, or
+the like) when a single medium would be too small to contain the whole
+archive. (Note that split archives are not just unitary archives split
+into pieces, as the .ZIP file format includes offsets to data structures
+in the archive, and for a split archive these are based on the start of
+each split, not on the start of the whole archive. Concatenating the
+pieces will invalidate these offsets, but UnZip can usually deal with
+it. Zip will usually refuse to process such a spliced archive unless
+the /FIX = FULL option is used to fix the offsets.)
+
+For a split archive with, say, 20 split files, the files are typically
+named ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19, ARCHIVE.zip, where
+"ARCHIVE" is the archive name specified by the user on the Zip command
+line. Note that the last split file is the ".zip" file. In contrast,
+"spanned" archives are the original multi-disk archive generally
+requiring floppy disks and using volume labels to store disk numbers.
+Zip supports split archives but not spanned archives, though a procedure
+exists for converting split archives of the right size to spanned
+archives. The reverse is also true, where each file of a spanned
+archive can be copied in order to files with the above names to create a
+split archive.
+
+<QUALIFIERS>
+<QUALIFIER>
+/ADJUST_OFFSETS
+
+/ADJUST_OFFSETS
+
+Adjust internal offsets of the Zip archive members after some data
+(e.g. a SFX executable stub) has been prepended to the archive file.
+<QUALIFIER>
+/APPEND
+
+/APPEND
+/GROW
+
+Grow (append to) the specified Zip archive, instead of creating a new
+one. If this operation fails, Zip attempts to restore the archive to
+its original state. If the restoration fails, the archive might become
+corrupted. This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+
+See also /DELETE /DIFFERENCE, /FRESHEN, /UPDATE.
+<QUALIFIER>
+/BATCH
+
+/BATCH[=list_file]
+
+Read input file specifications (inpaths) from "list_file" (one per
+line). The list_file defaults to SYS$INPUT.
+<QUALIFIER>
+/BEFORE
+
+/BEFORE=VMS_date_time
+
+Restricts the files by date-time when adding, updating, or freshening an
+archive. Only files with modification date-times earlier than the
+specified date-time are accepted.
+
+See also /SINCE.
+<QUALIFIER>
+/COMMENTS
+
+/COMMENTS[=KEYWORD[,KEYWORD]]
+
+Add comments to the Zip archive.
+
+<LITERAL>
+| ARCHIVE Add/replace the multi-line archive comment. (default)
+| FILES Add file comment to each updated/added archive member.
+<LARETIL>
+
+The Zip program prompts for each comment to be added, which makes sense
+only if Zip is run interactively.
+
+The one-line file (archive member) comments are terminated by typing
+<Return>. To skip a file comment, just type <Return> without entering
+any further characters.
+
+The Zip archive comment may be multi-line. The comment is ended by a
+line containing just a period, or by an end-of-file character (CTRL/Z).
+<QUALIFIER>
+/COMPRESSION
+
+/COMPRESSION = {BZIP2|DEFLATE|STORE}
+
+Specify the compression method to be used when adding or updating files
+in an archive. STORE disables compression (like /LEVEL = 0). Default:
+/COMPRESSION = DEFLATE.
+
+Zip can archive files with or without compression. The standard
+compression method ("deflate") is compatible with all UnZip versions
+(except really old ones that only understand the "store" method).
+Current Zip and UnZip versions may be built with optional support for
+the bzip2 compression method. (The bzip2 method can compress better,
+especially when compressing highly redundant files, but uses more CPU
+time, and requires an UnZip which includes the optional bzip2 support.
+See the installation instructions for details on adding bzip2
+compression support at build time.)
+<QUALIFIER>
+/COPY_ENTRIES
+
+/COPY_ENTRIES
+
+Select entries in an existing archive and copy them to a new archive.
+Copy mode is like update mode, but entries in the existing archive are
+selected by command line patterns rather than files from the file system
+and it uses the /OUTPUT option to write the resulting archive to a new
+file rather than updating the existing archive, leaving the original
+archive unchanged.
+<QUALIFIER>
+/DELETE
+
+/DELETE
+
+Delete entries from archive.
+
+See also /DIFFERENCE, /FRESHEN, /GROW, /UPDATE.
+<QUALIFIER>
+/DIFFERENCE
+
+/DIFFERENCE
+
+Create an incremental backup-style archive, where the resulting archive
+will contain all new and changed files since the original archive was
+created. For this to work, the input file list and current directory
+must be the same as during the original Zip operation.
+
+See also /DELETE, /FRESHEN, /GROW, /UPDATE.
+<QUALIFIER>
+/DIRNAMES
+
+/DIRNAMES (default)
+/NODIRNAMES
+
+Store directory entries in the archive.
+<QUALIFIER>
+/DISPLAY
+
+/DISPLAY=(KEYWORD[,KEYWORD[...]])
+
+Enable display of progress messages.
+<LITERAL>
+| BYTES Running count of bytes processed and bytes to go.
+| COUNTS Running count of entries done and entries to go.
+| DOTS = size Dots every <size> MB while processing files.
+| (0: no dots.)
+| GLOBALDOTS Progress dots reflect the whole archive instead of each
+| file.
+| USIZE Uncompressed size of each entry.
+| VOLUME Display the volume (disk) number each entry is being
+| written to.
+<LARETIL>
+
+The default is a dot every 10 MB of input file processed. The /VERBOSE
+option also displays dots and used to at a higher rate than this (at the
+same rate as in previous versions of Zip) but this rate has been changed
+to the new 10 MB default, and is also controlled by /DISPLAY=DOTS=size.
+<QUALIFIER>
+/DOT_VERSION
+
+/DOT_VERSION
+
+Directs Zip to retain VMS file version numbers on names in an archive,
+but as ".nnn" instead of ";nnn". By default, for compatibility
+with non-VMS systems, Zip strips VMS file version numbers from the names
+stored in an archive. Thus, without /DOT_VERSION or /KEEP_VERSION, a
+version number wildcard (";*") can cause errors when multiple versions
+of a single file are treated as multiple files with the same name.
+
+See also /KEEP_VERSION.
+<QUALIFIER>
+/ENCRYPT
+
+/ENCRYPT[="password"]
+
+Encrypt new or updated archive entries using a password which is
+supplied by the user interactively on the terminal in response to a
+prompt. (The password will not be echoed.) If SYS$COMMAND is not a
+terminal, Zip will exit with an error. The password is verified before
+being accepted.
+
+You may specify the password on the command line, although we do not
+recommend it because THIS IS INSECURE. Remember to enclose the password
+string with quotation marks ("pass word"), to prevent automatic
+conversion to upper case or misinterpretation of punctuation characters
+by DCL.
+
+Because standard Zip encryption is weak, where security is truly
+important, use a strong encryption program, such as Pretty Good Privacy
+(PGP) or GNU Privacy Guard (GnuPG), on an archive instead of standard
+Zip encryption. A stronger encryption method, such as AES, is planned
+for Zip 3.1.
+<QUALIFIER>
+/EXCLUDE
+
+/EXCLUDE=(file[,...])
+
+A comma-separated list of files to exclude when deleting, updating, or
+adding files in the archive. If multiple files are specified, the list
+should be enclosed in parentheses.
+<QUALIFIER>
+/EXLIST
+
+/EXLIST=list_file
+
+The files matching the filename patterns listed in "list_file" are
+excluded when deleting, updating or adding files in the archive.
+The "list_file" is a normal text file with one filename pattern entry per
+line. The name pattern entries are recognized exactly as found in
+"list_file", including leading, embedded, and trailing whitespace or most
+control characters (with exception of LineFeed and probably CarriageReturn).
+<QUALIFIER>
+/EXTRA_FIELDS
+
+/EXTRA_FIELDS (default)
+/NOEXTRA_FIELDS
+
+Allows (or suppresses) the saving of any optional extra fields in the
+archive. (/NOEXTRA_FIELDS conflicts with /VMS[=ALL].)
+
+The .ZIP file format allows some extra data to be stored with a file in
+the archive. For example, where local time zone information is
+available, Zip can store UTC date-time data for files. (Look for
+USE_EF_UT_TIME in a "zip -v" report.) On VMS, with /VMS[=ALL], Zip will
+also store VMS-specific file attributes. These data are packaged as
+"extra fields" in the archive. Some extra fields are specific to a
+particular operating system (like VMS file attributes). Large files
+(bigger than 4GB) on any OS require an extra field to hold their 64-bit
+size data. Depending on the capabilities of the UnZip program used to
+expand the archive, these extra fields may be used or ignored when files
+are extracted from the archive.
+
+Some extra fields, like UTC date-times or VMS file attributes, are
+optional. Others, like the Zip64 extra field which holds 64-bit sizes
+for a large file, are required.
+<QUALIFIER>
+/FILESYNC
+
+/FILESYNC
+
+Delete entries in the archive that do not match files on the OS.
+Normally when an archive is updated, new files are added and changed
+files are updated but files that no longer exist on the OS are not
+deleted from the archive. This option enables deleting of entries that
+are not matched on the OS. Enabling this option should create archives
+that are the same as new archives, but since existing entries are copied
+instead of compressed, updating an existing archive with /FILESYNC can
+be much faster than creating a new archive. If few files are being
+copied from the old archive, it may be faster to create a new archive
+instead.
+
+This option deletes files from the archive. If you need to preserve the
+original archive, make a copy of the archive first, or use the /OUTPUT
+option to output the new archive to a new file. Even though it's
+slower, creating a new archive with a new archive name is safer, avoids
+mismatches between archive and OS paths, and is preferred.
+<QUALIFIER>
+/FIX_ARCHIVE
+
+/FIX=_ARCHIVE={NORMAL|FULL}
+
+The /FIX_ARCHIVE=NORMAL option (NORMAL is the default) can be used if
+some portions of the archive are missing, but it requires a reasonably
+intact central directory. The input archive is scanned as usual, but
+zip will ignore some problems. The resulting archive should be valid,
+but any inconsistent entries will be left out.
+
+If the archive is too damaged or the end (where the central directory is
+situated) has been truncated, you must use /FIX_ARCHIVE=FULL. This is
+a change from zip 2.32, where the /FIX=NORMAL option was able to read a
+truncated archive. The /FIX=NORMAL option now more reliably fixes
+archives with minor damage, and the /FIX=FULL option is needed to fix
+some archives where /FIX=NORMAL was sufficient before.
+
+With /FIX=FULL, the archive is scanned from the beginning and Zip scans
+for special signatures to identify the limits between the archive
+members. The /FIX=NORMAL option is more reliable if the archive is not
+too much damaged, so try this option first.
+
+Neither option will recover archives that have been incorrectly
+transferred, such as by FTP in ASCII mode instead of binary. After the
+repair, the /TEST (-t) option of UnZip may show that some files have a
+bad CRC. Such files cannot be recovered; you can remove them from the
+archive using the /DELETE option of Zip.
+
+Because of the uncertainty of the "fixing" process, it's required
+to specify an output archive, rather than risking further damage to the
+original damaged archive. For example, to fix the damaged archive
+foo.zip:
+
+<LITERAL>
+zip /fix_archive /output=foo_fix foo
+<LARETIL>
+
+tries to read the entries normally, copying good entries to the new
+archive foo_fix.zip. If this doesn't work, as when the archive is
+truncated, or if some entries are missed because of bad central
+directory entries, try /FIX_ARCHIVE=FULL:
+
+<LITERAL>
+zip /fix_archive=full /output=foo_fixfix foo
+<LARETIL>
+
+and compare the resulting archive to the archive created using
+/FIX=NORMAL. The /FIX=FULL option may create an inconsistent archive.
+Depending on what is damaged, you can then use the /FIX=NORMAL option to
+fix that archive.
+
+A split archive with missing split files can be fixed using /FIX=NORMAL
+if you have the last split of the archive (the ".zip" file). If this
+file is missing, you must use /FIX=FULL to fix the archive, which will
+prompt you for the splits you have.
+
+Currently, the fix options can't recover an entry which has a bad
+checksum or is otherwise damaged.
+<QUALIFIER>
+/FRESHEN
+
+/FRESHEN
+
+Update existing entries in an existing archive. Does not add new files
+to the archive.
+
+See also /DELETE, /DIFFERENCE, /GROW, /UPDATE.
+<QUALIFIER>
+/FULL_PATH
+
+/FULL_PATH (default)
+/NOFULL_PATH
+
+Directs Zip to store the directory part of the file names (relative to
+the current working directory) in the Zip archive. With /NOFULL_PATH,
+Zip stores only the file names, discarding any directory information.
+<QUALIFIER>
+/GROW
+
+/GROW
+/APPEND
+
+Grow (append to) the specified Zip archive, instead of creating a new
+one. If this operation fails, Zip attempts to restore the archive to
+its original state. If the restoration fails, the archive might become
+corrupted. This option is ignored when there's no existing archive or
+when at least one archive member must be updated or deleted.
+
+See also /DELETE, /DIFFERENCE, /FRESHEN, /UPDATE.
+<QUALIFIER>
+/HELP
+
+/HELP[=EXTENDED]
+
+Display Zip's help screen, including the version message. With
+/HELP=EXTENDED, more detailed (longer) help information is shown.
+<QUALIFIER>
+/INCLUDE
+
+/INCLUDE=(file[,...])
+
+A comma-separated list of files to include when deleting, updating, or
+adding files in the archive. If multiple files are specified, the list
+should be enclosed in parentheses.
+<QUALIFIER>
+/INLIST
+
+/INLIST=list_file
+
+The files matching the filename patterns listed in "list_file" are
+included when deleting, updating, or adding files in the archive.
+The "list_file" is a normal text file with one filename pattern entry per
+line. The name pattern entries are recognized exactly as found in
+"list_file", including leading, embedded, and trailing whitespace or most
+control characters (with exception of LineFeed and probably CarriageReturn).
+<QUALIFIER>
+/JUNK
+
+/JUNK
+/NOJUNK (default)
+
+Junk (discard) the directory part of the file names for added entries
+(do not not save the directory structure). The /JUNK qualifier is an
+alias for /NOFULL_PATH.
+<QUALIFIER>
+/KEEP_VERSION
+
+/KEEP_VERSION
+/NOKEEP_VERSION (default)
+
+Directs Zip to retain VMS file version numbers on names in an archive.
+By default, for compatibility with non-VMS systems, Zip strips VMS
+file version numbers from the names stored in an archive. Thus, without
+/DOT_VERSION or /KEEP_VERSION, a version number wildcard (";*") can
+cause errors when multiple versions of a single file are treated as
+multiple files with the same name.
+
+See also /DOT_VERSION.
+<QUALIFIER>
+/LATEST
+
+/LATEST
+
+The archive's creation and modification time is set to the latest
+modification time of all archive members.
+<QUALIFIER>
+/LEVEL
+
+/LEVEL=number
+
+Specifies the compression level:
+<LITERAL>
+| 0 Store
+| 1 Fastest compression (Defl:F)
+| ...
+| 9 Best compression (Defl:X)
+<LARETIL>
+
+The default level is 6.
+<QUALIFIER>
+/LICENSE
+
+/LICENSE
+
+Displays the Zip license.
+<QUALIFIER>
+/LOG_FILE
+
+/LOG_FILE=(FILE=log_file [, APPEND] [, INFORMATIONAL])
+
+Zip normally sends messages to the user's terminal, but these may be
+also directed to a log file.
+
+<LITERAL>
+ FILE=log_file
+<LARETIL>
+
+Open a logfile at the given path. By default, a new version will be
+created.
+
+<LITERAL>
+ APPEND
+<LARETIL>
+
+Append to an existing log file. Default is to create a new version.
+
+<LITERAL>
+ INFORMATIONAL
+<LARETIL>
+
+Only warnings and errors are written to the log unless the INFORMATIONAL
+option is also specified, then all information messages are also written
+to the log.
+<QUALIFIER>
+/MOVE
+
+/MOVE
+
+Move the specified files into the Zip archive. That is, Zip will delete
+any files which are successfully added to or updated in the archive. No
+deletions will be done until the Zip operation has completed with no
+errors. This option is obviously dangerous and should be used with
+care, but it does reduce the need for free disk space. It's recommended
+that /TEST also be used to test the archive before the input files are
+deleted.
+<QUALIFIER>
+/MUST_MATCH
+
+/MUST_MATCH
+
+All input patterns must match at least one file and all input files
+found must be readable. Normally when an input pattern does not match
+a file the "name not matched" warning is issued and when an input
+file has been found but later is missing or not readable a "missing or
+not readable" warning is issued. In either case Zip continues
+creating the archive, with missing or unreadable new files being skipped
+and files already in the archive remaining unchanged. After the
+archive is created, if any files were not readable zip returns the OPEN
+error code (18 on most systems) instead of the normal success return (0
+on most systems). With /MUST_MATCH, Zip exits as soon as an input
+pattern is not matched (whenever the "name not matched" warning would be
+issued) or when an input file is not readable. In either case Zip exits
+with an OPEN error and no archive is created.
+
+This option is useful when a known list of files is to be zipped so any
+missing or unreadable files should result in an error. It may be less
+useful when used with wildcards, but Zip will still exit with an error
+if any input pattern doesn't match at least one file or if any
+matched files are unreadable. If you want to create the archive anyway
+and only need to know if files were skipped, then don't use /MUST_MATCH
+and just check the exit status. Also, a log file (see /LOG_FILE) could
+be useful.
+<QUALIFIER>
+/PATTERN_CASE
+
+/PATTERN_CASE={BLIND|SENSITIVE}
+
+<LITERAL>
+| BLIND Use case-blind pattern matching for archive entry names.
+| SENSITIVE Use case-sensitive pattern matching for archive entry
+| names. (Default.)
+<LARETIL>
+
+By default, on VMS, archive name pattern matching (/COPY_ENTRIES,
+/DELETE, /EXCLUDE, /INCLUDE, and /RECURSE=FILENAMES) is case sensitive,
+even when the file system is not case sensitive (or even case
+preserving). This allows accurate matching of mixed-case names in an
+archive which may have been created on a system with a case sensitive
+file system, but it can involve extra effort on VMS, where it may be
+necessary to use unnatural case names (or the same names in multiple
+cases, like "*.obj *.OBJ") for this kind of pattern matching to give the
+desired behavior. If completely case-blind pattern matching behavior is
+desired, specify the /PATTERN_CASE=BLIND option.
+<QUALIFIER>
+/PKZIP
+
+/PKZIP
+/NOPKZIP (default)
+
+Create PKZIP-compatible archive entries. File names and paths are
+adjusted to conform to MSDOS character-set and length
+limitations, to store only the MSDOS file attributes (just the
+owner:write attribute from VMS), and to mark the entry as made under
+MSDOS (even though it wasn't).
+<QUALIFIER>
+/PRESERVE_CASE
+
+/NOPRESERVE_CASE
+/PRESERVE_CASE[=(keyword[, ...])]
+
+Directs Zip to preserve the case of, or convert to lower-case, file names
+in the archive. Optional keywords are:
+<LITERAL>
+| NOODS2 Down-case ODS2 file names (default).
+| NOODS5 Down-case ODS5 file names.
+| ODS2 Preserve case of ODS2 file names.
+| ODS5 Preserve case of ODS5 file names (default).
+<LARETIL>
+
+By default, file names from an ODS2 file system are converted to lower
+case for storage in an archive, while the case of file names from an
+ODS5 file system is preserved.
+
+/NOPRESERVE_CASE is equivalent to /PRESERVE_CASE = (NOODS2, NOODS5),
+which causes all file names to be converted to lower-case. This is
+equivalent to the behavior of Zip before version 3.0.
+
+/PRESERVE_CASE is equivalent to /PRESERVE_CASE = (ODS2, ODS5), which
+preserves the case of all file names.
+<QUALIFIER>
+/QUIET
+
+/QUIET
+
+Quiet mode. Eliminates informational messages and comment prompts.
+This mode may be useful in command procedures, or if the Zip operation
+is being performed as a background task ("$ spawn/nowait zip /quiet foo
+*.c").
+<QUALIFIER>
+/RECURSE
+
+/RECURSE[=KEYWORD]
+/NORECURSE (default)
+
+Directs Zip to recurse into subdirectories.
+The optional keywords recognized are:
+<LITERAL>
+| PATH take patterns as full path specifiers (-r) (default)
+| FILENAMES start from current dir;
+| only use filename part of file patterns (-R)
+<LARETIL>
+The optional FILENAMES keyword modifies the recursion algorithm to be
+(almost) compatible to PKZIP's behaviour on subdirectory recursion.
+
+On VMS, directory recursion can also be requested by using the
+directory depth wildcard ("[...]") in an input file specification.
+<QUALIFIER>
+/SHOW
+
+/SHOW=(KEYWORD[,KEYWORD[...]])
+
+Controls various diagnostic messages.
+
+The keywords recognized are:
+<LITERAL>
+| COMMAND Show command line arguments as processed (only, then exit).
+| DEBUG Show Debug information.
+| FILES Show files to process (only, then exit).
+| OPTIONS Show all available command-line options on this system.
+<LARETIL>
+<QUALIFIER>
+/SINCE
+
+/SINCE=VMS_date_time
+
+Restricts the files by date-time when adding, updating, or freshening an
+archive. Only files with modification date-times at or later than the
+specified date-time are accepted.
+
+See also /BEFORE.
+<QUALIFIER>
+/SPLIT
+
+/SPLIT = (SIZE=size [, PAUSE [, BELL]] [, VERBOSE])
+
+Enables split archives, specifies the size of the splits, and controls
+other related behavior.
+
+SIZE=size specifies the split size. The size is given as a number
+followed optionally by a multiplier suffix of k (KB), m (MB, the default
+if no suffix is specified), g (GB), or t (TB). (All are powers of 1024,
+not 1000). 64K is the minimum split size. For example, the following
+command could be used to create a split archive called "foo" from the
+contents of the "bar" directory with splits of 670MB, which might be
+useful for burning on CDs:
+
+<LITERAL>
+| zip /split = size = 670m foo [.bar...]*.*
+<LARETIL>
+
+Using /SPLIT without PAUSE as above creates all the splits in the
+directory
+specified by "foo", in this case the current default directory. This
+split mode updates the splits as the archive is being created, requiring
+all splits to remain writable, but creates split archives that are
+readable by any UnZip that supports split archives. See PAUSE below for
+enabling split pause mode which allows splits to be written directly to
+removable media.
+
+PAUSE causes Zip to pause between splits to allow
+changing removable media, for example. PAUSE uses stream mode to
+write splits so unzips that can't read stream mode entries may not
+be able to read some entries in the archive. Unless standard encryption
+was used, copy mode using /COPY_ENTRIES can convert stream mode entries
+to normal entries.
+
+BELL ring the terminal bell when Zip pauses for the next split
+destination.
+
+VERBOSE enables verbose splitting and display details of how the
+splitting is being done.
+
+Though Zip does not update split archives, Zip provides the option
+/OUTPUT to allow split archives to be updated and saved in a new
+archive. For example:
+
+<LITERAL>
+| zip inarchive.zip foo.c bar.c /output = outarchive.zip
+<LARETIL>
+
+reads archive inarchive.zip, even if split, adds the files foo.c and
+bar.c, and writes the resulting archive to outarchive.zip. If
+inarchive.zip is split, then outarchive.zip defaults to the same split
+size. Be aware that outarchive.zip and any split files that are created
+with it are always overwritten without warning. This may be changed in
+the future.
+<QUALIFIER>
+/STORE_TYPES
+
+/STORE_TYPES=(.ext1,.ext2,... )
+
+Normally, a file which is already compressed will not be compressed much
+further (if at all) by Zip, and trying to do it can waste considerable
+CPU time. Zip can suppress compression on files with particular types,
+specified with /STORE_TYPES. The default list of types where
+compression is suppressed is /STORE_TYPES=(.Z, .zip, .zoo, .arc, .lzh,
+ .arj), and the comparison is case-insensitive.
+
+/LEVEL=9 will override /STORE_TYPES, causing compression to be attempted
+for all files.
+<QUALIFIER>
+/SYMLINKS
+
+/SYMLINKS
+
+Store symbolic links as such in the Zip archive, instead of compressing
+and storing the file referred to by the link. A symbolic link normally
+requires less storage than the actual file, both in the archive, and on
+the destination file system.
+
+On VMS, symbolic links are supported on ODS5 disks where the C RTL
+supports symbolic links. Full support for symbolic links seems to
+require VMS V8.3, but a Zip program supporting symbolic links may be
+built on VMS V7.3-2.
+<QUALIFIER>
+/TEMP_PATH
+
+/TEMP_PATH=temp_dir
+
+When creating a new archive or normally when changing an existing
+archive, Zip will write a temporary file in the archive destination
+directory ("ZIxxxxxxxx", where "xxxxxxxx" is the hexadecimal process ID)
+with the new contents. Then, if and when the Zip job has completed with
+no errors, it will rename the temporary file to the specified archive
+name (replacing the old archive, if any).
+
+/TEMP_PATH=temp_dir specifies an alternate device:[directory],
+"temp_dir", for the temporary file, but specifying a different device
+will force Zip to copy the temporary file to its final destination
+instead of simply renaming it, and that copying will take more time than
+renaming, especially for a large archive. For example:
+
+<LITERAL>
+| zip /temp_path = disk$scratch:[tmp] stuff *
+<LARETIL>
+
+will cause Zip to put its temporary files in the directory
+"disk$scratch:[tmp]", copying the temporary file back to the current
+directory as stuff.zip when it's complete.
+<QUALIFIER>
+/TEST
+
+/TEST[=UNZIP=unzip_cmd]
+
+Test the integrity of a Zip archive (the new one, if /OUTPUT is
+specified). If the check fails, the old archive is unchanged and
+(with the /MOVE option) no input files are removed.
+
+Implementation
+"zip /TEST" actually runs an "unzip -t" command to do the testing, so
+UnZip must be installed properly for this to work.
+
+With UNZIP=unzip_cmd, Zip uses the UnZip command specified by
+"unzip_cmd" (normally a DCL symbol), instead of the default command,
+"unzip -t". This can be useful if multiple versions of UnZip are
+installed on a system, and the default DCL symbol "UNZIP" would run the
+wrong one (or the logical name DCL$PATH would lead to the wrong one).
+
+In "unzip_cmd", the string "{}" is replaced by the name of the
+(temporary) archive to be tested, otherwise the name of the archive is
+appended to the end of the command. The exit status is checked for
+success severity.
+<QUALIFIER>
+/TRANSLATE_EOL
+
+/TRANSLATE_EOL[=KEYWORD]
+
+Selects conversion of the end-of-line markers in text files. This
+option should be used on text files only. The optional keywords
+recognized are:
+<LITERAL>
+| LF convert LF -> CRLF (UNIX to DOS) (default)
+| CRLF convert CRLF -> LF, strip trailing CTRL-Z's (DOS to UNIX)
+<LARETIL>
+
+The CRLF option may be useful when a DOS text file has been transfered
+to a VMS disk in stream (or stream_lf) format.
+<QUALIFIER>
+/UNSFX
+
+/UNSFX
+
+Strip any prepended data from the Zip archive. ZIP /UNSFX is normally
+used to convert a self-extracting archive to a normal archive by
+removing the UnZip SFX executable from the beginning of the SFX archive.
+
+Note that a self-extracting archive contains a normal Zip archive, and a
+normal UnZip program can be used to expand it in the normal way. You
+may get a warning about extra bytes at the beginning of the archive (the
+UnZip SFX program), but UnZip should work properly after that. This
+allows data in a self-extracting archive to be accessed on any system,
+not just the target system where its embedded UnZip SFX program runs.
+<QUALIFIER>
+/UPDATE
+
+/UPDATE
+
+Update existing archive entries and add new files. If the archive does
+not exist, create it. This is the default mode, so /UPDATE is optional.
+
+See also /DELETE /DIFFERENCE, /GROW, /FRESHEN.
+<QUALIFIER>
+/VERBOSE
+
+/VERBOSE[=NORMAL|MORE|DEBUG] [, COMMAND]]
+
+Verbose mode or print diagnostic version info.
+
+Normally, when applied to real operations, this option enables the
+display of a progress indicator during compression (see /DISPLAY=DOTS
+for more on dots) and requests verbose diagnostic info about archive
+structure oddities.
+
+/VERBOSE with no value is equivalent to /VERBOSE=NORMAL. MORE adds more
+messages, and DEBUG adds still more messages.
+
+When /VERBOSE is the only command line argument, a diagnostic report is
+displayed, showing:
+
+<LITERAL>
+| o Copyright and other legal notices
+| o Program name, version, and release date
+| o Pointers to Info-ZIP FTP and Web sites
+| o Program build information (compiler type and version, OS version,
+| and the compilation date
+| o Optional features enabled at compile-time
+| o Environment variable definitions (ZIP_OPTS, ZIPOPT)
+<LARETIL>
+
+This information should be included in bug reports.
+
+/VERBOSE=COMMAND causes Zip to display the UNIX-style command-line
+argument vector which is generated from the VMS-style CLI command line
+before executing the command. This is of primary interest to program
+developers debugging the CLI.
+<QUALIFIER>
+/VMS
+
+/VMS[=ALL]
+
+The /VMS and /VMS=ALL options cause Zip to store VMS file atributes
+(such as file organization, record format, carriage control, and so on)
+in VMS-specific "extra fields" in an archive along with the usual data.
+These extra fields are ignored on non-VMS systems, but on a VMS system,
+they allow UnZip to restore the files with their VMS attributes intact.
+
+With /VMS, Zip ignores any data in the file after the end-of-file (EOF)
+point (defined by FAT$L_EFBLK and FAT$W_FFBYTE), which works well for
+well-formed files (that is, those with no valid data beyond EOF).
+Portable-format files (Stream_LF, fixed-512) archived with /VMS should
+be extracted properly on a non-VMS system. Files with more complex
+structures, such as indexed files and files with embedded byte counts or
+other such data may be of limited use on other systems. (UnZip on
+non-VMS systems may be able to extract various VMS-format text files,
+however.)
+
+With /VMS=ALL, Zip processes all allocated blocks for the file
+(including those beyond EOF). When extracted on a VMS system, the
+original file should be reproduced with as much fidelity as possible,
+but on a non-VMS system, most files will be seen as corrupt because of
+the data from beyond EOF.
+<QUALIFIER>
+/WILDCARD
+
+<LITERAL>
+/NOWILDCARD
+/WILDCARD=NOSPAN
+<LARETIL>
+
+Controls wildcard processing.
+
+/NOWILDCARD Wildcard processing is disabled.
+
+/WILDCARD=NOSPAN Wildcards don't span directory boundaries in paths.
+<QUALIFIER>
+/ZIP64
+
+/ZIP64
+
+Forces use of Zip64 archive format, even for small files. This is
+mainly for testing and should never be used. Zip will automatically
+use Zip64 as needed without this option.
+<TOPIC>
+UNIX_Options
+
+"zip -h" provides a concise list of common command-line options. "zip
+-h2" provides more details. "zip -so" provides a list of all available
+options. "zip -v" shows the program version and available features.
+(The list below was derived from a "zip -so" listing.)
+
+Short-form options begin with a single hyphen ("-"). Long-form option
+begin with a double hyphen ("--"), and may be abbreviated to any
+unambiguous shorter string. For example:
+
+<LITERAL>
+| -v
+| --verbose
+| --verb
+<LARETIL>
+
+To avoid confusion, if a negatable option contains an embedded hyphen
+("-"), then avoid abbreviating it at the hyphen if you plan to negate
+it. For example, if an option like --some-option were abbreviated to
+--some-, the parser would consider that trailing hyphen to be part of
+the option name, rather than as a negating trailing hyphen. This
+behavior may change in the future, to interpret the trailing hyphen in
+--some- to be negating. (So don't do it.)
+
+Some options may be negated (or modified) by appending a "-":
+
+<LITERAL>
+| -la-
+| --show-files-
+<LARETIL>
+
+Some options take a value, which may immediately follow the option, or
+be separated by a space or "=". For example:
+<LITERAL>
+| -ttmmddyyyy
+| -tt mmddyyyy
+| -tt=mmddyyyy
+<LARETIL>
+
+<LITERAL0>
+| Sh Long Description
+|----+-------------------+------------------------------------------------
+| 0 store store (instead of compress)
+| 1 compress-1 compress faster (-2, -3, -4, ...)
+| 9 compress-9 compress better
+| ? show the Zip help screen
+| @ names-stdin read input file patterns from SYS$INPUT (1/line)
+| A adjust-sfx adjust self-extracting executable
+| b temp-path path use "path" directory for temporary files
+| C preserve-case preserve case of all file names added to archive
+| C- preserve-case- down-case all file names added to archive
+| C2 preserve-case-2 preserve case of ODS2 names added to archive
+| C2- preserve-case-2- down-case ODS2 file added to archive (default)
+| C5 preserve-case-5 preserve case of ODS5 names added to arcv (dflt)
+| C5- preserve-case-5- down-case ODS5 names added to archive
+| c entry-comments add a comment for each entry added to archive
+| D no-dir-entries do not add archive entries for directories
+| DF difference-archive difference archive: add only changed/new files
+| d delete delete entries in archive
+| db display-bytes display running byte counts
+| dc display-counts display running file counts
+| dd display-dots display progress dots for files (dflt sz = 10MB)
+| dg display-globaldots display progress dots for archive, not each file
+| ds dot-size size set progress dot interval to "size" (MB)
+| du display-usize display original uncompressed size for entries
+| dv display-volume display volume (disk) number as in_disk>out_disk
+| e encrypt encrypt entries, ask for password
+| F fix fix mostly intact archive (try F before FF)
+| FF fixfix salvage what can be salvaged (not as reliable)
+| FS filesync remove archive entries unmatched in file system
+| f freshen update existing entries (only changed files)
+| fd force-descriptors force data descriptors as if streaming
+| fz force-zip64 force use of Zip64 format
+| g grow grow existing archive (unless update or delete)
+| H show the Zip help screen
+| h help show the Zip help screen
+| h2 more-help show extended Zip help
+| i include pat1 [pat2 [...]] include only names matching the patterns
+| J junk-sfx junk (remove) archive preamble (unzipsfx)
+| j junk-paths junk (don't store) dir names, only file names
+| k DOS-names simulate PKZIP-made archive (DOS 8.3 names)
+| L license show software license
+| l to-crlf translate end-of-lines (LF -> CRLF)
+| la log-append append to existing log file
+| lf logfile-path lfile log to log file at lfile (default: new version)
+| li log-info include informational messages in log
+| ll from-crlf translate end-of-lines (CRLF -> LF)
+| MM must-match input file spec must exist (wildcrds must match)
+| m move delete files added to archive
+| n suffixes sfx1[:sfx2[...]] don't compress files with these suffixes
+| nw no-wild no wildcards during add or update
+| O output-file ozf use "ozf" as the output archive (dflt = inp archv)
+| o latest-time set archive date-time to match oldest entry
+| P password password encrypt with supplied "password" string
+| q quiet quiet operation (no info messages)
+| R recurse-patterns recurse subdirs from cur dir, match names only
+| r recurse-paths recurse directories from specified path pats
+| s split-size size split archive at "size" (K/MB) (0: don't split)
+| sb split-bell ring termnl bell at pause for split medium chng
+| sc show-command show command line
+| sd show-debug show debug messages
+| sf show-files show files to process (only)
+| so show-options show list of all command-line options
+| sp split-pause pause to select split destination(s)
+| sv split-verbose be verbose about creating splits
+| T test test archive integrity (runs UnZip -T)
+| t from-date mmddyyyy only do files since (at or after) "mmddyyyy"
+| tt before-date mmddyyyy only do files before "mmddyyyy"
+| u update update changed files, add new files (default)
+| V VMS-portable save VMS file attributes
+| VV VMS-specific save VMS file attributes and all allocated blks
+| v verbose verbose messages (version info if only arg)
+| w VMS-versions save VMS version numbers in archive
+| ww VMS-dot-versions save VMS version numbers as ".nnn", not ";nnn"
+| X strip-extra strip all but critical extra fields
+| X- strip-extra- keep all extra fields
+| x exclude pat1 [pat2 [...]] exclude all names matching the patterns
+| Z compression-method mthd use cmprs method "mthd" (bzip2 or deflate)
+| z archive-comment ask for archive comment
+<0LARETIL>
+
+With SET PROCESS /PARSE_STYLE = EXTENDED (available on recent non-VAX
+systems), Zip preserves the case of the command line. Otherwise, mixed-
+or upper-case options and arguments must be quoted. For example,
+"-V". Examples in this document generally do not show this quotation.
+<TOPIC>
+Copyright_and_License
+
+Zip has an option to display its copyright and license.
+
+<LITERAL>
+| /LICENSE
+<LARETIL>
+
+The license is reproduced below.
+
+This is version 2007-Mar-4 of the Info-ZIP license. The definitive
+version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and a copy
+at http://www.info-zip.org/pub/infozip/license.html.
+
+--------------------------------------------------------
+<LITERAL0>
+|Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+|
+|For the purposes of this copyright and license, "Info-ZIP" is defined as
+|the following set of individuals:
+|
+|Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+|Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+|Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+|David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+|Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+|Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+|Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+|Rich Wales, Mike White.
+|
+|This software is provided "as is," without warranty of any kind, express
+|or implied. In no event shall Info-ZIP or its contributors be held
+|liable for any direct, indirect, incidental, special or consequential
+|damages arising out of the use of or inability to use this software.
+|
+|Permission is granted to anyone to use this software for any purpose,
+|including commercial applications, and to alter it and redistribute it
+|freely, subject to the above disclaimer and the following restrictions:
+|
+|1. Redistributions of source code (in whole or in part) must retain
+| the above copyright notice, definition, disclaimer, and this list
+| of conditions.
+|
+|2. Redistributions in binary form (compiled executables and libraries)
+| must reproduce the above copyright notice, definition, disclaimer,
+| and this list of conditions in documentation and/or other materials
+| provided with the distribution. The sole exception to this condition
+| is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+| part of a self-extracting archive; that is permitted without inclusion
+| of this license, as long as the normal SFX banner has not been removed
+| from the binary or disabled.
+|
+|3. Altered versions -- including, but not limited to, ports to new
+| operating systems, existing ports with new graphical interfaces,
+| versions with modified or added functionality, and dynamic, shared,
+| or static library versions not from Info-ZIP -- must be plainly marked
+| as such and must not be misrepresented as being the original source
+| or, if binaries, compiled from the original source. Such altered
+| versions also must not be misrepresented as being Info-ZIP releases --
+| including, but not limited to, labeling of the altered versions with
+| the names "Info-ZIP" (or any variation thereof, including, but not
+| limited to, different capitalizations), "Pocket UnZip," "WiZ" or
+| "MacZip" without the explicit permission of Info-ZIP. Such altered
+| versions are further prohibited from misrepresentative use of the
+| Zip-Bugs or Info-ZIP e-mail addresses or the Info-ZIP URL(s), such as
+| to imply Info-ZIP will provide support for the altered versions.
+|
+|4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip",
+| "UnZip", "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and
+| "MacZip" for its own source and binary releases.
+<0LARETIL>
+
+===
diff --git a/vms/zip_msg.msg b/vms/zip_msg.msg
new file mode 100644
index 0000000..8654148
--- /dev/null
+++ b/vms/zip_msg.msg
@@ -0,0 +1,57 @@
+! VMS Error Message Source File for Zip
+!
+! Because the facility code was formally assigned by HP, the .FACILITY
+! directive below specifies /SYSTEM. Because the messages are, in
+! general, specific to Zip, this file is not compiled with /SHARED.
+! For example:
+!
+! MESSAGE /OBJECT = [.dest]ZIP_MSG.OBJ /NOSYMBOLS [.VMS]ZIP_MSG.MSG
+!
+! LINK /SHAREABLE = [.dest]ZIP_MSG.EXE [.dest]ZIP_MSG.OBJ
+!
+!-----------------------------------------------------------------------
+
+.TITLE Info-ZIP Zip Error Messages
+.FACILITY IZ_ZIP, 1955 /SYSTEM
+.IDENT 'V3.0-000'
+
+.BASE 0
+OK /SUCCESS <Normal successful completion>
+.BASE 4
+EOF /FATAL <Unexpected end of zip file>
+.BASE 6
+FORM /ERROR <Zip file structure invalid>
+.BASE 8
+MEM /FATAL <Out of memory>
+.BASE 10
+LOGIC /FATAL <Internal logic error>
+.BASE 12
+BIG /ERROR <Entry too big to split, read, or write>
+.BASE 14
+NOTE /ERROR <Invalid comment format>
+.BASE 16
+TEST /FATAL <Zip file invalid, could not spawn unzip, or wrong unzip>
+.BASE 18
+ABORT /ERROR <Interrupted>
+.BASE 20
+TEMP /FATAL <Temporary file failure>
+.BASE 22
+READ /FATAL <Input file read failure>
+.BASE 24
+NONE /WARNING <Nothing to do!>
+.BASE 26
+NAME /ERROR <Missing or empty zip file>
+.BASE 28
+WRITE /FATAL <Output file write failure>
+.BASE 30
+CREAT /FATAL <Could not create output file>
+.BASE 32
+PARMS /ERROR <Invalid command arguments>
+.BASE 36
+OPEN /ERROR <File not found or no read permission>
+.BASE 38
+COMPERR /FATAL <Not supported>
+.BASE 40
+ZIP64 /FATAL <Attempt to read unsupported Zip64 archive>
+
+.END
diff --git a/vms/zipup.h b/vms/zipup.h
new file mode 100644
index 0000000..8fe757f
--- /dev/null
+++ b/vms/zipup.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#ifndef __zipup_h
+#define __zipup_h 1
+
+#ifndef NO_ZIPUP_H
+
+#define fbad NULL
+typedef void *ftype;
+#define zopen(n,p) (vms_native?vms_open(n) :(ftype)fopen((n), p))
+#define zread(f,b,n) (vms_native?vms_read(f,b,n):fread((b),1,(n),(FILE*)(f)))
+#define zclose(f) (vms_native?vms_close(f) :fclose((FILE*)(f)))
+#define zerr(f) (vms_native?vms_error(f) :ferror((FILE*)(f)))
+#define zstdin stdin
+
+ftype vms_open OF((char *));
+unsigned int vms_read OF((ftype, char *, unsigned int));
+int vms_close OF((ftype));
+int vms_error OF((ftype));
+#ifdef VMS_PK_EXTRA
+int vms_get_attributes OF((ftype, struct zlist far *, iztimes *));
+#endif
+
+#endif /* !NO_ZIPUP_H */
+#endif /* !__zipup_h */
+
+
+#ifndef __zipup_cb_h
+#define __zipup_cb_h 1
+
+#ifdef __DECC
+
+/* File open callback ID values. (See also OSDEP.H.) */
+
+# define FHOW_ID 4
+
+/* File open callback ID storage. */
+
+extern int fhow_id;
+
+#define fhow "r", "acc", acc_cb, &fhow_id
+
+#else /* def __DECC */ /* (So, GNU C, VAX C, ...)*/
+
+#define fhow "r", "mbc=60"
+
+#endif /* def __DECC */
+
+#endif /* ndef __zipup_cb_h */
diff --git a/win32/README.NT b/win32/README.NT
new file mode 100644
index 0000000..d2b31f7
--- /dev/null
+++ b/win32/README.NT
@@ -0,0 +1,17 @@
+From: Michael Tibbott <tibbott@classifieds2000.com>
+Subject: Zip on Windows NT problem - here's the answer
+Date: Wed, 10 Dec 1997 15:24:29 -0800
+
+If you're running NT Server (I am not sure about NT Workstation) then you
+should do the following to prevent zip/unzip from page swapping itself to
+death. And as an added bonus, the zip was about 6% faster.
+
+- open the network control panel
+
+- Click on the services tab
+
+- double-click on the server item to open its properties
+
+- Click the "maximize throughput for network applications" radio button
+
+- save and reboot
diff --git a/win32/README.TZ b/win32/README.TZ
new file mode 100644
index 0000000..ddce3f8
--- /dev/null
+++ b/win32/README.TZ
@@ -0,0 +1,7 @@
+From: paul.kienitz@shelter.sf.ca.us (Paul Kienitz)
+> It looks like I don't have to create a tzset() kluge for Watcom to check
+> the win32 API timezone information after all -- their new 10.6 release has
+> corrected this oversight. The TZ variable overrides the API. So the only
+> win32-related patch I want to make for Zip is just to use USE_EF_UT_TIME
+> unconditionally. With this in place, timezone stuff is working flawlessly
+> with or without TZ being set.
diff --git a/win32/README.txt b/win32/README.txt
new file mode 100644
index 0000000..4d56445
--- /dev/null
+++ b/win32/README.txt
@@ -0,0 +1,10 @@
+Win32/README.txt
+27 June 2008
+
+The resource files zip.rc and windll.rc must not get edited and saved from
+MS Visual Studio. MS VS automatically re-adds its specific MFC-related resource
+infrastructure to the "xx.rc" files when saved after any modification. The
+dependancies on MFC related headers break the compilation process, when you
+try to use the freely available MS Visual Studio Express Editions (2005 or 2008)
+for building Zip. And, most third-party compilers also lack support for the
+propietary MFC environment.
diff --git a/win32/crc_i386.asm b/win32/crc_i386.asm
new file mode 100644
index 0000000..19998ff
--- /dev/null
+++ b/win32/crc_i386.asm
@@ -0,0 +1,330 @@
+;===========================================================================
+; Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_i386.asm, optimized CRC calculation function for Zip and UnZip,
+; created by Paul Kienitz and Christian Spieler. Last revised 07 Jan 2007.
+;
+; Revised 06-Oct-96, Scott Field (sfield@microsoft.com)
+; fixed to assemble with masm by not using .model directive which makes
+; assumptions about segment alignment. Also,
+; avoid using loop, and j[e]cxz where possible. Use mov + inc, rather
+; than lodsb, and other misc. changes resulting in the following performance
+; increases:
+;
+; unrolled loops NO_UNROLLED_LOOPS
+; *8 >8 <8 *8 >8 <8
+;
+; +54% +42% +35% +82% +52% +25%
+;
+; first item in each table is input buffer length, even multiple of 8
+; second item in each table is input buffer length, > 8
+; third item in each table is input buffer length, < 8
+;
+; Revised 02-Apr-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+; Incorporated Rodney Brown's 32-bit-reads optimization as found in the
+; UNIX AS source crc_i386.S. This new code can be disabled by defining
+; the macro symbol NO_32_BIT_LOADS.
+;
+; Revised 12-Oct-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+; Incorporated Rodney Brown's additional tweaks for 32-bit-optimized CPUs
+; (like the Pentium Pro, Pentium II, and probably some Pentium clones).
+; This optimization is controlled by the macro symbol __686 and is disabled
+; by default. (This default is based on the assumption that most users
+; do not yet work on a Pentium Pro or Pentium II machine ...)
+;
+; Revised 25-Mar-98, Cosmin Truta (cosmint@cs.ubbcluj.ro)
+; Working without .model directive caused tasm32 version 5.0 to produce
+; bad object code. The optimized alignments can be optionally disabled
+; by defining NO_ALIGN, thus allowing to use .model flat. There is no need
+; to define this macro if using other versions of tasm.
+;
+; Revised 16-Jan-2005, Cosmin Truta (cosmint@cs.ubbcluj.ro)
+; Enabled the 686 build by default, because there are hardly any pre-686 CPUs
+; in serious use nowadays. (See the 12-Oct-97 note above.)
+;
+; Revised 03-Jan-2006, Chr. Spieler
+; Enlarged unrolling loops to "do 16 bytes per turn"; optimized access to
+; data buffer in loop body (adjust pointer only once in loop body and use
+; offsets to access each item); added additional support for the "unfolded
+; tables" optimization variant (enabled by IZ_CRCOPTIM_UNFOLDTBL).
+;
+; Revised 07-Jan-2007, Chr. Spieler
+; Recognize additional conditional flag CRC_TABLE_ONLY that prevents
+; compilation of the crc32() function.
+;
+; FLAT memory model assumed.
+;
+; Loop unrolling can be disabled by defining the macro NO_UNROLLED_LOOPS.
+; This results in shorter code at the expense of reduced performance.
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used,
+; or only the precomputed CRC_32_Table is needed.
+;
+ IFNDEF USE_ZLIB
+ IFNDEF CRC_TABLE_ONLY
+;
+ .386p
+ name crc_i386
+
+ IFDEF NO_ALIGN
+ .model flat
+ ENDIF
+
+ IFNDEF PRE_686
+ IFNDEF __686
+__686 EQU 1 ; optimize for Pentium Pro, Pentium II and compatible CPUs
+ ENDIF
+ ENDIF
+
+extrn _get_crc_table:near ; ZCONST ulg near *get_crc_table(void);
+
+;
+ IFNDEF NO_STD_STACKFRAME
+ ; Use a `standard' stack frame setup on routine entry and exit.
+ ; Actually, this option is set as default, because it results
+ ; in smaller code !!
+STD_ENTRY MACRO
+ push ebp
+ mov ebp,esp
+ ENDM
+
+ Arg1 EQU 08H[ebp]
+ Arg2 EQU 0CH[ebp]
+ Arg3 EQU 10H[ebp]
+
+STD_LEAVE MACRO
+ pop ebp
+ ENDM
+
+ ELSE ; NO_STD_STACKFRAME
+
+STD_ENTRY MACRO
+ ENDM
+
+ Arg1 EQU 18H[esp]
+ Arg2 EQU 1CH[esp]
+ Arg3 EQU 20H[esp]
+
+STD_LEAVE MACRO
+ ENDM
+
+ ENDIF ; ?NO_STD_STACKFRAME
+
+; These two (three) macros make up the loop body of the CRC32 cruncher.
+; registers modified:
+; eax : crc value "c"
+; esi : pointer to next data byte (or dword) "buf++"
+; registers read:
+; edi : pointer to base of crc_table array
+; scratch registers:
+; ebx : index into crc_table array
+; (requires upper three bytes = 0 when __686 is undefined)
+ IFNDEF __686 ; optimize for 386, 486, Pentium
+Do_CRC MACRO
+ mov bl,al ; tmp = c & 0xFF
+ shr eax,8 ; c = (c >> 8)
+ xor eax,[edi+ebx*4] ; ^ table[tmp]
+ ENDM
+ ELSE ; __686 : optimize for Pentium Pro, Pentium II and compatible CPUs
+Do_CRC MACRO
+ movzx ebx,al ; tmp = c & 0xFF
+ shr eax,8 ; c = (c >> 8)
+ xor eax,[edi+ebx*4] ; ^ table[tmp]
+ ENDM
+ ENDIF ; ?__686
+Do_CRC_byte MACRO
+ xor al, byte ptr [esi] ; c ^= *buf
+ inc esi ; buf++
+ Do_CRC ; c = (c >> 8) ^ table[c & 0xFF]
+ ENDM
+Do_CRC_byteof MACRO ofs
+ xor al, byte ptr [esi+ofs] ; c ^= *(buf+ofs)
+ Do_CRC ; c = (c >> 8) ^ table[c & 0xFF]
+ ENDM
+ IFNDEF NO_32_BIT_LOADS
+ IFDEF IZ_CRCOPTIM_UNFOLDTBL
+ ; the edx register is needed in crc calculation
+ SavLen EQU Arg3
+
+UpdCRC_dword MACRO
+ movzx ebx,al ; tmp = c & 0xFF
+ mov edx,[edi+ebx*4+3072] ; table[256*3+tmp]
+ movzx ebx,ah ; tmp = (c>>8) & 0xFF
+ shr eax,16 ;
+ xor edx,[edi+ebx*4+2048] ; ^ table[256*2+tmp]
+ movzx ebx,al ; tmp = (c>>16) & 0xFF
+ shr eax,8 ; tmp = (c>>24)
+ xor edx,[edi+ebx*4+1024] ; ^ table[256*1+tmp]
+ mov eax,[edi+eax*4] ; ^ table[256*0+tmp]
+ xor eax,edx ; ..
+ ENDM
+UpdCRC_dword_sh MACRO dwPtrIncr
+ movzx ebx,al ; tmp = c & 0xFF
+ mov edx,[edi+ebx*4+3072] ; table[256*3+tmp]
+ movzx ebx,ah ; tmp = (c>>8) & 0xFF
+ xor edx,[edi+ebx*4+2048] ; ^ table[256*2+tmp]
+ shr eax,16 ;
+ movzx ebx,al ; tmp = (c>>16) & 0xFF
+ add esi, 4*dwPtrIncr ; ((ulg *)buf) += dwPtrIncr
+ shr eax,8 ; tmp = (c>>24)
+ xor edx,[edi+ebx*4+1024] ; ^ table[256*1+tmp]
+ mov eax,[edi+eax*4] ; ^ table[256*0+tmp]
+ xor eax,edx ; ..
+ ENDM
+ ELSE ; IZ_CRCOPTIM_UNFOLDTBL
+ ; the edx register is not needed anywhere else
+ SavLen EQU edx
+
+UpdCRC_dword MACRO
+ Do_CRC
+ Do_CRC
+ Do_CRC
+ Do_CRC
+ ENDM
+UpdCRC_dword_sh MACRO dwPtrIncr
+ Do_CRC
+ Do_CRC
+ add esi, 4*dwPtrIncr ; ((ulg *)buf) += dwPtrIncr
+ Do_CRC
+ Do_CRC
+ ENDM
+ ENDIF ; ?IZ_CRCOPTIM_UNFOLDTBL
+Do_CRC_dword MACRO
+ xor eax, dword ptr [esi] ; c ^= *(ulg *)buf
+ UpdCRC_dword_sh 1 ; ... ((ulg *)buf)++
+ ENDM
+Do_CRC_4dword MACRO
+ xor eax, dword ptr [esi] ; c ^= *(ulg *)buf
+ UpdCRC_dword
+ xor eax, dword ptr [esi+4] ; c ^= *((ulg *)buf+1)
+ UpdCRC_dword
+ xor eax, dword ptr [esi+8] ; c ^= *((ulg *)buf+2)
+ UpdCRC_dword
+ xor eax, dword ptr [esi+12] ; c ^= *((ulg *)buf]+3
+ UpdCRC_dword_sh 4 ; ... ((ulg *)buf)+=4
+ ENDM
+ ENDIF ; !NO_32_BIT_LOADS
+
+ IFNDEF NO_ALIGN
+_TEXT segment use32 para public 'CODE'
+ ELSE
+_TEXT segment use32
+ ENDIF
+ assume CS: _TEXT
+
+ public _crc32
+_crc32 proc near ; ulg crc32(ulg crc, ZCONST uch *buf, extent len)
+ STD_ENTRY
+ push edi
+ push esi
+ push ebx
+ push edx
+ push ecx
+
+ mov esi,Arg2 ; 2nd arg: uch *buf
+ sub eax,eax ;> if (!buf)
+ test esi,esi ;> return 0;
+ jz fine ;> else {
+
+ call _get_crc_table
+ mov edi,eax
+ mov eax,Arg1 ; 1st arg: ulg crc
+ IFNDEF __686
+ sub ebx,ebx ; ebx=0; make bl usable as a dword
+ ENDIF
+ mov ecx,Arg3 ; 3rd arg: extent len
+ not eax ;> c = ~crc;
+
+ test ecx,ecx
+ IFNDEF NO_UNROLLED_LOOPS
+ jz bail
+ IFNDEF NO_32_BIT_LOADS
+align_loop:
+ test esi,3 ; align buf pointer on next
+ jz SHORT aligned_now ; dword boundary
+ Do_CRC_byte
+ dec ecx
+ jnz align_loop
+aligned_now:
+ ENDIF ; !NO_32_BIT_LOADS
+ mov SavLen,ecx ; save current len for later
+ shr ecx,4 ; ecx = len / 16
+ jz No_Sixteens
+ IFNDEF NO_ALIGN
+; align loop head at start of 486 internal cache line !!
+ align 16
+ ENDIF
+Next_Sixteen:
+ IFNDEF NO_32_BIT_LOADS
+ Do_CRC_4dword
+ ELSE ; NO_32_BIT_LOADS
+ Do_CRC_byteof 0
+ Do_CRC_byteof 1
+ Do_CRC_byteof 2
+ Do_CRC_byteof 3
+ Do_CRC_byteof 4
+ Do_CRC_byteof 5
+ Do_CRC_byteof 6
+ Do_CRC_byteof 7
+ Do_CRC_byteof 8
+ Do_CRC_byteof 9
+ Do_CRC_byteof 10
+ Do_CRC_byteof 11
+ Do_CRC_byteof 12
+ Do_CRC_byteof 13
+ Do_CRC_byteof 14
+ Do_CRC_byteof 15
+ add esi, 16 ; buf += 16
+ ENDIF ; ?NO_32_BIT_LOADS
+ dec ecx
+ jnz Next_Sixteen
+No_Sixteens:
+ mov ecx,SavLen
+ and ecx,00000000FH ; ecx = len % 16
+ IFNDEF NO_32_BIT_LOADS
+ shr ecx,2 ; ecx = len / 4
+ jz SHORT No_Fours
+Next_Four:
+ Do_CRC_dword
+ dec ecx
+ jnz Next_Four
+No_Fours:
+ mov ecx,SavLen
+ and ecx,000000003H ; ecx = len % 4
+ ENDIF ; !NO_32_BIT_LOADS
+ ENDIF ; !NO_UNROLLED_LOOPS
+ jz SHORT bail ;> if (len)
+ IFNDEF NO_ALIGN
+; align loop head at start of 486 internal cache line !!
+ align 16
+ ENDIF
+loupe: ;> do {
+ Do_CRC_byte ; c = CRC32(c,*buf++,crctab);
+ dec ecx ;> } while (--len);
+ jnz loupe
+
+bail: ;> }
+ not eax ;> return ~c;
+fine:
+ pop ecx
+ pop edx
+ pop ebx
+ pop esi
+ pop edi
+ STD_LEAVE
+ ret
+_crc32 endp
+
+_TEXT ends
+;
+ ENDIF ; !CRC_TABLE_ONLY
+ ENDIF ; !USE_ZLIB
+;
+end
diff --git a/win32/crc_i386.c b/win32/crc_i386.c
new file mode 100644
index 0000000..971ee66
--- /dev/null
+++ b/win32/crc_i386.c
@@ -0,0 +1,310 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* crc_i386.c -- Microsoft 32-bit C/C++ adaptation of crc_i386.asm
+ * Created by Rodney Brown from crc_i386.asm, modified by Chr. Spieler.
+ * Last revised: 07-Jan-2007
+ *
+ * Original coded (in crc_i386.asm) and put into the public domain
+ * by Paul Kienitz and Christian Spieler.
+ *
+ * Revised 06-Oct-96, Scott Field (sfield@microsoft.com)
+ * fixed to assemble with masm by not using .model directive which makes
+ * assumptions about segment alignment. Also,
+ * avoid using loop, and j[e]cxz where possible. Use mov + inc, rather
+ * than lodsb, and other misc. changes resulting in the following performance
+ * increases:
+ *
+ * unrolled loops NO_UNROLLED_LOOPS
+ * *8 >8 <8 *8 >8 <8
+ *
+ * +54% +42% +35% +82% +52% +25%
+ *
+ * first item in each table is input buffer length, even multiple of 8
+ * second item in each table is input buffer length, > 8
+ * third item in each table is input buffer length, < 8
+ *
+ * Revised 02-Apr-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+ * Incorporated Rodney Brown's 32-bit-reads optimization as found in the
+ * UNIX AS source crc_i386.S. This new code can be disabled by defining
+ * the macro symbol NO_32_BIT_LOADS.
+ *
+ * Revised 12-Oct-97, Chr. Spieler, based on Rodney Brown (rdb@cmutual.com.au)
+ * Incorporated Rodney Brown's additional tweaks for 32-bit-optimized CPUs
+ * (like the Pentium Pro, Pentium II, and probably some Pentium clones).
+ * This optimization is controlled by the macro symbol __686 and is disabled
+ * by default. (This default is based on the assumption that most users
+ * do not yet work on a Pentium Pro or Pentium II machine ...)
+ *
+ * Revised 16-Nov-97, Chr. Spieler: Made code compatible with Borland C++
+ * 32-bit, removed unneeded kludge for potentially unknown movzx mnemonic,
+ * confirmed correct working with MS VC++ (32-bit).
+ *
+ * Revised 22-May-98, Peter Kunath, Chr. Spieler: The 16-Nov-97 revision broke
+ * MSVC 5.0. Inside preprocessor macros, each instruction is enclosed in its
+ * own __asm {...} construct. For MSVC, a "#pragma warning" was added to
+ * shut up the "no return value" warning message.
+ *
+ * Revised 13-Dec-98, Chr. Spieler: Modified path to "zip.h" header file.
+ *
+ * Revised 16-Jan-2005, Cosmin Truta: Added the ASM_CRC guard, for easier
+ * switching between ASM vs. non-ASM builds, when handling makefiles.
+ * Also enabled the 686 build by default, because there are hardly any
+ * pre-686 CPUs in serious use nowadays. (See the 12-Oct-97 note above.)
+ *
+ * Revised 03-Jan-2006, Chr. Spieler
+ * Enlarged unrolling loops to "do 16 bytes per turn"; optimized access to
+ * data buffer in loop body (adjust pointer only once in loop body and use
+ * offsets to access each item); added additional support for the "unfolded
+ * tables" optimization variant (enabled by IZ_CRCOPTIM_UNFOLDTBL).
+ *
+ * Revised 07-Jan-2007, Chr. Spieler
+ * Recognize additional conditional flag CRC_TABLE_ONLY that prevents
+ * compilation of the crc32() function.
+ *
+ * FLAT memory model assumed.
+ *
+ * Loop unrolling can be disabled by defining the macro NO_UNROLLED_LOOPS.
+ * This results in shorter code at the expense of reduced performance.
+ *
+ */
+
+#include "../zip.h"
+#include "../crc32.h"
+
+#if defined(ASM_CRC) && !defined(USE_ZLIB) && !defined(CRC_TABLE_ONLY)
+
+#if !defined(PRE_686) && !defined(__686)
+# define __686
+#endif
+
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+/* Select wether the following inline-assember code is supported. */
+#if (defined(_MSC_VER) && _MSC_VER >= 700)
+#if (defined(_M_IX86) && _M_IX86 >= 300)
+# define MSC_INLINE_ASM_32BIT_SUPPORT
+ /* Disable warning for no return value, typical of asm functions */
+# pragma warning( disable : 4035 )
+#endif
+#endif
+
+#if (defined(__BORLANDC__) && __BORLANDC__ >= 452)
+# define MSC_INLINE_ASM_32BIT_SUPPORT
+#endif
+
+#ifdef MSC_INLINE_ASM_32BIT_SUPPORT
+/* This code is intended for Microsoft C/C++ (32-bit) compatible compilers. */
+
+/*
+ * These two (three) macros make up the loop body of the CRC32 cruncher.
+ * registers modified:
+ * eax : crc value "c"
+ * esi : pointer to next data byte (or dword) "buf++"
+ * registers read:
+ * edi : pointer to base of crc_table array
+ * scratch registers:
+ * ebx : index into crc_table array
+ * (requires upper three bytes = 0 when __686 is undefined)
+ */
+#ifndef __686
+#define Do_CRC { \
+ __asm { mov bl, al }; \
+ __asm { shr eax, 8 }; \
+ __asm { xor eax, [edi+ebx*4] }; }
+#else /* __686 */
+#define Do_CRC { \
+ __asm { movzx ebx, al }; \
+ __asm { shr eax, 8 }; \
+ __asm { xor eax, [edi+ebx*4] }; }
+#endif /* ?__686 */
+
+#define Do_CRC_byte { \
+ __asm { xor al, byte ptr [esi] }; \
+ __asm { inc esi }; \
+ Do_CRC; }
+
+#define Do_CRC_byteof(ofs) { \
+ __asm { xor al, byte ptr [esi+(ofs)] }; \
+ Do_CRC; }
+
+#ifndef NO_32_BIT_LOADS
+#ifdef IZ_CRCOPTIM_UNFOLDTBL
+# define SavLen len /* the edx register is needed elsewhere */
+# define UpdCRC_dword { \
+ __asm { movzx ebx,al }; \
+ __asm { mov edx,[edi+ebx*4+3072] }; \
+ __asm { movzx ebx,ah }; \
+ __asm { shr eax,16 }; \
+ __asm { xor edx,[edi+ebx*4+2048] }; \
+ __asm { movzx ebx,al }; \
+ __asm { shr eax,8 }; \
+ __asm { xor edx,[edi+ebx*4+1024] }; \
+ __asm { mov eax,[edi+eax*4] }; \
+ __asm { xor eax,edx }; }
+# define UpdCRC_dword_sh(dwPtrIncr) { \
+ __asm { movzx ebx,al }; \
+ __asm { mov edx,[edi+ebx*4+3072] }; \
+ __asm { movzx ebx,ah }; \
+ __asm { xor edx,[edi+ebx*4+2048] }; \
+ __asm { shr eax,16 }; \
+ __asm { movzx ebx,al }; \
+ __asm { add esi, 4*dwPtrIncr }; \
+ __asm { shr eax,8 }; \
+ __asm { xor edx,[edi+ebx*4+1024] }; \
+ __asm { mov eax,[edi+eax*4] }; \
+ __asm { xor eax,edx }; }
+#else /* !IZ_CRCOPTIM_UNFOLDTBL */
+# define SavLen edx /* the edx register is free for use here */
+# define UpdCRC_dword { \
+ Do_CRC; \
+ Do_CRC; \
+ Do_CRC; \
+ Do_CRC; }
+# define UpdCRC_dword_sh(dwPtrIncr) { \
+ Do_CRC; \
+ Do_CRC; \
+ __asm { add esi, 4*(dwPtrIncr) }; \
+ Do_CRC; \
+ Do_CRC; }
+#endif /* ?IZ_CRCOPTIM_UNFOLDTBL */
+
+#define Do_CRC_dword { \
+ __asm { xor eax, dword ptr [esi] }; \
+ UpdCRC_dword_sh(1); }
+
+#define Do_CRC_4dword { \
+ __asm { xor eax, dword ptr [esi] }; \
+ UpdCRC_dword; \
+ __asm { xor eax, dword ptr [esi+4] }; \
+ UpdCRC_dword; \
+ __asm { xor eax, dword ptr [esi+8] }; \
+ UpdCRC_dword; \
+ __asm { xor eax, dword ptr [esi+12] }; \
+ UpdCRC_dword_sh(4); }
+#endif /* !NO_32_BIT_LOADS */
+
+/* ========================================================================= */
+ulg crc32(crc, buf, len)
+ ulg crc; /* crc shift register */
+ ZCONST uch *buf; /* pointer to bytes to pump through */
+ extent len; /* number of bytes in buf[] */
+/* Run a set of bytes through the crc shift register. If buf is a NULL
+ pointer, then initialize the crc shift register contents instead.
+ Return the current crc in either case. */
+{
+ __asm {
+ push edx
+ push ecx
+
+ mov esi,buf ;/* 2nd arg: uch *buf */
+ sub eax,eax ;/*> if (!buf) */
+ test esi,esi ;/*> return 0; */
+ jz fine ;/*> else { */
+
+ call get_crc_table
+ mov edi,eax
+ mov eax,crc ;/* 1st arg: ulg crc */
+#ifndef __686
+ sub ebx,ebx ;/* ebx=0; => bl usable as a dword */
+#endif
+ mov ecx,len ;/* 3rd arg: extent len */
+ not eax ;/*> c = ~crc; */
+
+ test ecx,ecx
+#ifndef NO_UNROLLED_LOOPS
+ jz bail
+# ifndef NO_32_BIT_LOADS
+align_loop:
+ test esi,3 ;/* align buf pointer on next */
+ jz aligned_now ;/* dword boundary */
+ }
+ Do_CRC_byte ;
+ __asm {
+ dec ecx
+ jnz align_loop
+aligned_now:
+# endif /* !NO_32_BIT_LOADS */
+ mov SavLen,ecx ;/* save current len for later */
+ shr ecx,4 ;/* ecx = len / 16 */
+ jz No_Sixteens
+; align loop head at start of 486 internal cache line !!
+ align 16
+Next_Sixteen:
+ }
+# ifndef NO_32_BIT_LOADS
+ Do_CRC_4dword ;
+# else /* NO_32_BIT_LOADS */
+ Do_CRC_byteof(0) ;
+ Do_CRC_byteof(1) ;
+ Do_CRC_byteof(2) ;
+ Do_CRC_byteof(3) ;
+ Do_CRC_byteof(4) ;
+ Do_CRC_byteof(5) ;
+ Do_CRC_byteof(6) ;
+ Do_CRC_byteof(7) ;
+ Do_CRC_byteof(8) ;
+ Do_CRC_byteof(9) ;
+ Do_CRC_byteof(10) ;
+ Do_CRC_byteof(11) ;
+ Do_CRC_byteof(12) ;
+ Do_CRC_byteof(13) ;
+ Do_CRC_byteof(14) ;
+ Do_CRC_byteof(15) ;
+ __asm { add esi,16 };
+# endif /* ?NO_32_BIT_LOADS */
+ __asm {
+ dec ecx
+ jnz Next_Sixteen
+No_Sixteens:
+ mov ecx,SavLen
+ and ecx,00000000FH ;/* ecx = len % 16 */
+# ifndef NO_32_BIT_LOADS
+ shr ecx,2
+ jz No_Fours
+Next_Four:
+ }
+ Do_CRC_dword ;
+ __asm {
+ dec ecx
+ jnz Next_Four
+No_Fours:
+ mov ecx,SavLen
+ and ecx,000000003H ;/* ecx = len % 4 */
+# endif /* !NO_32_BIT_LOADS */
+#endif /* !NO_UNROLLED_LOOPS */
+ jz bail ;/*> if (len) */
+; align loop head at start of 486 internal cache line !!
+ align 16
+loupe: ;/*> do { */
+ }
+ Do_CRC_byte ;/* c = CRC32(c,*buf++,crctab);*/
+ __asm {
+ dec ecx ;/*> } while (--len); */
+ jnz loupe
+
+bail: ;/*> } */
+ not eax ;/*> return ~c; */
+fine:
+ pop ecx
+ pop edx
+ }
+#ifdef NEED_RETURN
+ return _EAX;
+#endif
+}
+#endif /* MSC_INLINE_ASM_32BIT_SUPPORT */
+#if (defined(_MSC_VER) && _MSC_VER >= 700)
+#if (defined(_M_IX86) && _M_IX86 >= 300)
+ /* Reenable missing return value warning */
+# pragma warning( default : 4035 )
+#endif
+#endif
+#endif /* ASM_CRC && !USE_ZLIB && !CRC_TABLE_ONLY */
diff --git a/win32/crc_lcc.asm b/win32/crc_lcc.asm
new file mode 100644
index 0000000..1538d32
--- /dev/null
+++ b/win32/crc_lcc.asm
@@ -0,0 +1,166 @@
+;===========================================================================
+; Copyright (c) 1990-2006 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_lcc.asm, optimized CRC calculation function for Zip and UnZip,
+; created by Paul Kienitz and Christian Spieler. Last revised 02 Jan 2006.
+;
+; The code in this file has been copied verbatim from crc_i386.{asm|S};
+; only the assembler syntax and metacommands have been adapted to
+; the habits of the free LCC-Win32 C compiler package.
+; This version of the code uses the "optimized for i686" variant of
+; crc_i386.{asm|S}.
+; IMPORTANT NOTE to the Info-ZIP editors:
+; The TAB characters in this source file are required by the parser of
+; the LCC-Win32 assembler program and MUST NOT be removed!!
+;
+; For more information (and a revision log), look into the original
+; source files.
+;
+ .text
+ .file "crc32.c"
+ .text
+ .type _crc32,function
+_crc32:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ecx
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ .line 34
+ .line 37
+ movl 12(%ebp),%esi
+ subl %eax,%eax
+ testl %esi,%esi
+ jz _$3
+ .line 39
+ call _get_crc_table
+ movl %eax,%edi
+ .line 41
+ movl 8(%ebp),%eax
+ movl 16(%ebp),%ecx
+ notl %eax
+ testl %ecx,%ecx
+ jz _$4
+_$5:
+ testl $3,%esi
+ jz _$6
+ xorb (%esi),%al
+ incl %esi
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ decl %ecx
+ jnz _$5
+_$6:
+ movl %ecx,%edx
+ shrl $4,%ecx
+ jz _$8
+_$7:
+ xorl (%esi),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ xorl 4(%esi),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ xorl 8(%esi),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ xorl 12(%esi),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ addl $16,%esi
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ decl %ecx
+ jnz _$7
+_$8:
+ movl %edx,%ecx
+ andl $0x0f,%ecx
+ shrl $2,%ecx
+ jz _$10
+_$9:
+ xorl (%esi),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ addl $4,%esi
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ decl %ecx
+ jnz _$9
+_$10:
+ movl %edx,%ecx
+ andl $0x03,%ecx
+ jz _$4
+_$11:
+ xorb (%esi),%al
+ incl %esi
+ movzbl %al,%ebx
+ shrl $8,%eax
+ xorl (%edi,%ebx,4),%eax
+ decl %ecx
+ jnz _$11
+_$4:
+ xorl $0xffffffff,%eax
+_$3:
+ .line 52
+ popl %edi
+ popl %esi
+ popl %ebx
+ leave
+ ret
+_$34:
+ .size _crc32,_$34-_crc32
+ .globl _crc32
+ .extern _get_crc_table
diff --git a/win32/gvmat64.asm b/win32/gvmat64.asm
new file mode 100644
index 0000000..4b5aa4d
--- /dev/null
+++ b/win32/gvmat64.asm
@@ -0,0 +1,513 @@
+;uInt longest_match_x64(
+; deflate_state *s,
+; IPos cur_match); /* current match */
+
+; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-2005 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
+;
+; File written by Gilles Vollant, by converting to assembly the longest_match
+; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+;
+; and by taking inspiration on asm686 with masm, optimised assembly code
+; from Brian Raiter, written 1998
+;
+; http://www.zlib.net
+; http://www.winimage.com/zLibDll
+; http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; to compile this file for infozip Zip, I use option:
+; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm
+;
+; to compile this file for zLib, I use option:
+; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
+; Be carrefull to adapt zlib1222add below to your version of zLib
+; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change
+; value of zlib1222add later)
+;
+; This file compile with Microsoft Macro Assembler (x64) for AMD64
+;
+; ml64.exe is given with Visual Studio 2005 and Windows 2003 server DDK
+;
+; (you can get Windows 2003 server DDK with ml64 and cl for AMD64 from
+; http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)
+;
+
+
+;uInt longest_match(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; /* current match */
+.code
+longest_match PROC
+
+
+;LocalVarsSize equ 88
+ LocalVarsSize equ 72
+
+; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
+; free register : r14,r15
+; register can be saved : rsp
+
+ chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len
+ ; low word: s->wmask
+;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10
+;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11
+;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w
+;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx
+;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13
+;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d
+;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9
+IFDEF INFOZIP
+ELSE
+ nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size
+ENDIF
+
+save_rdi equ rsp + 24 - LocalVarsSize
+save_rsi equ rsp + 32 - LocalVarsSize
+save_rbx equ rsp + 40 - LocalVarsSize
+save_rbp equ rsp + 48 - LocalVarsSize
+save_r12 equ rsp + 56 - LocalVarsSize
+save_r13 equ rsp + 64 - LocalVarsSize
+;save_r14 equ rsp + 72 - LocalVarsSize
+;save_r15 equ rsp + 80 - LocalVarsSize
+
+
+
+; all the +4 offsets are due to the addition of pending_buf_size (in zlib
+; in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, remove the +4).
+; Note : these value are good with a 8 bytes boundary pack structure
+
+
+ MAX_MATCH equ 258
+ MIN_MATCH equ 3
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+
+
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+; all the +zlib1222add offsets are due to the addition of fields
+; in zlib in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+
+
+IFDEF INFOZIP
+
+_DATA SEGMENT
+COMM window_size:DWORD
+; WMask ; 7fff
+COMM window:BYTE:010040H
+COMM prev:WORD:08000H
+; MatchLen : unused
+; PrevMatch : unused
+COMM strstart:DWORD
+COMM match_start:DWORD
+; Lookahead : ignore
+COMM prev_length:DWORD ; PrevLen
+COMM max_chain_length:DWORD
+COMM good_match:DWORD
+COMM nice_match:DWORD
+prev_ad equ OFFSET prev
+window_ad equ OFFSET window
+nicematch equ nice_match
+_DATA ENDS
+WMask equ 07fffh
+
+ELSE
+
+ IFNDEF zlib1222add
+ zlib1222add equ 0
+ ENDIF
+dsWSize equ 56+zlib1222add+(zlib1222add/2)
+dsWMask equ 64+zlib1222add+(zlib1222add/2)
+dsWindow equ 72+zlib1222add
+dsPrev equ 88+zlib1222add
+dsMatchLen equ 128+zlib1222add
+dsPrevMatch equ 132+zlib1222add
+dsStrStart equ 140+zlib1222add
+dsMatchStart equ 144+zlib1222add
+dsLookahead equ 148+zlib1222add
+dsPrevLen equ 152+zlib1222add
+dsMaxChainLen equ 156+zlib1222add
+dsGoodMatch equ 172+zlib1222add
+dsNiceMatch equ 176+zlib1222add
+
+window_size equ [ rcx + dsWSize]
+WMask equ [ rcx + dsWMask]
+window_ad equ [ rcx + dsWindow]
+prev_ad equ [ rcx + dsPrev]
+strstart equ [ rcx + dsStrStart]
+match_start equ [ rcx + dsMatchStart]
+Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip
+prev_length equ [ rcx + dsPrevLen]
+max_chain_length equ [ rcx + dsMaxChainLen]
+good_match equ [ rcx + dsGoodMatch]
+nice_match equ [ rcx + dsNiceMatch]
+ENDIF
+
+; parameter 1 in r8(deflate state s), param 2 in rdx (cur match)
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
+
+
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+
+;;; Retrieve the function arguments. r8d will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
+
+; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
+
+ mov [save_rdi],rdi
+ mov [save_rsi],rsi
+ mov [save_rbx],rbx
+ mov [save_rbp],rbp
+IFDEF INFOZIP
+ mov r8d,ecx
+ELSE
+ mov r8d,edx
+ENDIF
+ mov [save_r12],r12
+ mov [save_r13],r13
+; mov [save_r14],r14
+; mov [save_r15],r15
+
+
+;;; uInt wmask = s->w_mask;
+;;; unsigned chain_length = s->max_chain_length;
+;;; if (s->prev_length >= s->good_match) {
+;;; chain_length >>= 2;
+;;; }
+
+ mov edi, prev_length
+ mov esi, good_match
+ mov eax, WMask
+ mov ebx, max_chain_length
+ cmp edi, esi
+ jl LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+;;; chainlen is decremented once beforehand so that the function can
+;;; use the sign flag instead of the zero flag for the exit test.
+;;; It is then shifted into the high word, to make room for the wmask
+;;; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+
+;;; on zlib only
+;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+IFDEF INFOZIP
+ mov [chainlenwmask], ebx
+; on infozip nice_match = [nice_match]
+ELSE
+ mov eax, nice_match
+ mov [chainlenwmask], ebx
+ mov r10d, Lookahead
+ cmp r10d, eax
+ cmovnl r10d, eax
+ mov [nicematch],r10d
+ENDIF
+
+;;; register Bytef *scan = s->window + s->strstart;
+ mov r10, window_ad
+ mov ebp, strstart
+ lea r13, [r10 + rbp]
+
+;;; Determine how many bytes the scan ptr is off from being
+;;; dword-aligned.
+
+ mov r9,r13
+ neg r13
+ and r13,3
+
+;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
+IFDEF INFOZIP
+ mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1))
+ELSE
+ mov eax, window_size
+ sub eax, MIN_LOOKAHEAD
+ENDIF
+ xor edi,edi
+ sub ebp, eax
+
+ mov r11d, prev_length
+
+ cmovng ebp,edi
+
+;;; int best_len = s->prev_length;
+
+
+;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+ lea rsi,[r10+r11]
+
+;;; register ush scan_start = *(ushf*)scan;
+;;; register ush scan_end = *(ushf*)(scan+best_len-1);
+;;; Posf *prev = s->prev;
+
+ movzx r12d,word ptr [r9]
+ movzx ebx, word ptr [r9 + r11 - 1]
+
+ mov rdi, prev_ad
+
+;;; Jump into the main loop.
+
+ mov edx, [chainlenwmask]
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop1:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry1:
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop2:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry2:
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop4:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry4:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jnz LookupLoop1
+ jmp LookupLoopIsZero
+
+
+;;; do {
+;;; match = s->window + cur_match;
+;;; if (*(ushf*)(match+best_len-1) != scan_end ||
+;;; *(ushf*)match != scan_start) continue;
+;;; [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;; && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; r8d = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+
+LookupLoop:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jnz LookupLoop1
+LookupLoopIsZero:
+ cmp r12w, word ptr [r10 + r8]
+ jnz LookupLoop1
+
+
+;;; Store the current value of chainlen.
+ mov [chainlenwmask], edx
+
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+
+ lea rsi,[r8+r10]
+ mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8)
+ lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8]
+ lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8]
+
+ prefetcht1 [rsi+rdx]
+ prefetcht1 [rdi+rdx]
+
+
+;;; Test the strings for equality, 8 bytes at a time. At the end,
+;;; adjust rdx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (rsi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+
+
+LoopCmps:
+ mov rax, [rsi + rdx]
+ xor rax, [rdi + rdx]
+ jnz LeaveLoopCmps
+
+ mov rax, [rsi + rdx + 8]
+ xor rax, [rdi + rdx + 8]
+ jnz LeaveLoopCmps8
+
+
+ mov rax, [rsi + rdx + 8+8]
+ xor rax, [rdi + rdx + 8+8]
+ jnz LeaveLoopCmps16
+
+ add rdx,8+8+8
+
+ jmp short LoopCmps
+LeaveLoopCmps16: add rdx,8
+LeaveLoopCmps8: add rdx,8
+LeaveLoopCmps:
+
+ test eax, 0000FFFFh
+ jnz LenLower
+
+ test eax,0ffffffffh
+
+ jnz LenLower32
+
+ add rdx,4
+ shr rax,32
+ or ax,ax
+ jnz LenLower
+
+LenLower32:
+ shr eax,16
+ add rdx,2
+LenLower: sub al, 1
+ adc rdx, 0
+;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+;;; then automatically accept it as the best possible match and leave.
+
+ lea rax, [rdi + rdx]
+ sub rax, r9
+ cmp eax, MAX_MATCH
+ jge LenMaximum
+
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+;///////////////////////////////////
+
+ cmp eax, r11d
+ jg LongerMatch
+
+ lea rsi,[r10+r11]
+
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; s->match_start = cur_match;
+;;; best_len = len;
+;;; if (len >= nice_match) break;
+;;; scan_end = *(ushf*)(scan+best_len-1);
+
+LongerMatch:
+ mov r11d, eax
+ mov match_start, r8d
+ cmp eax, [nicematch]
+ jge LeaveNow
+
+ lea rsi,[r10+rax]
+
+ movzx ebx, word ptr [r9 + rax - 1]
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; Accept the current string, with the maximum possible length.
+
+LenMaximum:
+ mov r11d,MAX_MATCH
+ mov match_start, r8d
+
+;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+;;; return s->lookahead;
+
+LeaveNow:
+IFDEF INFOZIP
+ mov eax,r11d
+ELSE
+ mov eax, Lookahead
+ cmp r11d, eax
+ cmovng eax, r11d
+ENDIF
+
+;;; Restore the stack and return from whence we came.
+
+
+ mov rsi,[save_rsi]
+ mov rdi,[save_rdi]
+ mov rbx,[save_rbx]
+ mov rbp,[save_rbp]
+ mov r12,[save_r12]
+ mov r13,[save_r13]
+; mov r14,[save_r14]
+; mov r15,[save_r15]
+
+
+ ret 0
+; please don't remove this string !
+; Your can freely use gvmat64 in any free or commercial app
+; but it is far better don't remove the string in the binary!
+ db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0
+longest_match ENDP
+
+match_init PROC
+ ret 0
+match_init ENDP
+
+
+END
diff --git a/win32/lm32_lcc.asm b/win32/lm32_lcc.asm
new file mode 100644
index 0000000..0450fe3
--- /dev/null
+++ b/win32/lm32_lcc.asm
@@ -0,0 +1,174 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; match32.asm by Jean-loup Gailly.
+
+; match32.asm, optimized version of longest_match() in deflate.c
+; To be used only with 32 bit flat model. To simplify the code, the option
+; -DDYN_ALLOC is not supported.
+; This file is only optional. If you don't have an assembler, use the
+; C version (add -DNO_ASM to CFLAGS in makefile and remove match.o
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+;
+; Win32 (Windows NT) version - 1994/04/13 by Steve Salisbury
+; * works with Microsoft MASM 6.1X and Microsoft Visual C++ / 32-bit edition
+;
+; The code in this file has been copied verbatim from match32.{asm|S};
+; only the assembler syntax and metacommands have been adapted to
+; the habits of the free LCC-Win32 C compiler package.
+; IMPORTANT NOTE to the Info-ZIP editors:
+; The TAB characters in this source file are required by the parser of
+; the LCC-Win32 assembler program and MUST NOT be removed!!
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+
+
+;/* This version is for 386 Unix or OS/2 in 32 bit mode.
+; * Warning: it uses the AT&T syntax: mov source,dest
+; * This file is only optional. If you want to force the C version,
+; * add -DNO_ASM to CFLAGS in Makefile and set OBJA to an empty string.
+; * If you have reduced WSIZE in (g)zip.h, then make sure this is
+; * assembled with an equivalent -DWSIZE=<whatever>.
+; * This version assumes static allocation of the arrays (-DDYN_ALLOC not used).
+; */
+
+ .text
+ .file "match.S"
+
+
+ .text
+ .type _match_init,function
+
+_match_init:
+ ret
+_$98:
+ .size _match_init,_$98-_match_init
+ .globl _match_init
+
+;/*-----------------------------------------------------------------------
+; * Set match_start to the longest match starting at the given string and
+; * return its length. Matches shorter or equal to prev_length are discarded,
+; * in which case the result is equal to prev_length and match_start is
+; * garbage.
+; * IN assertions: cur_match is the head of the hash chain for the current
+; * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+; */
+
+ .align 4
+ .type _longest_match,function
+
+_longest_match: ;/* int longest_match(cur_match) */
+
+; cur_match equ 20(%esp)
+; /* return address */ /* esp+16 */
+ push %ebp
+ push %edi
+;/* esp+8 */
+ push %esi
+;/* esp+4 */
+ push %ebx
+;/* esp */
+
+;/*
+; * match equ esi
+; * scan equ edi
+; * chain_length equ ebp
+; * best_len equ ebx
+; * limit equ edx
+; */
+ mov 20(%esp),%esi
+ mov _strstart,%edx
+ mov _max_chain_length,%ebp
+ mov %edx,%edi
+ sub $(32768-262),%edx
+ cld
+ jae limit_ok
+ sub %edx,%edx
+limit_ok:
+ add $2+_window,%edi
+ mov _prev_length,%ebx
+ movw -2(%edi),%cx
+ movw -3(%ebx,%edi),%ax
+ cmp _good_match,%ebx
+ jb do_scan
+ shr $2,%ebp
+ jmp do_scan
+
+ .align 4
+long_loop:
+;/* at this point, edi == scan+2, esi == cur_match */
+ movw -3(%ebx,%edi),%ax
+ movw -2(%edi),%cx
+short_loop:
+;/*
+; * at this point, di == scan+2, si == cur_match,
+; * ax = scan[best_len-1..best_len] and cx = scan[0..1]
+; */
+ and $(32768-1), %esi
+ dec %ebp
+ movw _prev(,%esi,2),%si
+ jz the_end
+ cmp %edx,%esi
+ jbe the_end
+do_scan:
+ cmpw _window-1(%ebx,%esi),%ax
+ jne short_loop
+ cmpw _window(%esi),%cx
+ jne short_loop
+
+ add $2+_window,%esi
+ mov $((258>>1)-1),%ecx
+ mov %edi,%eax
+ repe; cmpsw
+;/* loop until mismatch */
+ je maxmatch
+;/* match of length MAX_MATCH? */
+mismatch:
+ movb -2(%edi),%cl
+ xchg %edi,%eax
+ subb -2(%esi),%cl
+ sub %edi,%eax
+ sub $2+_window,%esi
+ sub %eax,%esi
+ subb $1,%cl
+ adc $0,%eax
+ cmp %ebx,%eax
+ jle long_loop
+ mov %esi,_match_start
+ mov %eax,%ebx
+ cmp _nice_match,%eax
+; /* len >= nice_match ? */
+ jl long_loop
+the_end:
+ mov %ebx,%eax
+ pop %ebx
+ pop %esi
+ pop %edi
+ pop %ebp
+ ret
+ .align 4
+maxmatch:
+ cmpsb
+ jmp mismatch
+_$99:
+
+ .size _longest_match,_$99-_longest_match
+ .globl _longest_match
+
+ .extern _nice_match
+ .extern _good_match
+ .extern _max_chain_length
+ .extern _match_start
+ .extern _strstart
+ .extern _prev_length
+ .extern _prev
+ .extern _window
diff --git a/win32/makefile.a64 b/win32/makefile.a64
new file mode 100644
index 0000000..d2bc841
--- /dev/null
+++ b/win32/makefile.a64
@@ -0,0 +1,134 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit Microsoft Visual C++
+
+# To use, do "nmake -f makefile.w32"
+
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have masm 6.1X.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+ASMOBJS = gvmat64.obj
+
+# ------------- 32-bit Microsoft Visual C++ -------------
+CC=cl -nologo
+CFLAGS=-W3 -O2 -DNO_ASM_CRC -DASMV -DWIN32 $(LOC)
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+
+# Remove "-coff" from ASFLAGS if you do not have MASM 6.11.
+
+AS=ml64 -nologo
+ASFLAGS= /c /Zi /DINFOZIP
+
+# If you build 16-bit executables with MS Visual C++ v1.0/1.5 and link them
+# with the /KNOWEAS switch, you can build dual-mode MS-DOS/Win32 executables
+# by passing the -stub switch to the 32-bit linker to specify the 16-bit part.
+
+LD=link -nologo
+LDFLAGS=advapi32.lib
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj win32_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+win32zip.obj: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj: win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+gvmat64.obj: win32/gvmat64.asm
+ $(AS) $(ASFLAGS) win32\gvmat64.asm
+
+zip.exe: $(OBJZ) $(OBJI)
+ $(LD) $(LDFLAGS) $(OBJZ) $(OBJI)
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC)
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS)
diff --git a/win32/makefile.bor b/win32/makefile.bor
new file mode 100644
index 0000000..10b4609
--- /dev/null
+++ b/win32/makefile.bor
@@ -0,0 +1,189 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# Borland C++ for Win32.
+# By E-Yen Tan.
+# Updated on 18 Dec 2005 by Cosmin Truta.
+# Last updated on 22 Jun 2008 by Christian Spieler.
+
+# To use, do "make -fwin32\makefile.bor"
+
+# Add -DNO_ASM to LOC and comment out the ASMOBJS definition below
+# if you do not have tasm32.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+!IF $(USEASM)
+LOC = $(LOCAL_ZIP)
+!ELSE
+LOC = -DNO_ASM $(LOCAL_ZIP)
+!ENDIF
+
+# CPU type: 3 (i386), 4 (i486), 5 (Pentium), etc.
+CPU_TYP = 6
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+!IF $(USEASM)
+ASMOBJS = match32.obj
+CRCA_O = crc_i386.obj
+!ENDIF
+
+ASCPUFLAG = __$(CPU_TYP)86
+
+VPATH=.;win32
+CC = bcc32
+CFLAGS=-w -w-aus -w-ccc -w-par -w-sig -O2 -I. -DWIN32 $(LOC)
+UTILFLAGS=-DUTIL $(CFLAGS) -o
+
+!ifdef USETASM16
+AS=tasm
+!else
+AS=tasm32
+!endif
+ASFLAGS=-ml -t -m2 -D$(ASCPUFLAG) $(LOC)
+
+LD=ilink32
+LDFLAGS=
+
+# variables
+OBJZ1 = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj $(CRCA_O) globals.obj
+OBJZ2 = deflate.obj trees.obj $(ASMOBJS)
+OBJZS = win32zip.obj win32.obj win32i64.obj nt.obj
+OBJZ = $(OBJZ1) $(OBJZ2) $(OBJZS)
+
+OBJU = zipfile_.obj fileio_.obj util_.obj crc32_.obj $(CRCA_O) globals.obj \
+ win32_.obj win32i64.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+win32zip.obj: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CFLAGS) win32/$*.c
+
+win32.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CFLAGS) win32/$*.c
+
+win32i64.obj: win32/win32i64.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) win32/$*.c
+
+nt.obj: win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CFLAGS) win32/$*.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS)$* util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS)$* crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS)$* crypt.c
+
+win32_.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS)$* win32/win32.c
+
+!ifdef USEMASM
+crc_i386.obj: win32/crc_i386.asm
+ masm -ml win32/crc_i386.asm,$@;
+!else
+!ifndef ASMOVERBCC32
+crc_i386.obj: win32/crc_i386.asm
+ $(AS) $(ASFLAGS) win32\crc_i386.asm, $@ ;
+!else
+crc_i386.obj: win32/crc_i386.c crc32.h
+ $(CC) -c $(CFLAGS) -o$@ win32/crc_i386.c
+!endif
+!endif
+
+!ifdef USEMASM
+match32.obj: win32/match32.asm
+ masm -ml win32/match32.asm,$@;
+!else
+match32.obj: win32/match32.asm
+ $(AS) $(ASFLAGS) win32\match32.asm, $@ ;
+!endif
+
+zip.res: win32/zip.rc revision.h
+ $(RC) /l 0x409 /fo$@ /i win32 /d WIN32 win32/zip.rc
+
+# Split the command line to fit in the MS-DOS 128 byte limit by using
+# Borland-Make specific response file syntax:
+zip.exe: $(OBJZ) zip.res
+ $(LD) -Gn -x -c -ap -Tpe @&&|
+c0x32.obj $(OBJZ),$@,,import32.lib cw32.lib,,zip.res
+|
+
+zipcloak.exe: $(OBJC)
+ $(CC) $(LDFLAGS) @&&|
+$(OBJC)
+|
+
+zipnote.exe: $(OBJN)
+ $(CC) $(LDFLAGS) @&&|
+$(OBJN)
+|
+
+zipsplit.exe: $(OBJS)
+ $(CC) $(LDFLAGS) @&&|
+$(OBJS)
+|
+
+clean:
+ -del *.obj
+ -del *.res
+ -del *.exe
+ -del *.tds
diff --git a/win32/makefile.dj b/win32/makefile.dj
new file mode 100644
index 0000000..902c9ed
--- /dev/null
+++ b/win32/makefile.dj
@@ -0,0 +1,112 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+# for djgpp 2.01 and RSXNTDJ 1.3.1 under Windows 95 / Windows NT
+# Derived from makefile.os2 by E-Yen Tan. Last updated 07 Jan 2007.
+
+CC = gcc -O2 -m486 -Wall -Zwin32
+CFLAGS = -DWIN32 -DASM_CRC $(LOCAL_ZIP)
+AS = gcc
+ASFLAGS = -Di386
+LDFLAGS = -o ./
+LDFLAGS2 =
+OBJ=.o
+
+CRC32=crc_gcc
+OBJA = matchgcc.o
+OBJZS = win32.o win32zip.o nt.o
+OBJUS = win32_.o
+OSDEP_H = win32/osdep.h
+
+ADVAPI32 = adv32
+ADVAPI32LIB = lib$(ADVAPI32).a
+L_ADVAPI32 = -l$(ADVAPI32)
+
+OBJZ1 = zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+ crc32$(OBJ) $(CRCA_O)
+OBJZ2 = globals$(OBJ) deflate$(OBJ) trees$(OBJ) crypt$(OBJ) \
+ ttyio$(OBJ)
+OBJZ = $(OBJZ1) $(OBJZ2) $(OBJZS) $(OBJA)
+
+OBJU1 = zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) crc32$(OBJ) globals$(OBJ)
+OBJU = $(OBJU1) $(OBJUS)
+
+OBJN = zipnote$(OBJ) $(OBJU)
+OBJS = zipsplit$(OBJ) $(OBJU)
+OBJC = zipcloak$(OBJ) crc32_$(OBJ) crypt_$(OBJ) ttyio$(OBJ) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+ $(CC) -c -I. $(CFLAGS) $<
+
+.asm$(OBJ):
+ $(AS) $(ASFLAGS) $<
+
+all: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ): zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ): zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ): zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+fileio$(OBJ): fileio.c $(ZIP_H) crc32.h
+util$(OBJ): util.c $(ZIP_H)
+globals$(OBJ): globals.c $(ZIP_H)
+deflate$(OBJ): deflate.c $(ZIP_H)
+trees$(OBJ): trees.c $(ZIP_H)
+crc32$(OBJ): crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ): ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+win32zip$(OBJ): win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c -I. $(CFLAGS) win32/win32zip.c
+
+win32$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CFLAGS) win32/win32.c
+
+nt$(OBJ): win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c -I. $(CFLAGS) win32/nt.c
+
+crc_gcc$(OBJ): crc_i386.S # 32bit, GNU AS
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o$@ crc_i386.S
+
+matchgcc$(OBJ): match.S
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o$@ match.S
+
+zipcloak$(OBJ): zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote$(OBJ): zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ): zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ zipfile.c
+
+fileio_$(OBJ): fileio.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ fileio.c
+
+util_$(OBJ): util.c $(ZIP_H) os2/os2zip.h
+ $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ util.c
+
+crc32_$(OBJ): crc32.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ crc32.c
+
+crypt_$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ crypt.c
+
+win32_$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CFLAGS) -DUTIL -o$@ win32/win32.c
+
+$(ADVAPI32LIB):
+ makelib "$(windir)/system/advapi32.dll" -o ./$@
+
+zip.exe: $(OBJZ) $(ADVAPI32LIB)
+ $(CC) $(LDFLAGS)$@ $(OBJZ) $(L_ADVAPI32) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+ $(CC) $(LDFLAGS)$@ $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+ $(CC) $(LDFLAGS)$@ $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+ $(CC) $(LDFLAGS)$@ $(OBJS) $(LDFLAGS2)
diff --git a/win32/makefile.emx b/win32/makefile.emx
new file mode 100644
index 0000000..5f050ab
--- /dev/null
+++ b/win32/makefile.emx
@@ -0,0 +1,304 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit
+# using emx 0.9c+rsxnt for Windows 95/98 and Windows NT and emx 0.9c for DOS.
+# By Kai-Uwe Rommel, Chr. Spieler, E-Yen Tan (and others).
+# Last updated 18th February 2007.
+#
+# Supported Make utilities:
+# - Microsoft/IBM nmake (e.g. from MSC 6.0 or newer)
+# - dmake 3.8 or higher
+# - GNU make, at least version 3.68 (GNUish 16-bit port, RSXNT Make 3.75,
+# DJGPP v1.12 Make 3.71, some versions of DJGPP v2.x 32-bit Make;
+# current DJGPP v2.01 Make 3.76.1 does NOT work)
+# - NOT watcom make
+# The "smart" Make utilities mentioned below are Christian Spieler's
+# enhanced version of GNUish 16-bit Make (3.74) and his adaption of these
+# GNU Make sources to EMX (32-bit).
+
+# Supported 32-bit C Compilers (created programs run under WinNT/Win95 only):
+# - GNU gcc (emx/rsxnt kit 0.9c or newer)
+
+# Supported Cross-Compilers for MS-DOS:
+# - GNU gcc (emx kit 0.9c or newer, 32-bit)
+
+# Supported Assemblers:
+# - GNU as with GNU gcc
+
+
+# To use, enter "make/nmake/dmake -f win32/makefile.emx"
+# (this makefile depends on its name being "win32/makefile.emx").
+
+# Add -DDYN_ALLOC to ASFLAGS if you have defined it in tailor.h or CFLAGS
+
+# Note: assembly language modules are really only supported for
+# GNU gcc 32-bit compilation.
+
+
+default:
+ @echo "Enter $(MAKE) -f win32/makefile.emx target"
+ @echo "where target is one of:"
+ @echo " gcc gccso gccdyn gccdebug gcczl gccdos gccdoszl"
+ @echo " -----------------------------------------------"
+ @echo "Or, specify a specific target for a partial build,"
+ @echo "This uses >gcc< setup (win32 statically linked binary)"
+
+# emx 0.9c, gcc, PE format, statically linked C runtime and rsxnt.dll
+gcc: all
+
+# emx 0.9c, gcc, PE format, statically linked C runtime, standalone
+gccso:
+ $(MAKE) -f win32/makefile.emx all \
+ CC="gcc -Zwin32 -Zsys -O2 -m486 -Wall" \
+ CFLAGS="-DWIN32 -DASM_CRC" \
+ AS="gcc -Zwin32" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-ladvapi32 -s" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ CRCAUO="crcgcc_.o" \
+ OBJA="matchgcc.o" \
+ DEF="win32/zip.def"
+
+# emx 0.9c, gcc, PE format, dynamically linked C runtime and rsxnt.dll
+gccdyn:
+ $(MAKE) -f win32/makefile.emx all \
+ CC="gcc -Zwin32 -Zcrtdll=crtrsxnt -O2 -m486 -Wall" \
+ CFLAGS="-DWIN32 -DASM_CRC" \
+ AS="gcc -Zwin32" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-ladvapi32 -s" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ CRCAUO="crcgcc_.o" \
+ OBJA="matchgcc.o" \
+ DEF="win32/zip.def"
+
+# emx 0.9c, gcc, PE format, with debug info for gdb
+gccdebug:
+ $(MAKE) -f win32/makefile.emx all \
+ CC="gcc -Zwin32 -O2 -g -Wall" \
+ CFLAGS="-DWIN32 -DASM_CRC" \
+ AS="gcc -Zwin32" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-ladvapi32 -Zsmall-conv" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ CRCAUO="crcgcc_.o" \
+ OBJA="matchgcc.o" \
+ DEF="win32/zip.def"
+
+# emx 0.9c, gcc, PE format,, statically linked zlib, C runtime, and rsxnt.dll
+gcczl:
+ $(MAKE) -f win32/makefile.emx all \
+ CC="gcc -Zwin32 -O2 -m486 -Wall" \
+ CFLAGS="-DWIN32 -DUSE_ZLIB" \
+ AS="gcc -Zwin32" \
+ ASFLAGS="-Di386 -DUSE_ZLIB" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-L. -lzlib -ladvapi32 -s" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="" \
+ CRCAUO="" \
+ OBJA="" \
+ DEF="win32/zip.def"
+
+# emx 0.9c, gcc, a.out format, for MS-DOS
+gccdos:
+ $(MAKE) -f win32/makefile.emx all \
+ CC="gcc -O2 -m486 -Wall" \
+ CFLAGS="-DDOS -DMSDOS -DASM_CRC" \
+ AS="gcc" \
+ ASFLAGS="-Di386" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-s -Zsmall-conv" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="crc_gcc.o" \
+ CRCAUO="crcgcc_.o" \
+ OBJA="matchgcc.o" \
+ OBJZS="msdos.o" \
+ OBJUS="msdos_.o" \
+ OSDEP_H="msdos/osdep.h" \
+ ZIPUP_H="msdos/zipup.h"
+
+# emx 0.9c, gcc, a.out format, for MS-DOS, using zlib
+gccdoszl:
+ $(MAKE) -f win32/makefile.emx all \
+ CC="gcc -O2 -m486 -Wall" \
+ CFLAGS="-DDOS -DMSDOS -DUSE_ZLIB" \
+ AS="gcc" \
+ ASFLAGS="-Di386 -DUSE_ZLIB" \
+ LDFLAGS="-o ./" \
+ LDFLAGS2="-L. -lzlib -s -Zsmall-conv" \
+ OUT="-o" \
+ OBJ=".o" \
+ CRCA_O="" \
+ CRCAUO="" \
+ OBJA="" \
+ OBJZS="msdos.o" \
+ OBJUS="msdos_.o" \
+ OSDEP_H="msdos/osdep.h" \
+ ZIPUP_H="msdos/zipup.h"
+
+# VPATH = .;win32
+
+# variables
+
+#default settings for target dependent macros:
+
+# the "gcc" (statically linked Win32 executables) target:
+CC=gcc -Zwin32 -O2 -m486 -Wall
+CFLAGS=-DWIN32 -DASM_CRC
+AS=gcc -Zwin32
+ASFLAGS=-Di386
+LDFLAGS=-o ./
+LDFLAGS2=-ladvapi32 -s -Zsmall-conv
+OUT=-o
+OBJ=.o
+CRCA_O=crc_gcc$(OBJ)
+CRCAUO=crcgcc_$(OBJ)
+OBJA=matchgcc$(OBJ)
+OSDEP_H=win32/osdep.h
+ZIPUP_H=win32/zipup.h
+DEF=win32/zip.def
+
+DIRSEP = /
+AS_DIRSEP = /
+RM = del
+LOCAL_OPTS = $(LOCAL_ZIP)
+CCFLAGS = $(CFLAGS) $(LOCAL_OPTS)
+
+
+OBJZ1 = zip$(OBJ) zipfile$(OBJ) zipup$(OBJ) fileio$(OBJ) util$(OBJ) \
+ crc32$(OBJ) $(CRCA_O)
+OBJZ2 = globals$(OBJ) deflate$(OBJ) trees$(OBJ) crypt$(OBJ) \
+ ttyio$(OBJ)
+OBJZS = win32zip$(OBJ) win32$(OBJ) nt$(OBJ)
+OBJZ = $(OBJZ1) $(OBJZ2) $(OBJZS) $(OBJA)
+
+OBJU1 = zipfile_$(OBJ) fileio_$(OBJ) util_$(OBJ) crc32_$(OBJ) $(CRCAUO) \
+ globals$(OBJ)
+OBJUS = win32_$(OBJ)
+OBJU = $(OBJU1) $(OBJUS)
+
+OBJN = zipnote$(OBJ) $(OBJU)
+OBJS = zipsplit$(OBJ) $(OBJU)
+OBJC1 = zipcloak$(OBJ) crypt_$(OBJ) ttyio$(OBJ)
+OBJC = $(OBJC1) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+# rules
+
+.SUFFIXES: .c $(OBJ)
+
+.c$(OBJ):
+ $(CC) -c -I. $(CCFLAGS) $(OUT)$@ $<
+
+# targets
+
+all: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip$(OBJ): zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile$(OBJ): zipfile.c $(ZIP_H) crc32.h
+zipup$(OBJ): zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio$(OBJ): fileio.c $(ZIP_H) crc32.h
+util$(OBJ): util.c $(ZIP_H)
+globals$(OBJ): globals.c $(ZIP_H)
+deflate$(OBJ): deflate.c $(ZIP_H)
+trees$(OBJ): trees.c $(ZIP_H)
+crc32$(OBJ): crc32.c $(ZIP_H) crc32.h
+crypt$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio$(OBJ): ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+msdos$(OBJ): msdos/msdos.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) msdos$(DIRSEP)msdos.c
+
+win32zip$(OBJ): win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32zip.c
+
+win32$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)win32.c
+
+nt$(OBJ): win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c -I. $(CCFLAGS) win32$(DIRSEP)nt.c
+
+crc_gcc$(OBJ): crc_i386.S # 32bit, GNU AS
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ crc_i386.S
+
+matchgcc$(OBJ): match.S
+ $(AS) $(ASFLAGS) -x assembler-with-cpp -c -o $@ match.S
+
+zipcloak$(OBJ): zipcloak.c $(ZIP_H) revision.h crypt.h ttyio.h
+zipnote$(OBJ): zipnote.c $(ZIP_H) revision.h
+zipsplit$(OBJ): zipsplit.c $(ZIP_H) revision.h
+
+zipfile_$(OBJ): zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ zipfile.c
+
+fileio_$(OBJ): fileio.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ fileio.c
+
+util_$(OBJ): util.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ util.c
+
+crc32_$(OBJ): crc32.c $(ZIP_H) crc32.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crc32.c
+
+crypt_$(OBJ): crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ crypt.c
+
+msdos_$(OBJ): msdos/msdos.c $(ZIP_H)
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ msdos$(DIRSEP)msdos.c
+
+win32_$(OBJ): win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c -I. $(CCFLAGS) -DUTIL $(OUT)$@ win32$(DIRSEP)win32.c
+
+crcgcc_$(OBJ): crc_i386.S # 32bit, GNU AS
+ $(AS) $(ASFLAGS) -DUTIL -x assembler-with-cpp -c -o $@ crc_i386.S
+
+zip.exe: $(OBJZ)
+# for DUMB make utilities, uncomment the following commands:
+ -@$(RM) zip.rsp
+ @for %%f in ($(OBJZ1)) do echo %%f >> zip.rsp
+ @for %%f in ($(OBJZ2)) do echo %%f >> zip.rsp
+ @for %%f in ($(OBJZS) $(OBJA)) do echo %%f >> zip.rsp
+ $(CC) $(LDFLAGS)$@ @zip.rsp $(LDFLAGS2)
+ @$(RM) zip.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+# $(CC) $(LDFLAGS)$@ $(OBJZ) $(LDFLAGS2)
+
+zipcloak.exe: $(OBJC)
+# for DUMB make utilities, uncomment the following commands:
+ -@$(RM) zipcloak.rsp
+ @for %%f in ($(OBJC1)) do echo %%f >> zipcloak.rsp
+ @for %%f in ($(OBJU1)) do echo %%f >> zipcloak.rsp
+ @for %%f in ($(OBJUS)) do echo %%f >> zipcloak.rsp
+ $(CC) $(LDFLAGS)$@ @zipcloak.rsp $(LDFLAGS2)
+ @$(RM) zipcloak.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+# $(CC) $(LDFLAGS)$@ $(OBJC) $(LDFLAGS2)
+
+zipnote.exe: $(OBJN)
+# for DUMB make utilities, uncomment the following commands:
+ -@$(RM) zipnote.rsp
+ @for %%f in ($(OBJN)) do echo %%f >> zipnote.rsp
+ $(CC) $(LDFLAGS)$@ @zipnote.rsp $(LDFLAGS2)
+ @$(RM) zipnote.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+# $(CC) $(LDFLAGS)$@ $(OBJN) $(LDFLAGS2)
+
+zipsplit.exe: $(OBJS)
+# for DUMB make utilities, uncomment the following commands:
+ -@$(RM) zipsplit.rsp
+ @for %%f in ($(OBJN)) do echo %%f >> zipsplit.rsp
+ $(CC) $(LDFLAGS)$@ @zipsplit.rsp $(LDFLAGS2)
+ @$(RM) zipsplit.rsp
+# smart make utilities (like well done ports of GNU Make) can use this:
+# $(CC) $(LDFLAGS)$@ $(OBJS) $(LDFLAGS2)
diff --git a/win32/makefile.gcc b/win32/makefile.gcc
new file mode 100644
index 0000000..d28c447
--- /dev/null
+++ b/win32/makefile.gcc
@@ -0,0 +1,159 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for port of gcc producing
+# native Win32-Intel binaries. Derived from makefile.w32.
+# Currently supported implementations: Cygwin and MinGW.
+# Authors: Cosmin Truta, Christian Spieler, and possibly others.
+# Last updated: 2008-Jun-22.
+#
+# To use, do "make -f win32/makefile.gcc".
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+# ------------ GNU C ------------
+CC=gcc
+CFLAGS=-O2 -Wall -DWIN32 -DFORCE_WIN32_OVER_UNIX
+ifndef USEZLIB
+CCFLAGS=$(CFLAGS) $(LOC)
+else
+CCFLAGS=$(CFLAGS) -DUSE_ZLIB $(LOC)
+endif
+UTILFLAGS=$(CCFLAGS) -DUTIL -o$@
+
+#AS=as
+AS=$(CC)
+ifndef USEZLIB
+ASDEFS=
+else
+ASDEFS=-DUSE_ZLIB
+endif
+ASFLAGS=-c $(ASDEFS) $(LOC)
+
+RC=windres
+
+LD=$(CC)
+LDFLAGS=-o$@ -s
+ifndef USEZLIB
+LIBS=-luser32 -ladvapi32
+else
+LIBS=-L. -lz -luser32 -ladvapi32
+endif
+
+OSDEP_H = win32/osdep.h
+ZIPUP_H = win32/zipup.h
+
+# variables
+ifndef USEZLIB
+CRCA_O = crc_i386.o
+CRCAUO = crci386_.o
+OBJA = match.o $(CRCA_O)
+else
+CRCA_O =
+CRCAUO =
+OBJA =
+endif
+#use second definition for linking against libz
+
+OBJZ1 = zip.o crypt.o ttyio.o zipfile.o zipup.o fileio.o util.o \
+ crc32.o globals.o
+OBJZ2 = deflate.o trees.o $(OBJA)
+OBJZS = win32.o win32zip.o win32i64.o nt.o
+OBJZ = $(OBJZ1) $(OBJZ2) $(OBJZS)
+
+OBJU1 = zipfile_.o fileio_.o util_.o crc32_.o $(CRCAUO) globals.o
+OBJUS = win32_.o win32i64.o
+OBJU = $(OBJU1) $(OBJUS)
+
+OBJN = zipnote.o $(OBJU)
+OBJS = zipsplit.o $(OBJU)
+OBJC1 = zipcloak.o crypt_.o ttyio.o
+OBJC = $(OBJC1) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h $(OSDEP_H)
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+# rules
+
+.SUFFIXES: .c .o
+
+.c.o:
+ $(CC) -c $(CCFLAGS) -I. -o$@ $<
+
+# targets
+
+zips: $(ZIPS)
+
+zip.o: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile.o: zipfile.c $(ZIP_H) crc32.h
+zipup.o: zipup.c $(ZIP_H) revision.h crc32.h crypt.h $(ZIPUP_H)
+fileio.o: fileio.c $(ZIP_H) crc32.h
+util.o: util.c $(ZIP_H)
+globals.o: globals.c $(ZIP_H)
+deflate.o: deflate.c $(ZIP_H)
+trees.o: trees.c $(ZIP_H)
+crc32.o: crc32.c $(ZIP_H) crc32.h
+crypt.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio.o: ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+win32zip.o: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CCFLAGS) -I. win32/win32zip.c
+
+win32.o: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CCFLAGS) -I. win32/win32.c
+
+win32i64.o: win32/win32i64.c $(ZIP_H)
+ $(CC) -c $(CCFLAGS) -I. win32/win32i64.c
+
+nt.o: win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CCFLAGS) -I. win32/nt.c
+
+zipcloak.o: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote.o: zipnote.c $(ZIP_H) revision.h
+zipsplit.o: zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.o: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.o: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.o: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.o: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.o: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.o: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+match.o: match.S
+ $(AS) $(ASFLAGS) match.S
+
+crc_i386.o: crc_i386.S
+ $(AS) $(ASFLAGS) crc_i386.S
+
+crci386_.o: crc_i386.S
+ $(AS) $(ASFLAGS) -DUTIL -o$@ crc_i386.S
+
+ziprc.o: win32/zip.rc revision.h
+ - $(RC) -o $@ win32/zip.rc
+
+zip.exe: $(OBJZ) ziprc.o
+ $(LD) $(LDFLAGS) $(OBJZ) ziprc.o $(LIBS)
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC) $(LIBS)
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS)
+
+clean:
+ rm -f *.o $(ZIPS)
diff --git a/win32/makefile.ibm b/win32/makefile.ibm
new file mode 100644
index 0000000..3cd2975
--- /dev/null
+++ b/win32/makefile.ibm
@@ -0,0 +1,123 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit IBM Visual Age C++
+
+# To use, do "nmake -f win32\makefile.ibm"
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+# ASMOBJS = match32.obj
+
+# ------------- 32-bit IBM Visual Age C++ -------------
+CC=icc -q -O
+CFLAGS=-W0 -DWIN32 -Sm -DNO_ASM -DNO_MKTEMP $(LOC)
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+LDFLAGS=
+LIBS=advapi32.lib
+AS=ml -nologo
+ASFLAGS=-c -Cx
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj globals.obj win32_.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crc32_.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+win32zip.obj: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj: win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+match32.obj: win32/match32.asm
+ $(AS) $(ASFLAGS) win32\match32.asm
+
+zip.exe: $(OBJZ) $(OBJI)
+ $(CC) -Fe $@ $(LDFLAGS) $(OBJZ) $(OBJI) $(LIBS)
+
+zipcloak.exe: $(OBJC)
+ $(CC) -Fe $@ $(LDFLAGS) $(OBJC) $(LIBS)
+
+zipnote.exe: $(OBJN)
+ $(CC) -Fe $@ $(LDFLAGS) $(OBJN) $(LIBS)
+
+zipsplit.exe: $(OBJS)
+ $(CC) -Fe $@ $(LDFLAGS) $(OBJS) $(LIBS)
diff --git a/win32/makefile.lcc b/win32/makefile.lcc
new file mode 100644
index 0000000..6c7e8b5
--- /dev/null
+++ b/win32/makefile.lcc
@@ -0,0 +1,125 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit using LCC-Win32.
+# By E-Yen Tan (3 June 1998).
+# Last updated 9 February 2008 (Christian Spieler).
+
+# This compiler evaluates #include locations relative to current working dir,
+# not relative to the location of the file containing the #include directive.
+# As a consequence, a "-Iwin32" option is required to allow compilation of
+# the WIN32 specific sources.
+
+CC = lcc
+# -O caused a segmentation violation with previous versions of lcc, but
+# now the optimizer seems to be fixed.
+CCFLAGS = -Zp8 -O -DWIN32
+AS = lcc
+ASFLAGS =
+LD = lcclnk
+LDFLAGS = -s
+
+# Optional macros should be declared below.
+# LCC's Make will not read the LOCAL_ZIP environment variable.
+LOC = $(ASMFLG)
+
+# Options to select optimized assembler code for CRC32 calculation.
+#ifdef USEASM
+CRCA_O = crc_lcc.obj
+OBJA = lm32_lcc.obj
+ASMFLG = -DASM_CRC -DASMV
+#else
+#CRCA_O =
+#OBJA =
+#ASMFLG = -DNO_ASM
+#endif
+
+CFLAGS = $(CCFLAGS) $(LOC)
+
+OBJZS = win32.obj win32zip.obj nt.obj $(OBJA)
+OBJUS = win32_.obj
+
+OBJZ1 = zip.obj zipfile.obj zipup.obj fileio.obj util.obj
+OBJZ2 = crc32.obj $(CRCA_O) globals.obj
+OBJZ3 = deflate.obj trees.obj crypt.obj ttyio.obj
+OBJZ = $(OBJZ1) $(OBJZ2) $(OBJZ3) $(OBJZS)
+
+OBJU1 = zipfile_.obj fileio_.obj util_.obj crc32_.obj globals.obj
+OBJU = $(OBJU1) $(OBJUS)
+
+OBJN = zipnote.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+OBJK = zipcloak.obj crypt_.obj ttyio.obj
+OBJC = $(OBJK) $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+# rules
+
+.SUFFIXES: .c .obj
+
+.c.obj:
+ $(CC) $(CFLAGS) $<
+
+.asm.obj:
+ $(AS) $(ASFLAGS) $<
+
+all: zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+util.obj: util.c $(ZIP_H)
+globals.obj: globals.c $(ZIP_H)
+deflate.obj: deflate.c $(ZIP_H)
+trees.obj: trees.c $(ZIP_H)
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+
+win32.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) $(CFLAGS) -Iwin32 -Fo$@ win32/win32.c
+
+win32zip.obj: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) $(CFLAGS) -Iwin32 -Fo$@ win32/win32zip.c
+
+nt.obj: win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) $(CFLAGS) -Iwin32 -Fo$@ win32/nt.c
+
+crc_lcc.obj: win32/crc_lcc.asm
+ $(AS) $(ASFLAGS) -Fo$@ win32/crc_lcc.asm
+
+lm32_lcc.obj: win32/lm32_lcc.asm
+ $(AS) $(ASFLAGS) -Fo$@ win32/lm32_lcc.asm
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) $(CFLAGS) -DUTIL -Fo$@ zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) $(CFLAGS) -DUTIL -Fo$@ fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) $(CFLAGS) -DUTIL -Fo$@ util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) $(CFLAGS) -DUTIL -Fo$@ crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) $(CFLAGS) -DUTIL -Fo$@ crypt.c
+
+win32_.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) $(CFLAGS) -DUTIL -Iwin32 -Fo$@ win32/win32.c
+
+zip.exe: $(OBJZ)
+ $(LD) $(LDFLAGS) -o $@ $(OBJZ)
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) -o $@ $(OBJC)
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) -o $@ $(OBJN)
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
diff --git a/win32/makefile.w10 b/win32/makefile.w10
new file mode 100644
index 0000000..0463f3b
--- /dev/null
+++ b/win32/makefile.w10
@@ -0,0 +1,197 @@
+# WMAKE makefile for Windows 95 and Windows NT (Intel only)
+# using Watcom C/C++ v10.5+, by Paul Kienitz, last revised 22 Jun 2008.
+# Makes Zip.exe, ZipNote.exe, ZipCloak.exe, and ZipSplit.exe.
+#
+# Invoke from Zip source dir with "WMAKE -F WIN32\MAKEFILE.WAT [targets]"
+# To build with debug info use "WMAKE DEBUG=1 ..."
+# To build without any assembly modules use "WMAKE NOASM=1 ..."
+#
+# Other options to be fed to the compiler can be specified in an environment
+# variable called LOCAL_ZIP. One possibility "-DDYN_ALLOC", but currently
+# this is not supported unless NOASM is also used.
+
+variation = $(%LOCAL_ZIP)
+
+# Stifle annoying "Delete this file?" questions when errors occur:
+.ERASE
+
+.EXTENSIONS:
+.EXTENSIONS: .exe .obj .c .h .asm
+
+# We maintain multiple sets of object files in different directories so that
+# we can compile msdos, dos/4gw, and win32 versions of Zip without their
+# object files interacting. The following var must be a directory name
+# ending with a backslash. All object file names must include this macro
+# at the beginning, for example "$(O)foo.obj".
+
+!ifdef DEBUG
+OBDIR = od32w
+!else
+OBDIR = ob32w
+!endif
+O = $(OBDIR)\ # comment here so backslash won't continue the line
+
+# The assembly hot-spot code in crc_i386.asm and match32.asm is optional.
+# This section controls its usage.
+
+!ifdef NOASM
+asmob =
+asmco =
+cvars = $+$(cvars)$- -DNO_ASM # otherwise ASM_CRC might default on!
+# "$+$(foo)$-" means expand foo as it has been defined up to now; normally,
+# this make defers inner expansion until the outer macro is expanded.
+!else # !NOASM
+asmco = $(O)crc_i386.obj
+asmob = $(asmco) $(O)match32.obj
+cvars = $+$(cvars)$- -DASMV -DASM_CRC
+!endif
+
+# Our object files. OBJZ is for Zip, OBJC is for ZipCloak, OBJN is for
+# ZipNote, and OBJS is for ZipSplit:
+
+OBJZ3 = $(O)zip.obj $(O)crypt.obj $(O)ttyio.obj $(O)trees.obj $(O)zipup.obj
+OBJZ2 = $(OBJZ3) $(O)util.obj $(O)zipfile.obj $(O)fileio.obj $(O)deflate.obj
+OBJZ1 = $(OBJZ2) $(O)globals.obj $(O)crc32.obj $(asmob)
+OBJZ = $(OBJZ1) $(O)win32zip.obj $(O)win32.obj $(O)win32i64.obj $(O)nt.obj
+
+OBJU1 = $(O)zipfile_.obj $(O)fileio_.obj $(O)util_.obj $(O)crc32_.obj $(asmco)
+OBJ_U = $(OBJU1) $(O)globals.obj $(O)win32_.obj $(O)win32i64_.obj
+
+OBJC = $(O)zipcloak.obj $(O)crypt_.obj $(O)ttyio.obj $(OBJ_U)
+
+OBJN = $(O)zipnote.obj $(OBJ_U)
+
+OBJS = $(O)zipsplit.obj $(OBJ_U)
+
+# Common header files included by all C sources:
+
+ZIP_H = zip.h ziperr.h tailor.h win32\osdep.h
+
+# Now we have to pick out the proper compiler and options for it.
+
+cc = wcc386
+link = wlink
+asm = wasm
+rc = wrc
+# Use Pentium Pro timings, register args, static strings in code:
+cflags = -bt=NT -6r -zt -zq
+aflags = -bt=NT -mf -3 -zq
+rcflags= -bt=NT -DWIN32 -iwin32 -q
+lflags = sys NT
+cvars = $+$(cvars)$- -DWIN32 $(variation)
+avars = $+$(avars)$- $(variation)
+
+# Specify optimizations, or a nonoptimized debugging version:
+
+!ifdef DEBUG
+cdebug = -od -d2
+ldebug = d w all op symf
+!else
+cdebug = -s -oeilrt -zp4
+# note: -ol+ does not help. -oa helps slightly but might be dangerous.
+ldebug = op el
+!endif
+
+# How to compile sources:
+.c.obj:
+ $(cc) $(cdebug) $(cflags) $(cvars) $< -fo=$@
+
+# Here we go! By default, make all targets:
+all: Zip.exe ZipNote.exe ZipCloak.exe ZipSplit.exe
+
+# Convenient shorthand options for single targets:
+z: Zip.exe .SYMBOLIC
+n: ZipNote.exe .SYMBOLIC
+c: ZipCloak.exe .SYMBOLIC
+s: ZipSplit.exe .SYMBOLIC
+
+Zip.exe: $(OBDIR) $(OBJZ) $(O)zip.res
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJZ)}
+ $(rc) $(O)zip.res $@
+
+ZipNote.exe: $(OBDIR) $(OBJN)
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJN)}
+
+ZipCloak.exe: $(OBDIR) $(OBJC)
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJC)}
+
+ZipSplit.exe: $(OBDIR) $(OBJS)
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJS)}
+
+# Source dependencies:
+
+$(O)crc32.obj: crc32.c $(ZIP_H) crc32.h # only used if NOASM
+$(O)crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+$(O)deflate.obj: deflate.c $(ZIP_H)
+$(O)fileio.obj: fileio.c $(ZIP_H) crc32.h
+$(O)globals.obj: globals.c $(ZIP_H)
+$(O)trees.obj: trees.c $(ZIP_H)
+$(O)ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+$(O)util.obj: util.c $(ZIP_H)
+$(O)zip.obj: zip.c $(ZIP_H) crc32.h crypt.h revision.h ttyio.h
+$(O)zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+$(O)zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32\zipup.h
+$(O)zipnote.obj: zipnote.c $(ZIP_H) revision.h
+$(O)zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+$(O)zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+# Special case object files:
+
+$(O)win32.obj: win32\win32.c $(ZIP_H) win32\win32zip.h
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\win32.c -fo=$@
+
+$(O)win32i64.obj: win32\win32i64.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\win32i64.c -fo=$@
+
+$(O)win32zip.obj: win32\win32zip.c $(ZIP_H) win32\win32zip.h win32\nt.h
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\win32zip.c -fo=$@
+
+$(O)nt.obj: win32\nt.c $(ZIP_H) win32\nt.h
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\nt.c -fo=$@
+
+$(O)match32.obj: win32\match32.asm
+ $(asm) $(aflags) $(avars) win32\match32.asm -fo=$@
+
+$(O)crc_i386.obj: win32\crc_i386.asm
+ $(asm) $(aflags) $(avars) win32\crc_i386.asm -fo=$@
+
+# Variant object files for ZipNote, ZipCloak, and ZipSplit:
+
+$(O)zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL zipfile.c -fo=$@
+
+$(O)fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL fileio.c -fo=$@
+
+$(O)util_.obj: util.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL util.c -fo=$@
+
+$(O)crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crc32.c -fo=$@
+
+$(O)crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crypt.c -fo=$@
+
+$(O)win32_.obj: win32\win32.c $(ZIP_H) win32\win32zip.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32.c -fo=$@
+
+$(O)win32i64_.obj: win32\win32i64.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32i64.c -fo=$@
+
+$(O)zip.res: win32\zip.rc revision.h
+ $(rc) -r $(rcflags) -fo=$@ win32\zip.rc
+
+# Creation of subdirectory for intermediate files
+$(OBDIR):
+ -mkdir $@
+
+# Unwanted file removal:
+
+clean: .SYMBOLIC
+ del $(O)*.obj
+
+cleaner: clean .SYMBOLIC
+ del Zip.exe
+ del ZipNote.exe
+ del ZipCloak.exe
+ del ZipSplit.exe
diff --git a/win32/makefile.w32 b/win32/makefile.w32
new file mode 100644
index 0000000..7afbf0e
--- /dev/null
+++ b/win32/makefile.w32
@@ -0,0 +1,224 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit Microsoft Visual C++
+
+# To use, do "nmake -f makefile.w32"
+
+# Add "NOASM=1" to the nmake command to disable usage of assembler sources
+# if you do not have masm 6.1X.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+!IFNDEF debug
+NODEBUG=1
+!ENDIF
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+!IFDEF NOASM
+ASMOBJS =
+CRCA_O =
+CFLG_ASM = -DNO_ASM
+!ELSE
+ASMOBJS = match32.obj
+CRCA_O = crci386c.obj
+CFLG_ASM = -DASM_CRC
+!ENDIF
+
+!IFDEF USEBZ2
+LOC=$(LOC) -DBZIP2_SUPPORT
+!IFNDEF debug
+EXTLIB=$(EXTLIB) libbz2.lib
+!ELSE
+EXTLIB=$(EXTLIB) libbz2.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+LOC=$(LOC) -DUSE_ZLIB
+ASMOBJS=
+!IFNDEF debug
+EXTLIB=$(EXTLIB) zlib.lib
+!ELSE
+EXTLIB=$(EXTLIB) zlib.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+USE_MSVCRT=1
+!ELSE
+!IFDEF USEBZIP2
+USE_MSVCRT=1
+!ELSE
+USE_MSVCRT=0
+!ENDIF
+!ENDIF # USEZLIB
+
+!IF $(USE_MSVCRT) == 1
+CRTLIB=-MD
+!ELSE
+!IF "$(VS80COMNTOOLS)" == ""
+CRTLIB=-ML
+!ELSE
+# no single-threaded CRT static lib, only multi-threaded in VC8
+CRTLIB=-MT
+!ENDIF
+!ENDIF
+
+!IFDEF NODEBUG
+cdebug = -O2
+cdbgsz = -O1
+!ELSE
+cdebug = -Od
+cdbgsz = $(cdebug)
+!ENDIF
+
+# ------------- 32-bit Microsoft Visual C++ -------------
+CC=cl -nologo
+CFLAGS=-W3 $(cdebug) -DWIN32 $(CFLG_ASM) $(CRTLIB) $(LOC)
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+
+# Remove "-coff" from ASFLAGS if you do not have MASM 6.11.
+
+AS=ml -nologo
+ASFLAGS=-c -coff -Cx
+
+RC=rc
+
+# If you build 16-bit executables with MS Visual C++ v1.0/1.5 and link them
+# with the /KNOWEAS switch, you can build dual-mode MS-DOS/Win32 executables
+# by passing the -stub switch to the 32-bit linker to specify the 16-bit part.
+
+LD=link -nologo
+LDFLAGS=user32.lib advapi32.lib /OPT:NOWIN98 /INCREMENTAL:NO /PDB:$*.pdb $(EXTLIB)
+SYMS=/DEBUG:full /DEBUGTYPE:CV
+!IFDEF debug
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ELSE
+LDFLAGS=$(LDFLAGS) /RELEASE
+!IFDEF sym
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ENDIF
+!ENDIF
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj $(CRCA_O) globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj win32i64.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj crc32_.obj $(CRCA_O) globals.obj \
+ win32_.obj win32i64.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+win32i64.obj: win32/win32i64.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) -I. win32/win32i64.c
+
+win32zip.obj: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj: win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+crci386c.obj: win32/crc_i386.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) -I. -Fo$@ win32/crc_i386.c
+
+crc_i386.obj: win32/crc_i386.asm
+ $(AS) $(ASFLAGS) win32\crc_i386.asm
+
+match32.obj: win32/match32.asm
+ $(AS) $(ASFLAGS) win32\match32.asm
+
+zip.res: win32/zip.rc revision.h
+ $(RC) /l 0x409 /fo$@ /i win32 /d WIN32 win32/zip.rc
+
+zip.exe: $(OBJZ) $(OBJI) zip.res
+ $(LD) $(LDFLAGS) $(OBJZ) $(OBJI) zip.res
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC)
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS)
+
+clean:
+ -del *.obj
+ -del *.exe
diff --git a/win32/makefile.wat b/win32/makefile.wat
new file mode 100644
index 0000000..f13d580
--- /dev/null
+++ b/win32/makefile.wat
@@ -0,0 +1,197 @@
+# WMAKE makefile for Windows 95 and Windows NT (Intel only)
+# using Watcom C/C++ v11.0+, by Paul Kienitz, last revised 22 Jun 2008.
+# Makes Zip.exe, ZipNote.exe, ZipCloak.exe, and ZipSplit.exe.
+#
+# Invoke from Zip source dir with "WMAKE -F WIN32\MAKEFILE.WAT [targets]"
+# To build with debug info use "WMAKE DEBUG=1 ..."
+# To build without any assembly modules use "WMAKE NOASM=1 ..."
+#
+# Other options to be fed to the compiler can be specified in an environment
+# variable called LOCAL_ZIP. One possibility "-DDYN_ALLOC", but currently
+# this is not supported unless NOASM is also used.
+
+variation = $(%LOCAL_ZIP)
+
+# Stifle annoying "Delete this file?" questions when errors occur:
+.ERASE
+
+.EXTENSIONS:
+.EXTENSIONS: .exe .obj .c .h .asm
+
+# We maintain multiple sets of object files in different directories so that
+# we can compile msdos, dos/4gw, and win32 versions of Zip without their
+# object files interacting. The following var must be a directory name
+# ending with a backslash. All object file names must include this macro
+# at the beginning, for example "$(O)foo.obj".
+
+!ifdef DEBUG
+OBDIR = od32w
+!else
+OBDIR = ob32w
+!endif
+O = $(OBDIR)\ # comment here so backslash won't continue the line
+
+# The assembly hot-spot code in crc_i386.asm and match32.asm is optional.
+# This section controls its usage.
+
+!ifdef NOASM
+asmob =
+asmco =
+cvars = $+$(cvars)$- -DNO_ASM # otherwise ASM_CRC might default on!
+# "$+$(foo)$-" means expand foo as it has been defined up to now; normally,
+# this make defers inner expansion until the outer macro is expanded.
+!else # !NOASM
+asmco = $(O)crc_i386.obj
+asmob = $(asmco) $(O)match32.obj
+cvars = $+$(cvars)$- -DASMV -DASM_CRC
+!endif
+
+# Our object files. OBJZ is for Zip, OBJC is for ZipCloak, OBJN is for
+# ZipNote, and OBJS is for ZipSplit:
+
+OBJZ3 = $(O)zip.obj $(O)crypt.obj $(O)ttyio.obj $(O)trees.obj $(O)zipup.obj
+OBJZ2 = $(OBJZ3) $(O)util.obj $(O)zipfile.obj $(O)fileio.obj $(O)deflate.obj
+OBJZ1 = $(OBJZ2) $(O)globals.obj $(O)crc32.obj $(asmob)
+OBJZ = $(OBJZ1) $(O)win32zip.obj $(O)win32.obj $(O)win32i64.obj $(O)nt.obj
+
+OBJU1 = $(O)zipfile_.obj $(O)fileio_.obj $(O)util_.obj $(O)crc32_.obj $(asmco)
+OBJ_U = $(OBJU1) $(O)globals.obj $(O)win32_.obj $(O)win32i64_.obj
+
+OBJC = $(O)zipcloak.obj $(O)crypt_.obj $(O)ttyio.obj $(OBJ_U)
+
+OBJN = $(O)zipnote.obj $(OBJ_U)
+
+OBJS = $(O)zipsplit.obj $(OBJ_U)
+
+# Common header files included by all C sources:
+
+ZIP_H = zip.h ziperr.h tailor.h win32\osdep.h
+
+# Now we have to pick out the proper compiler and options for it.
+
+cc = wcc386
+link = wlink
+asm = wasm
+rc = wrc
+# Use Pentium Pro timings, register args, static strings in code:
+cflags = -bt=NT -6r -zt -zq
+aflags = -bt=NT -mf -3 -zq
+rcflags= -bt=NT -DWIN32 -iwin32 -q
+lflags = sys NT
+cvars = $+$(cvars)$- -DWIN32 $(variation)
+avars = $+$(avars)$- -DWATCOM_DSEG $(variation)
+
+# Specify optimizations, or a nonoptimized debugging version:
+
+!ifdef DEBUG
+cdebug = -od -d2
+ldebug = d w all op symf
+!else
+cdebug = -s -obhikl+rt -oe=100 -zp8
+# -oa helps slightly but might be dangerous.
+ldebug = op el
+!endif
+
+# How to compile sources:
+.c.obj:
+ $(cc) $(cdebug) $(cflags) $(cvars) $[@ -fo=$@
+
+# Here we go! By default, make all targets:
+all: Zip.exe ZipNote.exe ZipCloak.exe ZipSplit.exe
+
+# Convenient shorthand options for single targets:
+z: Zip.exe .SYMBOLIC
+n: ZipNote.exe .SYMBOLIC
+c: ZipCloak.exe .SYMBOLIC
+s: ZipSplit.exe .SYMBOLIC
+
+Zip.exe: $(OBDIR) $(OBJZ) $(O)zip.res
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJZ)}
+ $(rc) $(O)zip.res $@
+
+ZipNote.exe: $(OBDIR) $(OBJN)
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJN)}
+
+ZipCloak.exe: $(OBDIR) $(OBJC)
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJC)}
+
+ZipSplit.exe: $(OBDIR) $(OBJS)
+ $(link) $(lflags) $(ldebug) name $@ file {$(OBJS)}
+
+# Source dependencies:
+
+$(O)crc32.obj: crc32.c $(ZIP_H) crc32.h # only used if NOASM
+$(O)crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+$(O)deflate.obj: deflate.c $(ZIP_H)
+$(O)fileio.obj: fileio.c $(ZIP_H) crc32.h
+$(O)globals.obj: globals.c $(ZIP_H)
+$(O)trees.obj: trees.c $(ZIP_H)
+$(O)ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+$(O)util.obj: util.c $(ZIP_H)
+$(O)zip.obj: zip.c $(ZIP_H) crc32.h crypt.h revision.h ttyio.h
+$(O)zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+$(O)zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32\zipup.h
+$(O)zipnote.obj: zipnote.c $(ZIP_H) revision.h
+$(O)zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+$(O)zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+
+# Special case object files:
+
+$(O)win32.obj: win32\win32.c $(ZIP_H) win32\win32zip.h
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\win32.c -fo=$@
+
+$(O)win32i64.obj: win32\win32i64.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\win32i64.c -fo=$@
+
+$(O)win32zip.obj: win32\win32zip.c $(ZIP_H) win32\win32zip.h win32\nt.h
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\win32zip.c -fo=$@
+
+$(O)nt.obj: win32\nt.c $(ZIP_H) win32\nt.h
+ $(cc) $(cdebug) $(cflags) $(cvars) win32\nt.c -fo=$@
+
+$(O)match32.obj: win32\match32.asm
+ $(asm) $(aflags) $(avars) win32\match32.asm -fo=$@
+
+$(O)crc_i386.obj: win32\crc_i386.asm
+ $(asm) $(aflags) $(avars) win32\crc_i386.asm -fo=$@
+
+# Variant object files for ZipNote, ZipCloak, and ZipSplit:
+
+$(O)zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL zipfile.c -fo=$@
+
+$(O)fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL fileio.c -fo=$@
+
+$(O)util_.obj: util.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL util.c -fo=$@
+
+$(O)crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crc32.c -fo=$@
+
+$(O)crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL crypt.c -fo=$@
+
+$(O)win32_.obj: win32\win32.c $(ZIP_H) win32\win32zip.h
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32.c -fo=$@
+
+$(O)win32i64_.obj: win32\win32i64.c $(ZIP_H)
+ $(cc) $(cdebug) $(cflags) $(cvars) -DUTIL win32\win32i64.c -fo=$@
+
+$(O)zip.res: win32\zip.rc revision.h
+ $(rc) -r $(rcflags) -fo=$@ win32\zip.rc
+
+# Creation of subdirectory for intermediate files
+$(OBDIR):
+ -mkdir $@
+
+# Unwanted file removal:
+
+clean: .SYMBOLIC
+ del $(O)*.obj
+
+cleaner: clean .SYMBOLIC
+ del Zip.exe
+ del ZipNote.exe
+ del ZipCloak.exe
+ del ZipSplit.exe
diff --git a/win32/makenoas.w32 b/win32/makenoas.w32
new file mode 100644
index 0000000..403b087
--- /dev/null
+++ b/win32/makenoas.w32
@@ -0,0 +1,219 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for
+# 32-bit Microsoft Visual C++
+
+# To use, do "nmake -f makefile.w32"
+
+# This version disables assembly.
+# Add -DNO_ASM to CFLAGS and comment out the ASMOBJS definition if
+# you do not have masm 6.1X.
+
+# Optional nonstandard preprocessor flags (as -DMEDIUM_MEM or -DNO_ASM)
+# should be added to the environment via "set LOCAL_ZIP=-DFOO" or added
+# to the declaration of LOC here:
+LOC = $(LOCAL_ZIP)
+
+!IFNDEF debug
+NODEBUG=1
+!ENDIF
+
+# Uncomment the following macro to use the optimized assembler
+# routines in Zip:
+#ASMOBJS = match32.obj
+CRCA_O = crci386c.obj
+CFLG_ASM = -DASM_CRC
+
+!IFDEF USEBZ2
+LOC=$(LOC) -DBZIP2_SUPPORT
+!IFNDEF debug
+EXTLIB=$(EXTLIB) libbz2.lib
+!ELSE
+EXTLIB=$(EXTLIB) libbz2.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+LOC=$(LOC) -DUSE_ZLIB
+ASMOBJS=
+!IFNDEF debug
+EXTLIB=$(EXTLIB) zlib.lib
+!ELSE
+EXTLIB=$(EXTLIB) zlib.lib
+!ENDIF
+!ENDIF
+
+!IFDEF USEZLIB
+USE_MSVCRT=1
+!ELSE
+!IFDEF USEBZIP2
+USE_MSVCRT=1
+!ELSE
+USE_MSVCRT=0
+!ENDIF
+!ENDIF # USEZLIB
+
+!IF $(USE_MSVCRT) == 1
+CRTLIB=-MD
+!ELSE
+!IF "$(VS80COMNTOOLS)" == ""
+CRTLIB=-ML
+!ELSE
+# no single-threaded CRT static lib, only multi-threaded in VC8
+CRTLIB=-MT
+!ENDIF
+!ENDIF
+
+!IFDEF NODEBUG
+cdebug = -O2
+cdbgsz = -O1
+!ELSE
+cdebug = -Od
+cdbgsz = $(cdebug)
+!ENDIF
+
+# ------------- 32-bit Microsoft Visual C++ -------------
+CC=cl -nologo
+CFLAGS=-W3 $(cdebug) -DWIN32 $(CFLG_ASM) $(CRTLIB) $(LOC) -DNO_ASM
+UTILFLAGS=$(CFLAGS) -DUTIL -Fo$@
+
+# Remove "-coff" from ASFLAGS if you do not have MASM 6.11.
+
+AS=ml -nologo
+ASFLAGS=-c -coff -Cx
+
+RC=rc
+
+# If you build 16-bit executables with MS Visual C++ v1.0/1.5 and link them
+# with the /KNOWEAS switch, you can build dual-mode MS-DOS/Win32 executables
+# by passing the -stub switch to the 32-bit linker to specify the 16-bit part.
+
+LD=link -nologo
+LDFLAGS=user32.lib advapi32.lib /OPT:NOWIN98 /INCREMENTAL:NO /PDB:$*.pdb $(EXTLIB)
+SYMS=/DEBUG:full /DEBUGTYPE:CV
+!IFDEF debug
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ELSE
+LDFLAGS=$(LDFLAGS) /RELEASE
+!IFDEF sym
+LDFLAGS=$(LDFLAGS) $(SYMS)
+CFLAGS=$(CFLAGS) /Zi
+!ENDIF
+!ENDIF
+
+# variables
+OBJZ = zip.obj crypt.obj ttyio.obj zipfile.obj zipup.obj fileio.obj util.obj \
+ crc32.obj $(CRCA_O) globals.obj
+
+OBJI = deflate.obj trees.obj $(ASMOBJS) win32.obj win32zip.obj nt.obj win32i64.obj
+
+OBJU = zipfile_.obj fileio_.obj util_.obj crc32_.obj $(CRCA_O) globals.obj \
+ win32_.obj win32i64.obj
+OBJN = zipnote.obj $(OBJU)
+OBJC = zipcloak.obj crypt_.obj ttyio.obj $(OBJU)
+OBJS = zipsplit.obj $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h win32/osdep.h
+
+ZIPS = zip.exe zipnote.exe zipsplit.exe zipcloak.exe
+
+zips: $(ZIPS)
+
+zip.obj: zip.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipup.obj: zipup.c $(ZIP_H) revision.h crc32.h crypt.h win32/zipup.h
+ $(CC) -c $(CFLAGS) $*.c
+
+fileio.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+util.obj: util.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+globals.obj: globals.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+deflate.obj: deflate.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+trees.obj: trees.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) $*.c
+
+crc32.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) $*.c
+
+crypt.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+ttyio.obj: ttyio.c $(ZIP_H) crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+win32i64.obj: win32/win32i64.c $(ZIP_H)
+ $(CC) -c $(CFLAGS) -I. win32/win32i64.c
+
+win32zip.obj: win32/win32zip.c $(ZIP_H) win32/win32zip.h win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/win32zip.c
+
+win32.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(CFLAGS) -I. win32/win32.c
+
+nt.obj: win32/nt.c $(ZIP_H) win32/nt.h
+ $(CC) -c $(CFLAGS) -I. win32/nt.c
+
+zipcloak.obj: zipcloak.c $(ZIP_H) revision.h crc32.h crypt.h ttyio.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipnote.obj: zipnote.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipsplit.obj: zipsplit.c $(ZIP_H) revision.h
+ $(CC) -c $(CFLAGS) $*.c
+
+zipfile_.obj: zipfile.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) zipfile.c
+
+fileio_.obj: fileio.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) fileio.c
+
+util_.obj: util.c $(ZIP_H)
+ $(CC) -c $(UTILFLAGS) util.c
+
+crc32_.obj: crc32.c $(ZIP_H) crc32.h
+ $(CC) -c $(UTILFLAGS) crc32.c
+
+crypt_.obj: crypt.c $(ZIP_H) crypt.h crc32.h ttyio.h
+ $(CC) -c $(UTILFLAGS) crypt.c
+
+win32_.obj: win32/win32.c $(ZIP_H) win32/win32zip.h
+ $(CC) -c $(UTILFLAGS) -I. win32/win32.c
+
+crci386c.obj: win32/crc_i386.c $(ZIP_H) crc32.h
+ $(CC) -c $(CFLAGS) -I. -Fo$@ win32/crc_i386.c
+
+crc_i386.obj: win32/crc_i386.asm
+ $(AS) $(ASFLAGS) win32\crc_i386.asm
+
+match32.obj: win32/match32.asm
+ $(AS) $(ASFLAGS) win32\match32.asm
+
+zip.res: win32/zip.rc revision.h
+ $(RC) /l 0x409 /fo$@ /i win32 /d WIN32 win32/zip.rc
+
+zip.exe: $(OBJZ) $(OBJI) zip.res
+ $(LD) $(LDFLAGS) $(OBJZ) $(OBJI) zip.res
+
+zipcloak.exe: $(OBJC)
+ $(LD) $(LDFLAGS) $(OBJC)
+
+zipnote.exe: $(OBJN)
+ $(LD) $(LDFLAGS) $(OBJN)
+
+zipsplit.exe: $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJS)
+
+clean:
+ -del *.obj
+ -del *.exe
diff --git a/win32/match32.asm b/win32/match32.asm
new file mode 100644
index 0000000..81db41f
--- /dev/null
+++ b/win32/match32.asm
@@ -0,0 +1,192 @@
+;===========================================================================
+; Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2005-Feb-10 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+;
+; match32.asm by Jean-loup Gailly.
+
+; match32.asm, optimized version of longest_match() in deflate.c
+; To be used only with 32 bit flat model. To simplify the code, the option
+; -DDYN_ALLOC is not supported.
+; This file is only optional. If you don't have an assembler, use the
+; C version (add -DNO_ASM to CFLAGS in makefile and remove match.o
+; from OBJI). If you have reduced WSIZE in zip.h, then make sure this is
+; assembled with an equivalent -DWSIZE=<whatever>.
+;
+; Win32 (Windows NT) version - 1994/04/13 by Steve Salisbury
+; * works with Microsoft MASM 6.1X and Microsoft Visual C++ / 32-bit edition
+;
+; Adapted to work with Borland Turbo Assembler 5.0 by Cosmin Truta, 1997
+;
+; Adapted to work with OpenWatcom WASM by Chr. Spieler, 2005
+; (Define the symbol WATCOM_DSEG to activate the specific Watcom C
+; data segment naming convention.)
+;
+;==============================================================================
+;
+; Do NOT assemble this source if external crc32 routine from zlib gets used.
+;
+ IFNDEF USE_ZLIB
+;
+ .386p
+ ifdef ASM_NEW
+ .MODEL FLAT
+ endif
+
+ name match
+
+ ifdef ASM_NEW
+_BSS segment public use32
+ else
+_BSS segment public use32 'DATA'
+ endif
+ extrn _match_start : dword
+ extrn _prev_length : dword
+ extrn _good_match : dword
+ ifndef FULL_SEARCH
+ extrn _nice_match : dword
+ endif
+ extrn _strstart : dword
+ extrn _max_chain_length : dword
+ extrn _prev : word
+ extrn _window : byte
+_BSS ends
+
+ ifdef WATCOM_DSEG
+DGROUP group _BSS
+ endif
+
+ ifdef ASM_NEW
+_TEXT segment public use32
+ else
+_TEXT segment para public use32 'CODE'
+ endif
+ assume CS: _TEXT
+ assume DS: _BSS, ES: _BSS, FS: _BSS
+ public _match_init
+ public _longest_match
+
+ ifndef WSIZE
+ WSIZE equ 32768 ; keep in sync with zip.h !
+ endif
+ MIN_MATCH equ 3
+ MAX_MATCH equ 258
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+ MAX_DIST equ (WSIZE-MIN_LOOKAHEAD)
+
+; initialize or check the variables used in match.asm.
+
+_match_init proc near
+ ret
+_match_init endp
+
+; -----------------------------------------------------------------------
+; Set match_start to the longest match starting at the given string and
+; return its length. Matches shorter or equal to prev_length are discarded,
+; in which case the result is equal to prev_length and match_start is
+; garbage.
+; IN assertions: cur_match is the head of the hash chain for the current
+; string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+
+; int longest_match(cur_match)
+
+_longest_match proc near
+
+ cur_match equ dword ptr [esp+20]
+ ; return address ; esp+16
+ push ebp ; esp+12
+ push edi ; esp+8
+ push esi ; esp+4
+ push ebx ; esp
+
+; match equ esi
+; scan equ edi
+; chain_length equ ebp
+; best_len equ ebx
+; limit equ edx
+
+ mov esi,cur_match
+ mov edx,_strstart
+ mov ebp,_max_chain_length ; chain_length = max_chain_length
+ mov edi,edx
+ sub edx,MAX_DIST ; limit = strstart-MAX_DIST
+ cld ; string ops increment esi and edi
+ jae short limit_ok
+ sub edx,edx ; limit = NIL
+limit_ok:
+ add edi,2+offset _window ; edi = offset(window + strstart + 2)
+ mov ebx,_prev_length ; best_len = prev_length
+ mov cx,[edi-2] ; cx = scan[0..1]
+ mov ax,[ebx+edi-3] ; ax = scan[best_len-1..best_len]
+ cmp ebx,_good_match ; do we have a good match already?
+ jb short do_scan
+ shr ebp,2 ; chain_length >>= 2
+ jmp short do_scan
+
+ align 4 ; align destination of branch
+long_loop:
+; at this point, edi == scan+2, esi == cur_match
+ mov ax,[ebx+edi-3] ; ax = scan[best_len-1..best_len]
+ mov cx,[edi-2] ; cx = scan[0..1]
+short_loop:
+; at this point, edi == scan+2, esi == cur_match,
+; ax = scan[best_len-1..best_len] and cx = scan[0..1]
+ and esi,WSIZE-1
+ dec ebp ; --chain_length
+ mov si,_prev[esi+esi] ; cur_match = prev[cur_match]
+ ; top word of esi is still 0
+ jz short the_end
+ cmp esi,edx ; cur_match <= limit ?
+ jbe short the_end
+do_scan:
+ cmp ax,word ptr _window[ebx+esi-1] ; check match at best_len-1
+ jne short_loop
+ cmp cx,word ptr _window[esi] ; check min_match_length match
+ jne short_loop
+
+ lea esi,_window[esi+2] ; esi = match
+ mov ecx,(MAX_MATCH-2)/2 ; scan for at most MAX_MATCH bytes
+ mov eax,edi ; eax = scan+2
+ repe cmpsw ; loop until mismatch
+ je short maxmatch ; match of length MAX_MATCH?
+mismatch:
+ mov cl,[edi-2] ; mismatch on first or second byte?
+ xchg eax,edi ; edi = scan+2, eax = end of scan
+ sub cl,[esi-2] ; cl = 0 if first bytes equal
+ sub eax,edi ; eax = len
+ sub esi,2+offset _window ; esi = match - (2 + offset(window))
+ sub esi,eax ; esi = cur_match (= match - len)
+ sub cl,1 ; set carry if cl == 0 (can't use DEC)
+ adc eax,0 ; eax = carry ? len+1 : len
+ cmp eax,ebx ; len > best_len ?
+ jle long_loop
+ mov _match_start,esi ; match_start = cur_match
+ mov ebx,eax ; ebx = best_len = len
+ ifdef FULL_SEARCH
+ cmp eax,MAX_MATCH ; len >= MAX_MATCH ?
+ else
+ cmp eax,_nice_match ; len >= nice_match ?
+ endif
+ jl long_loop
+the_end:
+ mov eax,ebx ; result = eax = best_len
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+maxmatch: ; come here if maximum match
+ cmpsb ; increment esi and edi
+ jmp mismatch ; force match_length = MAX_LENGTH
+
+_longest_match endp
+
+_TEXT ends
+;
+ ENDIF ; !USE_ZLIB
+;
+end
diff --git a/win32/nt.c b/win32/nt.c
new file mode 100644
index 0000000..aa0529f
--- /dev/null
+++ b/win32/nt.c
@@ -0,0 +1,492 @@
+/*
+ win32/nt.c - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*++
+
+Copyright (c) 1996 Scott Field
+
+Module Name:
+
+ nt.c (formerly nt_zip.c)
+
+Abstract:
+
+ This module implements WinNT security descriptor operations for the
+ Win32 Info-ZIP project. Operation such as querying file security,
+ using/querying local and remote privileges. The contents of this module
+ are only relevant when the code is running on Windows NT, and the target
+ volume supports persistent Acl storage.
+
+ User privileges that allow accessing certain privileged aspects of the
+ security descriptor (such as the Sacl) are only used if the user specified
+ to do so.
+
+ In the future, this module may be expanded to support storage of
+ OS/2 EA data, Macintosh resource forks, and hard links, which are all
+ supported by NTFS.
+
+Author:
+
+ Scott Field (sfield@microsoft.com) 27-Sep-96
+
+--*/
+
+#include "../zip.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#ifdef __RSXNT__
+# include "../win32/rsxntwin.h"
+#endif
+#include "../win32/nt.h"
+
+#ifdef NTSD_EAS /* This file is only needed for NTSD handling */
+
+/* Borland C++ does not define FILE_SHARE_DELETE. Others also? */
+#ifndef FILE_SHARE_DELETE
+# define FILE_SHARE_DELETE 0x00000004
+#endif
+
+/* This macro definition is missing in old versions of MS' winbase.h. */
+#ifndef InterlockedExchangePointer
+# define InterlockedExchangePointer(Target, Value) \
+ (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
+#endif
+
+/* private prototypes */
+
+static BOOL Initialize(VOID);
+#if 0 /* currently unused */
+static BOOL Shutdown(VOID);
+#endif
+static VOID GetRemotePrivilegesGet(CHAR *FileName, PDWORD dwRemotePrivileges);
+static VOID InitLocalPrivileges(VOID);
+
+
+BOOL bZipInitialized = FALSE; /* module level stuff initialized? */
+HANDLE hZipInitMutex = NULL; /* prevent multiple initialization */
+
+BOOL g_bBackupPrivilege = FALSE; /* for local get file security override */
+BOOL g_bZipSaclPrivilege = FALSE; /* for local get sacl operations, only when
+ backup privilege not present */
+
+/* our single cached volume capabilities structure that describes the last
+ volume root we encountered. A single entry like this works well in the
+ zip/unzip scenario for a number of reasons:
+ 1. typically one extraction path during unzip.
+ 2. typically process one volume at a time during zip, and then move
+ on to the next.
+ 3. no cleanup code required and no memory leaks.
+ 4. simple code.
+
+ This approach should be reworked to a linked list approach if we expect to
+ be called by many threads which are processing a variety of input/output
+ volumes, since lock contention and stale data may become a bottleneck. */
+
+VOLUMECAPS g_VolumeCaps;
+CRITICAL_SECTION VolumeCapsLock;
+
+
+static BOOL Initialize(VOID)
+{
+ HANDLE hMutex;
+ HANDLE hOldMutex;
+
+ if(bZipInitialized) return TRUE;
+
+ hMutex = CreateMutex(NULL, TRUE, NULL);
+ if(hMutex == NULL) return FALSE;
+
+ hOldMutex = (HANDLE)InterlockedExchangePointer((void *)&hZipInitMutex,
+ hMutex);
+
+ if(hOldMutex != NULL) {
+ /* somebody setup the mutex already */
+ InterlockedExchangePointer((void *)&hZipInitMutex,
+ hOldMutex);
+
+ CloseHandle(hMutex); /* close new, un-needed mutex */
+
+ /* wait for initialization to complete and return status */
+ WaitForSingleObject(hOldMutex, INFINITE);
+ ReleaseMutex(hOldMutex);
+
+ return bZipInitialized;
+ }
+
+ /* initialize module level resources */
+
+ InitializeCriticalSection( &VolumeCapsLock );
+ memset(&g_VolumeCaps, 0, sizeof(VOLUMECAPS));
+
+ InitLocalPrivileges();
+
+ bZipInitialized = TRUE;
+
+ ReleaseMutex(hMutex); /* release correct mutex */
+
+ return TRUE;
+}
+
+#if 0 /* currently not used ! */
+static BOOL Shutdown(VOID)
+{
+ /* really need to free critical sections, disable enabled privilges, etc,
+ but doing so brings up possibility of race conditions if those resources
+ are about to be used. The easiest way to handle this is let these
+ resources be freed when the process terminates... */
+
+ return TRUE;
+}
+#endif /* never */
+
+
+static VOID GetRemotePrivilegesGet(char *FileName, PDWORD dwRemotePrivileges)
+{
+ HANDLE hFile;
+
+ *dwRemotePrivileges = 0;
+
+ /* see if we have the SeBackupPrivilege */
+
+ hFile = CreateFileA(
+ FileName,
+ ACCESS_SYSTEM_SECURITY | GENERIC_READ | READ_CONTROL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ if(hFile != INVALID_HANDLE_VALUE) {
+ /* no remote way to determine SeBackupPrivilege -- just try a read
+ to simulate it */
+ SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+ PSECURITY_DESCRIPTOR sd;
+ DWORD cbBuf = 0;
+
+ GetKernelObjectSecurity(hFile, si, NULL, cbBuf, &cbBuf);
+
+ if(ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
+ if((sd = HeapAlloc(GetProcessHeap(), 0, cbBuf)) != NULL) {
+ if(GetKernelObjectSecurity(hFile, si, sd, cbBuf, &cbBuf)) {
+ *dwRemotePrivileges |= OVERRIDE_BACKUP;
+ }
+ HeapFree(GetProcessHeap(), 0, sd);
+ }
+ }
+
+ CloseHandle(hFile);
+ } else {
+
+ /* see if we have the SeSecurityPrivilege */
+ /* note we don't need this if we have SeBackupPrivilege */
+
+ hFile = CreateFileA(
+ FileName,
+ ACCESS_SYSTEM_SECURITY,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* maximum sharing */
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if(hFile != INVALID_HANDLE_VALUE) {
+ CloseHandle(hFile);
+ *dwRemotePrivileges |= OVERRIDE_SACL;
+ }
+ }
+}
+
+
+BOOL ZipGetVolumeCaps(
+ char *rootpath, /* filepath, or NULL */
+ char *name, /* filename associated with rootpath */
+ PVOLUMECAPS VolumeCaps /* result structure describing capabilities */
+ )
+{
+ char TempRootPath[MAX_PATH + 1];
+ DWORD cchTempRootPath = 0;
+ BOOL bSuccess = TRUE; /* assume success until told otherwise */
+
+ if(!bZipInitialized) if(!Initialize()) return FALSE;
+
+ /* process the input path to produce a consistent path suitable for
+ compare operations and also suitable for certain picky Win32 API
+ that don't like forward slashes */
+
+ if(rootpath != NULL && rootpath[0] != '\0') {
+ DWORD i;
+
+ cchTempRootPath = lstrlen(rootpath);
+ if(cchTempRootPath > MAX_PATH) return FALSE;
+
+ /* copy input, converting forward slashes to back slashes as we go */
+
+ for(i = 0 ; i <= cchTempRootPath ; i++) {
+ if(rootpath[i] == '/') TempRootPath[i] = '\\';
+ else TempRootPath[i] = rootpath[i];
+ }
+
+ /* check for UNC and Null terminate or append trailing \ as appropriate */
+
+ /* possible valid UNCs we are passed follow:
+ \\machine\foo\bar (path is \\machine\foo\)
+ \\machine\foo (path is \\machine\foo\)
+ \\machine\foo\
+ \\.\c$\ (FIXFIX: Win32API doesn't like this - GetComputerName())
+ LATERLATER: handling mounted DFS drives in the future will require
+ slightly different logic which isn't available today.
+ This is required because directories can point at
+ different servers which have differing capabilities.
+ */
+
+ if(TempRootPath[0] == '\\' && TempRootPath[1] == '\\') {
+ DWORD slash = 0;
+
+ for(i = 2 ; i < cchTempRootPath ; i++) {
+ if(TempRootPath[i] == '\\') {
+ slash++;
+
+ if(slash == 2) {
+ i++;
+ TempRootPath[i] = '\0';
+ cchTempRootPath = i;
+ break;
+ }
+ }
+ }
+
+ /* if there was only one slash found, just tack another onto the end */
+
+ if(slash == 1 && TempRootPath[cchTempRootPath] != '\\') {
+ TempRootPath[cchTempRootPath] = TempRootPath[0]; /* '\' */
+ TempRootPath[cchTempRootPath+1] = '\0';
+ cchTempRootPath++;
+ }
+
+ } else {
+
+ if(TempRootPath[1] == ':') {
+
+ /* drive letter specified, truncate to root */
+ TempRootPath[2] = '\\';
+ TempRootPath[3] = '\0';
+ cchTempRootPath = 3;
+ } else {
+
+ /* must be file on current drive */
+ TempRootPath[0] = '\0';
+ cchTempRootPath = 0;
+ }
+
+ }
+
+ } /* if path != NULL */
+
+ /* grab lock protecting cached entry */
+ EnterCriticalSection( &VolumeCapsLock );
+
+ if(!g_VolumeCaps.bValid || lstrcmpi(g_VolumeCaps.RootPath, TempRootPath) != 0) {
+
+ /* no match found, build up new entry */
+
+ DWORD dwFileSystemFlags;
+ DWORD dwRemotePrivileges = 0;
+ BOOL bRemote = FALSE;
+
+ /* release lock during expensive operations */
+ LeaveCriticalSection( &VolumeCapsLock );
+
+ bSuccess = GetVolumeInformation(
+ (TempRootPath[0] == '\0') ? NULL : TempRootPath,
+ NULL, 0,
+ NULL, NULL,
+ &dwFileSystemFlags,
+ NULL, 0);
+
+ /* only if target volume supports Acls, and we were told to use
+ privileges do we need to go out and test for the remote case */
+
+ if(bSuccess && (dwFileSystemFlags & FS_PERSISTENT_ACLS) && VolumeCaps->bUsePrivileges) {
+ if(GetDriveType( (TempRootPath[0] == '\0') ? NULL : TempRootPath ) == DRIVE_REMOTE) {
+ bRemote = TRUE;
+
+ /* make a determination about our remote capabilities */
+
+ GetRemotePrivilegesGet(name, &dwRemotePrivileges);
+ }
+ }
+
+ /* always take the lock again, since we release it below */
+ EnterCriticalSection( &VolumeCapsLock );
+
+ /* replace the existing data if successful */
+ if(bSuccess) {
+
+ lstrcpynA(g_VolumeCaps.RootPath, TempRootPath, cchTempRootPath+1);
+ g_VolumeCaps.bProcessDefer = FALSE;
+ g_VolumeCaps.dwFileSystemFlags = dwFileSystemFlags;
+ g_VolumeCaps.bRemote = bRemote;
+ g_VolumeCaps.dwRemotePrivileges = dwRemotePrivileges;
+ g_VolumeCaps.bValid = TRUE;
+ }
+ }
+
+ if(bSuccess) {
+ /* copy input elements */
+ g_VolumeCaps.bUsePrivileges = VolumeCaps->bUsePrivileges;
+ g_VolumeCaps.dwFileAttributes = VolumeCaps->dwFileAttributes;
+
+ /* give caller results */
+ memcpy(VolumeCaps, &g_VolumeCaps, sizeof(VOLUMECAPS));
+ } else {
+ g_VolumeCaps.bValid = FALSE;
+ }
+
+ LeaveCriticalSection( &VolumeCapsLock ); /* release lock */
+
+ return bSuccess;
+}
+
+BOOL SecurityGet(
+ char *resource,
+ PVOLUMECAPS VolumeCaps,
+ unsigned char *buffer,
+ DWORD *cbBuffer
+ )
+{
+ HANDLE hFile;
+ DWORD dwDesiredAccess;
+ DWORD dwFlags;
+ PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)buffer;
+ SECURITY_INFORMATION RequestedInfo;
+ BOOL bBackupPrivilege = FALSE;
+ BOOL bSaclPrivilege = FALSE;
+ BOOL bSuccess = FALSE;
+
+ DWORD cchResourceLen;
+
+ if(!bZipInitialized) if(!Initialize()) return FALSE;
+
+ /* see if we are dealing with a directory */
+ /* rely on the fact resource has a trailing [back]slash, rather
+ than calling expensive GetFileAttributes() */
+
+ cchResourceLen = lstrlenA(resource);
+
+ if(resource[cchResourceLen-1] == '/' || resource[cchResourceLen-1] == '\\')
+ VolumeCaps->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+
+ /* setup privilege usage based on if told we can use privileges, and if so,
+ what privileges we have */
+
+ if(VolumeCaps->bUsePrivileges) {
+ if(VolumeCaps->bRemote) {
+ /* use remotely determined privileges */
+ if(VolumeCaps->dwRemotePrivileges & OVERRIDE_BACKUP)
+ bBackupPrivilege = TRUE;
+
+ if(VolumeCaps->dwRemotePrivileges & OVERRIDE_SACL)
+ bSaclPrivilege = TRUE;
+ } else {
+ /* use local privileges */
+ bBackupPrivilege = g_bBackupPrivilege;
+ bSaclPrivilege = g_bZipSaclPrivilege;
+ }
+ }
+
+ /* always try to read the basic security information: Dacl, Owner, Group */
+
+ dwDesiredAccess = READ_CONTROL;
+
+ RequestedInfo = OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION;
+
+ /* if we have the SeBackupPrivilege or SeSystemSecurityPrivilege, read
+ the Sacl, too */
+
+ if(bBackupPrivilege || bSaclPrivilege) {
+ dwDesiredAccess |= ACCESS_SYSTEM_SECURITY;
+ RequestedInfo |= SACL_SECURITY_INFORMATION;
+ }
+
+ dwFlags = 0;
+
+ /* if we have the backup privilege, specify that */
+ /* opening a directory requires FILE_FLAG_BACKUP_SEMANTICS */
+
+ if(bBackupPrivilege || (VolumeCaps->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ dwFlags |= FILE_FLAG_BACKUP_SEMANTICS;
+
+ hFile = CreateFileA(
+ resource,
+ dwDesiredAccess,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* maximum sharing */
+ NULL,
+ OPEN_EXISTING,
+ dwFlags,
+ NULL
+ );
+
+ if(hFile == INVALID_HANDLE_VALUE) return FALSE;
+
+ if(GetKernelObjectSecurity(hFile, RequestedInfo, sd, *cbBuffer, cbBuffer)) {
+ *cbBuffer = GetSecurityDescriptorLength( sd );
+ bSuccess = TRUE;
+ }
+
+ CloseHandle(hFile);
+
+ return bSuccess;
+}
+
+static VOID InitLocalPrivileges(VOID)
+{
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tp;
+
+ /* try to enable some interesting privileges that give us the ability
+ to get some security information that we normally cannot.
+
+ note that enabling privileges is only relevant on the local machine;
+ when accessing files that are on a remote machine, any privileges
+ that are present on the remote machine get enabled by default. */
+
+ if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
+ return;
+
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ /* try to enable SeBackupPrivilege.
+ if this succeeds, we can read all aspects of the security descriptor */
+
+ if(LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &tp.Privileges[0].Luid)) {
+ if(AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) &&
+ GetLastError() == ERROR_SUCCESS) g_bBackupPrivilege = TRUE;
+ }
+
+ /* try to enable SeSystemSecurityPrivilege if SeBackupPrivilege not present.
+ if this succeeds, we can read the Sacl */
+
+ if(!g_bBackupPrivilege &&
+ LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) {
+
+ if(AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) &&
+ GetLastError() == ERROR_SUCCESS) g_bZipSaclPrivilege = TRUE;
+ }
+
+ CloseHandle(hToken);
+}
+#endif /* NTSD_EAS */
diff --git a/win32/nt.h b/win32/nt.h
new file mode 100644
index 0000000..f722530
--- /dev/null
+++ b/win32/nt.h
@@ -0,0 +1,75 @@
+/*
+ win32/nt.h - Zip 3
+
+ Copyright (c) 1990-2003 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2003-May-08 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _NT_ZIP_H
+#define _NT_ZIP_H
+
+/* central header for EF_NTSD "SD" extra field */
+
+#define EF_NTSD_MAX_VER_SUPPORT (0)
+ /* describes maximum ver# we know how to handle */
+
+typedef struct
+{
+ USHORT nID;
+ USHORT nSize;
+ ULONG lSize;
+}
+EF_NTSD_C_HEADER, *PEF_NTSD_C_HEADER;
+
+#define EF_NTSD_C_LEN (sizeof(EF_NTSD_C_HEADER))
+
+/* local header for EF_NTSD "SD" extra field */
+
+#pragma pack(1) /* bytes following structure immediately follow BYTE Version */
+
+typedef struct
+{
+ USHORT nID; /* tag for this extra block type */
+ USHORT nSize; /* total data size for this block */
+ ULONG lSize; /* uncompressed security descriptor data size */
+ BYTE Version; /* Version of uncompressed security descriptor data format */
+}
+IZ_PACKED EF_NTSD_L_HEADER, *PEF_NTSD_L_HEADER;
+
+#pragma pack()
+
+/* ...followed by... */
+/* SHORT CType; compression type */
+/* ULONG EACRC; CRC value for uncompressed security descriptor data */
+/* <var.> Variable length data */
+
+
+#define EF_NTSD_L_LEN (EF_NTSD_C_LEN + sizeof(BYTE))
+ /* avoid alignment size computation */
+
+#define NTSD_BUFFERSIZE (1024) /* threshold to cause malloc() */
+
+#define OVERRIDE_BACKUP 1 /* we have SeBackupPrivilege on remote */
+#define OVERRIDE_RESTORE 2 /* we have SeRestorePrivilege on remote */
+#define OVERRIDE_SACL 4 /* we have SeSystemSecurityPrivilege on remote */
+
+typedef struct {
+ BOOL bValid; /* are our contents valid? */
+ BOOL bProcessDefer; /* process deferred entry yet? */
+ BOOL bUsePrivileges; /* use privilege overrides? */
+ DWORD dwFileSystemFlags; /* describes target file system */
+ BOOL bRemote; /* is volume remote? */
+ DWORD dwRemotePrivileges; /* relevant only on remote volumes */
+ DWORD dwFileAttributes;
+ char RootPath[MAX_PATH+1]; /* path to network / filesystem */
+} VOLUMECAPS, *PVOLUMECAPS, *LPVOLUMECAPS;
+
+BOOL SecurityGet(char *resource, PVOLUMECAPS VolumeCaps, unsigned char *buffer,
+ DWORD *cbBuffer);
+BOOL ZipGetVolumeCaps(char *rootpath, char *name, PVOLUMECAPS VolumeCaps);
+
+#endif /* _NT_ZIP_H */
+
diff --git a/win32/osdep.h b/win32/osdep.h
new file mode 100644
index 0000000..eaf6507
--- /dev/null
+++ b/win32/osdep.h
@@ -0,0 +1,617 @@
+/*
+ win32/osdep.h
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/* Automatic setting of the common Microsoft C idenfifier MSC.
+ * NOTE: Watcom also defines M_I*86 !
+ */
+#if defined(_MSC_VER) || (defined(M_I86) && !defined(__WATCOMC__))
+# ifndef MSC
+# define MSC /* This should work for older MSC, too! */
+# endif
+#endif
+
+/* Tell Microsoft Visual C++ 2005 to leave us alone and
+ * let us use standard C functions the way we're supposed to.
+ */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+# ifndef _CRT_SECURE_NO_DEPRECATE
+# define _CRT_SECURE_NO_DEPRECATE
+# endif
+# ifndef _CRT_NONSTDC_NO_DEPRECATE
+# define _CRT_NONSTDC_NO_DEPRECATE
+# endif
+#endif
+
+#if defined(__WATCOMC__) && defined(__386__)
+# define WATCOMC_386
+#endif
+
+#if (defined(__CYGWIN32__) && !defined(__CYGWIN__))
+# define __CYGWIN__ /* compatibility for CygWin B19 and older */
+#endif
+
+/* enable multibyte character set support by default */
+#ifndef _MBCS
+# define _MBCS
+#endif
+#if defined(__CYGWIN__)
+# undef _MBCS
+#endif
+
+/* Get types and stat */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h>
+
+#ifndef MSDOS
+/*
+ * Windows 95 (and Windows NT) file systems are (to some extend)
+ * extensions of MSDOS. Common features include for example:
+ * FAT or (FAT like) file systems,
+ * '\\' as directory separator in paths,
+ * "\r\n" as record (line) terminator in text files, ...
+ */
+# define MSDOS
+/* inherit MS-DOS file system etc. stuff */
+#endif
+
+#define USE_CASE_MAP
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, filter_match_case))
+#define BROKEN_FSEEK
+#ifndef __RSXNT__
+# define HAVE_FSEEKABLE
+#endif
+
+
+/* popen
+ *
+ * On Win32 must map to _popen() and _pclose()
+ */
+#define popen _popen
+#define pclose _pclose
+
+/* WIN32_OEM
+ *
+ * This enables storing paths in archives on WIN32 in OEM format
+ * which is more work but seems the standard now. It also enables
+ * converting paths in read DOS archives from assumed OEM to ANSI.
+ */
+#ifndef NO_WIN32_OEM
+# define WIN32_OEM
+#endif
+
+/* Large File Support
+ *
+ * If this is set it is assumed that the port
+ * supports 64-bit file calls. The types are
+ * defined here. Any local implementations are
+ * in Win32.c and the prototypes for the calls are
+ * in tailor.h. Note that a port must support
+ * these calls fully or should not set
+ * LARGE_FILE_SUPPORT.
+ */
+
+/* Note also that ZOFF_T_FORMAT_SIZE_PREFIX has to be defined here
+ or tailor.h will define defaults */
+
+/* If port has LARGE_FILE_SUPPORT then define here
+ to make large file support automatic unless overridden */
+
+
+#ifndef LARGE_FILE_SUPPORT
+# ifndef NO_LARGE_FILE_SUPPORT
+ /* MS C and VC */
+# if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
+# define LARGE_FILE_SUPPORT
+# endif
+# if defined(__WATCOMC__)
+# define LARGE_FILE_SUPPORT
+# endif
+# endif
+#endif
+
+#ifdef LARGE_FILE_SUPPORT
+ /* 64-bit Large File Support */
+
+ /* Only types and the printf format stuff go here. Functions
+ go in tailor.h since ANSI prototypes are required and the OF define
+ is not defined here. */
+
+# if (defined(_MSC_VER) && (_MSC_VER >= 1100)) || defined(__MINGW32__)
+ /* MS C and VC, MinGW32 */
+ /* these compiler systems use the Microsoft C RTL */
+
+ /* base types for file offsets and file sizes */
+ typedef __int64 zoff_t;
+ typedef unsigned __int64 uzoff_t;
+
+ /* 64-bit stat struct */
+ typedef struct _stati64 z_stat;
+
+ /* printf format size prefix for zoff_t values */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "I64"
+
+# elif (defined(__GNUC__) || defined(ULONG_LONG_MAX))
+ /* GNU C */
+
+ /* base types for file offsets and file sizes */
+ typedef long long zoff_t;
+ typedef unsigned long long uzoff_t;
+
+# ifdef __CYGWIN__
+ /* Use Cygwin's own stat struct */
+ typedef struct stat z_stat;
+# else
+ /* 64-bit stat struct */
+ typedef struct _stati64 z_stat;
+# endif
+
+ /* printf format size prefix for zoff_t values */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+# elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
+ /* WATCOM C */
+
+ /* base types for file offsets and file sizes */
+ typedef __int64 zoff_t;
+ typedef unsigned __int64 uzoff_t;
+
+ /* 64-bit stat struct */
+ typedef struct _stati64 z_stat;
+
+ /* printf format size prefix for zoff_t values */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+
+# elif (defined(__IBMC__) && (__IBMC__ >= 350))
+ /* IBM C */
+
+ /* base types for file offsets and file sizes */
+ typedef __int64 zoff_t;
+ typedef unsigned __int64 uzoff_t;
+
+ /* 64-bit stat struct */
+
+ /* printf format size prefix for zoff_t values */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "I64"
+
+# else
+# undef LARGE_FILE_SUPPORT
+# endif
+
+#endif
+
+#if 0
+# ifndef ZOFF_T_FORMAT_SIZE_PREFIX
+ /* unsupported WIN32 */
+
+ /* base types for file offsets and file sizes */
+ typedef long long zoff_t;
+ typedef unsigned long long uzoff_t;
+
+ /* 64-bit stat struct */
+ typedef struct stat z_stat;
+
+ /* printf format size prefix for zoff_t values */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "ll"
+# endif
+#endif
+
+
+/* Automatically set ZIP64_SUPPORT if supported */
+
+/* MS C and VC */
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__WATCOMC__)
+# ifdef LARGE_FILE_SUPPORT
+# ifndef NO_ZIP64_SUPPORT
+# ifndef ZIP64_SUPPORT
+# define ZIP64_SUPPORT
+# endif
+# endif
+# endif
+#endif
+
+
+#ifndef LARGE_FILE_SUPPORT
+ /* No Large File Support */
+
+ /* base type for file offsets and file sizes */
+ typedef long zoff_t;
+ typedef unsigned long uzoff_t;
+
+ /* stat struct */
+ typedef struct stat z_stat;
+
+ /* printf format size prefix for zoff_t values */
+# define ZOFF_T_FORMAT_SIZE_PREFIX "l"
+#endif
+
+
+ /* UNICODE */
+#ifdef WIN32
+ /* assume wide character conversion functions */
+# ifndef UNICODE_SUPPORT
+# ifndef NO_UNICODE_SUPPORT
+# define UNICODE_SUPPORT
+# endif
+# endif
+#endif
+
+#if 0
+ /* this is now generic */
+# ifdef UNICODE_SUPPORT
+ /* Set up Unicode support - 9/27/05 EG */
+
+ /* type of wide string characters */
+# define zchar wchar_t
+
+ /* default char string used if a wide char can't be converted */
+# define zchar_default "_"
+
+# else
+# define zchar char
+# endif
+#endif
+
+
+/* File operations--use "b" for binary if allowed or fixed length 512 on VMS
+ * use "S" for sequential access on NT to prevent the NT
+ * file cache eating up memory with large .zip files
+ */
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wbS"
+
+#if (defined(__CYGWIN__) && !defined(NO_MKTIME))
+# define NO_MKTIME /* Cygnus' mktime() implementation is buggy */
+#endif
+#if (!defined(NT_TZBUG_WORKAROUND) && !defined(NO_NT_TZBUG_WORKAROUND))
+# define NT_TZBUG_WORKAROUND
+#endif
+#if (defined(UTIL) && defined(NT_TZBUG_WORKAROUND))
+# undef NT_TZBUG_WORKAROUND /* the Zip utilities do not use time-stamps */
+#endif
+#if !defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME)
+# define USE_EF_UT_TIME
+#endif
+#if (!defined(NO_NTSD_EAS) && !defined(NTSD_EAS))
+# define NTSD_EAS
+#endif
+
+#if (defined(NTSD_EAS) && !defined(ZP_NEED_MEMCOMPR))
+# define ZP_NEED_MEMCOMPR
+#endif
+
+#ifdef WINDLL
+# ifndef NO_ASM
+# define NO_ASM
+# endif
+# ifndef MSWIN
+# define MSWIN
+# endif
+# ifndef REENTRANT
+# define REENTRANT
+# endif
+#endif /* WINDLL */
+
+/* Enable use of optimized x86 assembler version of longest_match() for
+ MSDOS, WIN32 and OS2 per default. */
+#if !defined(NO_ASM) && !defined(ASMV)
+# define ASMV
+#endif
+
+/* Enable use of optimized x86 assembler version of crc32() for
+ MSDOS, WIN32 and OS2 per default. */
+#if !defined(NO_ASM) && !defined(ASM_CRC) && !defined(NO_ASM_CRC)
+# define ASM_CRC
+#endif
+
+#if !defined(__GO32__) && !defined(__EMX__) && !defined(__CYGWIN__)
+# define NO_UNISTD_H
+#endif
+
+/* Microsoft C requires additional attributes attached to all RTL function
+ * declarations when linking against the CRTL dll.
+ */
+#ifdef MSC
+# ifdef IZ_IMP
+# undef IZ_IMP
+# endif
+# define IZ_IMP _CRTIMP
+#else
+# ifndef IZ_IMP
+# define IZ_IMP
+# endif
+#endif
+
+/* WIN32 runs solely on little-endian processors; enable support
+ * for the 32-bit optimized CRC-32 C code by default.
+ */
+#ifdef IZ_CRC_BE_OPTIMIZ
+# undef IZ_CRC_BE_OPTIMIZ
+#endif
+#if !defined(IZ_CRC_LE_OPTIMIZ) && !defined(NO_CRC_OPTIMIZ)
+# define IZ_CRC_LE_OPTIMIZ
+#endif
+
+/* the following definitions are considered as "obsolete" by Microsoft and
+ * might be missing in some versions of <windows.h>
+ */
+#ifndef AnsiToOem
+# define AnsiToOem CharToOemA
+#endif
+#ifndef OemToAnsi
+# define OemToAnsi OemToCharA
+#endif
+
+/* handlers for OEM <--> ANSI string conversions */
+#if defined(__RSXNT__) || defined(WIN32_CRT_OEM)
+ /* RSXNT uses OEM coded strings in functions supplied by C RTL */
+# ifdef CRTL_CP_IS_ISO
+# undef CRTL_CP_IS_ISO
+# endif
+# ifndef CRTL_CP_IS_OEM
+# define CRTL_CP_IS_OEM
+# endif
+#else
+ /* "real" native WIN32 compilers use ANSI coded strings in C RTL calls */
+# ifndef CRTL_CP_IS_ISO
+# define CRTL_CP_IS_ISO
+# endif
+# ifdef CRTL_CP_IS_OEM
+# undef CRTL_CP_IS_OEM
+# endif
+#endif
+
+#ifdef CRTL_CP_IS_ISO
+ /* C RTL's file system support assumes ANSI coded strings */
+# define ISO_TO_INTERN(src, dst) {if ((src) != (dst)) strcpy((dst), (src));}
+# define OEM_TO_INTERN(src, dst) OemToAnsi(src, dst)
+# define INTERN_TO_ISO(src, dst) {if ((src) != (dst)) strcpy((dst), (src));}
+# define INTERN_TO_OEM(src, dst) AnsiToOem(src, dst)
+# define _OEM_INTERN(str1) OEM_TO_INTERN(str1, str1)
+# define _ISO_INTERN(str1) {;}
+# define _INTERN_OEM(str1) INTERN_TO_OEM(str1, str1)
+# define _INTERN_ISO(str1) {;}
+#endif /* CRTL_CP_IS_ISO */
+#ifdef CRTL_CP_IS_OEM
+ /* C RTL's file system support assumes OEM coded strings */
+# define ISO_TO_INTERN(src, dst) AnsiToOem(src, dst)
+# define OEM_TO_INTERN(src, dst) {if ((src) != (dst)) strcpy((dst), (src));}
+# define INTERN_TO_ISO(src, dst) OemToAnsi(src, dst)
+# define INTERN_TO_OEM(src, dst) {if ((src) != (dst)) strcpy((dst), (src));}
+# define _OEM_INTERN(str1) {;}
+# define _ISO_INTERN(str1) ISO_TO_INTERN(str1, str1)
+# define _INTERN_OEM(str1) {;}
+# define _INTERN_ISO(str1) INTERN_TO_ISO(str1, str1)
+#endif /* CRTL_CP_IS_OEM */
+
+/* The following "OEM vs. ISO Zip entry names" code has been copied from UnZip.
+ * It should be applicable to the generic Zip code. However, currently only
+ * the Win32 port of Zip supplies the required charset conversion functions.
+ * (The Win32 port uses conversion functions supplied by the OS.)
+ */
+/* Convert filename (and file comment string) into "internal" charset.
+ * This macro assumes that Zip entry filenames are coded in OEM (IBM DOS)
+ * codepage when made on
+ * -> DOS (this includes 16-bit Windows 3.1) (FS_FAT_)
+ * -> OS/2 (FS_HPFS_)
+ * -> Win95/WinNT with Nico Mak's WinZip (FS_NTFS_ && hostver == "5.0")
+ * EXCEPTIONS:
+ * PKZIP for Windows 2.5, 2.6, and 4.0 flag their entries as "FS_FAT_", but
+ * the filename stored in the local header is coded in Windows ANSI (CP 1252
+ * resp. ISO 8859-1 on US and western Europe locale settings).
+ * Likewise, PKZIP for UNIX 2.51 flags its entries as "FS_FAT_", but the
+ * filenames stored in BOTH the local and the central header are coded
+ * in the local system's codepage (usually ANSI codings like ISO 8859-1,
+ * but could also be UTF-8 on "modern" setups...).
+ *
+ * All other ports are assumed to code zip entry filenames in ISO (8859-1
+ * on "Western" localisations).
+ */
+#define FS_FAT_ 0 /* filesystem used by MS-DOS, OS/2, Win32 */
+#define FS_HPFS_ 6 /* filesystem used by OS/2 (and NT 3.x) */
+#define FS_NTFS_ 11 /* filesystem used by Windows NT */
+#ifndef Ext_ASCII_TO_Native
+# define Ext_ASCII_TO_Native(string, hostnum, hostver, isuxatt, islochdr) \
+ if (((hostnum) == FS_FAT_ && \
+ !(((islochdr) || (isuxatt)) && \
+ ((hostver) == 25 || (hostver) == 26 || (hostver) == 40))) || \
+ (hostnum) == FS_HPFS_ || \
+ ((hostnum) == FS_NTFS_ && (hostver) == 50)) { \
+ _OEM_INTERN((string)); \
+ } else { \
+ _ISO_INTERN((string)); \
+ }
+#endif
+
+#if (defined(__RSXNT__) && defined(__CRTRSXNT__))
+# include <crtrsxnt.h>
+#endif
+
+#ifdef _MBCS
+# if (!defined(__EMX__) && !defined(__MINGW32__) && !defined(__CYGWIN__))
+# include <stdlib.h>
+# include <mbstring.h>
+# endif
+# if (defined(__MINGW32__) && !defined(MB_CUR_MAX))
+# ifdef __MSVCRT__
+ IZ_IMP extern int *__p___mb_cur_max(void);
+# define MB_CUR_MAX (*__p___mb_cur_max())
+# else
+ IZ_IMP extern int *_imp____mb_cur_max_dll;
+# define MB_CUR_MAX (*_imp____mb_cur_max_dll)
+# endif
+# endif
+# if (defined(__LCC__) && !defined(MB_CUR_MAX))
+ IZ_IMP extern int *_imp____mb_cur_max;
+# define MB_CUR_MAX (*_imp____mb_cur_max)
+# endif
+#endif
+
+#ifdef __LCC__
+# include <time.h>
+# ifndef tzset
+# define tzset _tzset
+# endif
+# ifndef utime
+# define utime _utime
+# endif
+#endif
+#ifdef __MINGW32__
+ IZ_IMP extern void _tzset(void); /* this is missing in <time.h> */
+# ifndef tzset
+# define tzset _tzset
+# endif
+#endif
+#if (defined(__RSXNT__) || defined(__EMX__)) && !defined(tzset)
+# define tzset _tzset
+#endif
+#ifdef W32_USE_IZ_TIMEZONE
+# ifdef __BORLANDC__
+# define tzname tzname
+# define IZTZ_DEFINESTDGLOBALS
+# endif
+# ifndef tzset
+# define tzset _tzset
+# endif
+# ifndef timezone
+# define timezone _timezone
+# endif
+# ifndef daylight
+# define daylight _daylight
+# endif
+# ifndef tzname
+# define tzname _tzname
+# endif
+# if (!defined(NEED__ISINDST) && !defined(__BORLANDC__))
+# define NEED__ISINDST
+# endif
+# ifdef IZTZ_GETLOCALETZINFO
+# undef IZTZ_GETLOCALETZINFO
+# endif
+# define IZTZ_GETLOCALETZINFO GetPlatformLocalTimezone
+#endif /* W32_USE_IZ_TIMEZONE */
+
+#ifdef MATCH
+# undef MATCH
+#endif
+#define MATCH dosmatch /* use DOS style wildcard matching */
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+# define MATCHW dosmatchw
+# endif
+#endif
+
+#ifdef ZCRYPT_INTERNAL
+# ifdef WINDLL
+# define ZCR_SEED2 (unsigned)3141592654L /* use PI as seed pattern */
+# else
+# include <process.h> /* getpid() declaration for srand seed */
+# endif
+#endif
+
+/* Up to now, all versions of Microsoft C runtime libraries lack the support
+ * for customized (non-US) switching rules between daylight saving time and
+ * standard time in the TZ environment variable string.
+ * But non-US timezone rules are correctly supported when timezone information
+ * is read from the OS system settings in the Win32 registry.
+ * The following work-around deletes any TZ environment setting from
+ * the process environment. This results in a fallback of the RTL time
+ * handling code to the (correctly interpretable) OS system settings, read
+ * from the registry.
+ */
+#ifdef USE_EF_UT_TIME
+# if (defined(__WATCOMC__) || defined(__CYGWIN__) || \
+ defined(W32_USE_IZ_TIMEZONE))
+# define iz_w32_prepareTZenv()
+# else
+# define iz_w32_prepareTZenv() putenv("TZ=")
+# endif
+#endif
+
+/* This patch of stat() is useful for at least three compilers. It is */
+/* difficult to take a stat() of a root directory under Windows95, so */
+/* zstat_zipwin32() detects that case and fills in suitable values. */
+#ifndef __RSXNT__
+# ifndef W32_STATROOT_FIX
+# define W32_STATROOT_FIX
+# endif
+#endif /* !__RSXNT__ */
+
+#if (defined(NT_TZBUG_WORKAROUND) || defined(W32_STATROOT_FIX))
+# define W32_STAT_BANDAID
+# ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ int zstat_zipwin32(const char *path, z_stat *buf);
+# else
+ int zstat_zipwin32(const char *path, struct stat *buf);
+# endif
+# ifdef UNICODE_SUPPORT
+# ifdef LARGE_FILE_SUPPORT
+ int zstat_zipwin32w(const wchar_t *pathw, struct _stati64 *buf);
+# else
+ int zstat_zipwin32w(const wchar_t *pathw, struct _stat *buf);
+# endif
+# endif
+# ifdef SSTAT
+# undef SSTAT
+# endif
+# define SSTAT zstat_zipwin32
+# ifdef UNICODE_SUPPORT
+# define SSTATW zstat_zipwin32w
+# endif
+#endif /* NT_TZBUG_WORKAROUND || W32_STATROOT_FIX */
+
+int getch_win32(void);
+
+#ifdef __GNUC__
+# define IZ_PACKED __attribute__((packed))
+#else
+# define IZ_PACKED
+#endif
+
+/* for some (all ?) versions of IBM C Set/2 and IBM C Set++ */
+#ifndef S_IFMT
+# define S_IFMT 0xF000
+#endif /* !S_IFMT */
+
+#ifdef __WATCOMC__
+# include <stdio.h> /* PATH_MAX is defined here */
+# define NO_MKTEMP
+
+/* Get asm routines to link properly without using "__cdecl": */
+# ifdef __386__
+# ifdef ASMV
+# pragma aux match_init "_*" parm caller [] modify []
+# pragma aux longest_match "_*" parm caller [] value [eax] \
+ modify [eax ecx edx]
+# endif
+# if defined(ASM_CRC) && !defined(USE_ZLIB)
+# pragma aux crc32 "_*" parm caller [] value [eax] modify [eax]
+# pragma aux get_crc_table "_*" parm caller [] value [eax] \
+ modify [eax ecx edx]
+# endif /* ASM_CRC && !USE_ZLIB */
+# endif /* __386__ */
+ /* Watcom C (like the other Win32 C compiler systems) does not support
+ * symlinks on Win32, but defines the S_IFLNK symbol nevertheless.
+ * However, the existence of this symbol is used as "symlinks supported"
+ * indicator in the generic Zip code (see tailor.h). So, for a simple
+ * work-around, this symbol is undefined here. */
+# ifdef S_IFLNK
+# undef S_IFLNK
+# endif
+# ifdef UNICODE_SUPPORT
+ /* Watcom C does not supply wide-char definitions in the "standard"
+ * headers like MSC; so we have to pull in a wchar-specific header.
+ */
+# include <wchar.h>
+# endif
+#endif /* __WATCOMC__ */
diff --git a/win32/readme.a64 b/win32/readme.a64
new file mode 100644
index 0000000..54b2750
--- /dev/null
+++ b/win32/readme.a64
@@ -0,0 +1,42 @@
+readme.x64
+==========
+
+[Note - the gvmat64.asm longest_match routine in Windows 64-bit assembler
+and makefile.a64 used to compile it were provided at the last minute and
+are currently untested by Info-ZIP. They are provided to allow testing of
+this optimization which is planned for inclusion in Zip 3.0.
+USE AT YOUR OWN RISK. That said, thanks Gilles for providing this
+optimization and we plan to better support it in Zip 3.0. 2/28/2005 EG]
+
+makefile.asm64 is a makefile for 64 bits optimized version of zip for
+Microsoft Windows running on AMD64 (Athlon64/Opteron) and Intel EM64T
+(the Pentium 4 and Xeon with 64 bits extension)
+
+makefile.asm64 contain a makefile for 64 Microsoft C++ for Windows 64 bits,
+extended edition (for both AMD64 and Intel EM64T), included in Visual
+Studio 2005
+
+to compile it, start the C++ AMD64 build environnement prompt,
+go to the zip source directory and start
+
+ nmake -a -f makefile.a64
+
+This makefile uses gvmat64.asm, which is the optimized longest_match written
+in assembly code for AMD64/Intel EM64T
+
+gvmat64.asm was tested by Gilles Vollant on AMD64 with infozip, and also tested
+with a lot of file with zLib 1.2.2 on both AMD64 and Intel EM64T processor.
+
+It was written by Gilles Vollant, by modifiying the longest_match
+from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+and modifying asm686 (1998), optimised assembly code from Brian Raiter,
+(see http://www.muppetlabs.com/~breadbox/software/assembly.html)
+
+
+Gilles Vollant
+info@winimage.com
+
+http://www.winimage.com
+http://www.winimage.com/zLibdll
+
+
diff --git a/win32/rsxntwin.h b/win32/rsxntwin.h
new file mode 100644
index 0000000..a710a35
--- /dev/null
+++ b/win32/rsxntwin.h
@@ -0,0 +1,173 @@
+/*
+ win32/rsxntwin.h - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* rsxntwin.h
+ *
+ * fills some gaps in the rsxnt 1.3 win32 header files (<windows.h>) that are
+ * required for compiling Info-ZIP sources for Win NT / Win 95
+ */
+
+#ifdef __RSXNT__
+#if !defined (_RSXNTWIN_H)
+#define _RSXNTWIN_H
+
+#ifdef TFUNCT /* TFUNCT is undefined when MSSDK headers are used */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PASCAL __stdcall
+
+#define ANYSIZE_ARRAY 1
+
+#ifndef TIME_ZONE_ID_UNKNOWN
+# define TIME_ZONE_ID_UNKNOWN 0
+#endif
+#ifndef TIME_ZONE_ID_INVALID
+# define TIME_ZONE_ID_INVALID (DWORD)0xFFFFFFFFL
+#endif
+
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+
+#define FILE_SHARE_DELETE 0x00000004
+
+#define FILE_PERSISTENT_ACLS 0x00000008
+
+#define HFILE_ERROR ((HFILE)-1)
+
+#define FS_PERSISTENT_ACLS FILE_PERSISTENT_ACLS
+
+
+BOOL WINAPI DosDateTimeToFileTime(WORD, WORD, LPFILETIME);
+
+
+#ifndef SetVolumeLabel
+#define SetVolumeLabel TFUNCT(SetVolumeLabel)
+#endif
+BOOL WINAPI SetVolumeLabel(LPCTSTR, LPCTSTR);
+
+
+#ifndef GetDriveType
+#define GetDriveType TFUNCT(GetDriveType)
+#endif
+DWORD GetDriveType(LPCTSTR);
+
+#define DRIVE_UNKNOWN 0
+#define DRIVE_REMOVABLE 2
+#define DRIVE_FIXED 3
+#define DRIVE_REMOTE 4
+#define DRIVE_CDROM 5
+#define DRIVE_RAMDISK 6
+
+#ifndef SearchPath
+#define SearchPath TFUNCT(SearchPath)
+#endif
+BOOL WINAPI SearchPath(LPCTSTR, LPCTSTR, LPCTSTR, UINT, LPTSTR, LPTSTR *);
+
+#define ERROR_SUCCESS 0
+#define ERROR_INSUFFICIENT_BUFFER 122
+
+LONG WINAPI InterlockedExchange(LPLONG, LONG);
+
+#define ACCESS_SYSTEM_SECURITY 0x01000000L
+
+typedef PVOID PSECURITY_DESCRIPTOR;
+typedef PVOID PSID;
+typedef struct _ACL {
+ BYTE AclRevision;
+ BYTE Sbz1;
+ WORD AclSize;
+ WORD AceCount;
+ WORD Sbz2;
+} ACL;
+typedef ACL *PACL;
+
+typedef struct _LUID {
+ DWORD LowPart;
+ LONG HighPart;
+} LUID, *PLUID;
+
+typedef struct _LUID_AND_ATTRIBUTES {
+ LUID Luid;
+ DWORD Attributes;
+ } LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;
+
+typedef struct _TOKEN_PRIVILEGES {
+ DWORD PrivilegeCount;
+ LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
+} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
+
+#define TOKEN_QUERY 0x0008
+#define TOKEN_ADJUST_PRIVILEGES 0x0020
+
+BOOL WINAPI OpenProcessToken(HANDLE, DWORD, PHANDLE);
+BOOL WINAPI AdjustTokenPrivileges(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD,
+ PTOKEN_PRIVILEGES, PDWORD);
+
+#ifndef LookupPrivilegeValue
+#define LookupPrivilegeValue TFUNCT(LookupPrivilegeValue)
+#endif
+BOOL WINAPI LookupPrivilegeValue(LPCTSTR, LPCTSTR, PLUID);
+
+typedef DWORD SECURITY_INFORMATION, *PSECURITY_INFORMATION;
+#define OWNER_SECURITY_INFORMATION 0x00000001L
+#define GROUP_SECURITY_INFORMATION 0x00000002L
+#define DACL_SECURITY_INFORMATION 0x00000004L
+#define SACL_SECURITY_INFORMATION 0x00000008L
+
+typedef WORD SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL;
+#define SE_DACL_PRESENT 0x0004
+#define SE_SACL_PRESENT 0x0010
+
+#define SE_PRIVILEGE_ENABLED 0x00000002L
+
+#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege")
+#define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
+#define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
+
+BOOL WINAPI GetKernelObjectSecurity(HANDLE, SECURITY_INFORMATION,
+ PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
+BOOL WINAPI SetKernelObjectSecurity(HANDLE, SECURITY_INFORMATION,
+ PSECURITY_DESCRIPTOR);
+BOOL WINAPI IsValidSid(PSID);
+BOOL WINAPI IsValidAcl(PACL);
+BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR);
+BOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR);
+DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR);
+BOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,
+ PSECURITY_DESCRIPTOR_CONTROL, LPDWORD);
+BOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,
+ SECURITY_DESCRIPTOR_CONTROL, SECURITY_DESCRIPTOR_CONTROL);
+BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,
+ LPBOOL, PACL *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL);
+BOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR,
+ LPBOOL, PACL *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL);
+BOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR, PSID *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR, PSID, BOOL);
+BOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR, PSID *, LPBOOL);
+BOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR, PSID, BOOL);
+VOID WINAPI InitializeCriticalSection();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TFUNCT */
+
+#ifndef CP_UTF8
+# define CP_UTF8 65001 /* UTF-8 translation */
+#endif
+
+#endif /* !defined (_RSXNTWIN_H) */
+#endif /* __RSXNT__ */
diff --git a/win32/vc6/ReadmeVC.txt b/win32/vc6/ReadmeVC.txt
new file mode 100644
index 0000000..f0295cb
--- /dev/null
+++ b/win32/vc6/ReadmeVC.txt
@@ -0,0 +1,10 @@
+VC6 Readme
+
+This directory has a VC6 project list that can be used to compile Zip
+and the utilities. It does not include bzip2 support.
+
+The vc6bz2 directory provides a variant of this directory that includes
+the settings needed for including bzip2 support in Zip.
+
+Ed Gordon
+26 March 2007
diff --git a/win32/vc6/zip.dsp b/win32/vc6/zip.dsp
new file mode 100644
index 0000000..10acbe1
--- /dev/null
+++ b/win32/vc6/zip.dsp
@@ -0,0 +1,337 @@
+# Microsoft Developer Studio Project File - Name="zip" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=zip - Win32 ASM Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zip.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zip.mak" CFG="zip - Win32 ASM Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zip - Win32 ASM Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "zip - Win32 ASM Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "zip - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "zip - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zip - Win32 ASM Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zip___Win32_ASM_Release"
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zip___Win32_ASM_Release"
+# PROP Intermediate_Dir "zip___Win32_ASM_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "ASM_CRC" /D "ASMV" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "zip - Win32 ASM Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zip___Win32_ASM_Debug"
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zip___Win32_ASM_Debug"
+# PROP Intermediate_Dir "zip___Win32_ASM_Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "ASM_CRC" /D "ASMV" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zip - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zip___Win32_Release"
+# PROP BASE Intermediate_Dir "zip___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zip___Win32_Release"
+# PROP Intermediate_Dir "zip___Win32_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "NO_ASM" /D "WIN32" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "zip - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zip___Win32_Debug"
+# PROP BASE Intermediate_Dir "zip___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zip___Win32_Debug"
+# PROP Intermediate_Dir "zip___Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "zip - Win32 ASM Release"
+# Name "zip - Win32 ASM Debug"
+# Name "zip - Win32 Release"
+# Name "zip - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crypt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\deflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\globals.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\nt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\trees.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ttyio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32i64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zip.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipup.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\crc32.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crypt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ebcdic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\nt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\osdep.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\revision.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\tailor.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ttyio.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ziperr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\zipup.h
+# End Source File
+# End Group
+# Begin Group "Assembler Files"
+
+# PROP Default_Filter "asm;obj"
+# Begin Source File
+
+SOURCE=..\crc_i386.asm
+
+!IF "$(CFG)" == "zip - Win32 ASM Release"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Release
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 ASM Debug"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Debug
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 Release"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "zip - Win32 Debug"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\match32.asm
+
+!IF "$(CFG)" == "zip - Win32 ASM Release"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Release
+InputPath=..\match32.asm
+InputName=match32
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 ASM Debug"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Debug
+InputPath=..\match32.asm
+InputName=match32
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 Release"
+
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "zip - Win32 Debug"
+
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win32/vc6/zip.dsw b/win32/vc6/zip.dsw
new file mode 100644
index 0000000..681d183
--- /dev/null
+++ b/win32/vc6/zip.dsw
@@ -0,0 +1,65 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zip"=".\zip.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zipcloak"=".\zipcloak.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zipnote"=".\zipnote.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zipsplit"=".\zipsplit.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/win32/vc6/zipcloak.dsp b/win32/vc6/zipcloak.dsp
new file mode 100644
index 0000000..e09ccd7
--- /dev/null
+++ b/win32/vc6/zipcloak.dsp
@@ -0,0 +1,264 @@
+# Microsoft Developer Studio Project File - Name="zipcloak" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=zipcloak - Win32 ASM Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zipcloak.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zipcloak.mak" CFG="zipcloak - Win32 ASM Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zipcloak - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipcloak - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipcloak - Win32 ASM Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipcloak - Win32 ASM Release" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zipcloak - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zipcloak___Win32_Release"
+# PROP BASE Intermediate_Dir "zipcloak___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zipcloak___Win32_Release"
+# PROP Intermediate_Dir "zipcloak___Win32_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "UTIL" /D "WIN32" /D "NO_ASM" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "zipcloak - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zipcloak___Win32_Debug"
+# PROP BASE Intermediate_Dir "zipcloak___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zipcloak___Win32_Debug"
+# PROP Intermediate_Dir "zipcloak___Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zipcloak - Win32 ASM Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zipcloak___Win32_ASM_Debug"
+# PROP BASE Intermediate_Dir "zipcloak___Win32_ASM_Debug"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zipcloak___Win32_ASM_Debug"
+# PROP Intermediate_Dir "zipcloak___Win32_ASM_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zipcloak - Win32 ASM Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zipcloak___Win32_ASM_Release"
+# PROP BASE Intermediate_Dir "zipcloak___Win32_ASM_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zipcloak___Win32_ASM_Release"
+# PROP Intermediate_Dir "zipcloak___Win32_ASM_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "zipcloak - Win32 Release"
+# Name "zipcloak - Win32 Debug"
+# Name "zipcloak - Win32 ASM Debug"
+# Name "zipcloak - Win32 ASM Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crypt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\globals.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ttyio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32i64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipcloak.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipfile.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\crc32.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crypt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ebcdic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\osdep.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\revision.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\tailor.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ttyio.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ziperr.h
+# End Source File
+# End Group
+# Begin Group "Assembler Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\crc_i386.asm
+
+!IF "$(CFG)" == "zipcloak - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zipcloak - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zipcloak - Win32 ASM Debug"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zipcloak___Win32_ASM_Debug
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zipcloak - Win32 ASM Release"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zipcloak___Win32_ASM_Release
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win32/vc6/zipnote.dsp b/win32/vc6/zipnote.dsp
new file mode 100644
index 0000000..a7f9f57
--- /dev/null
+++ b/win32/vc6/zipnote.dsp
@@ -0,0 +1,248 @@
+# Microsoft Developer Studio Project File - Name="zipnote" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=zipnote - Win32 ASM Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zipnote.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zipnote.mak" CFG="zipnote - Win32 ASM Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zipnote - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipnote - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipnote - Win32 ASM Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipnote - Win32 ASM Release" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zipnote - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zipnote___Win32_Release"
+# PROP BASE Intermediate_Dir "zipnote___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zipnote___Win32_Release"
+# PROP Intermediate_Dir "zipnote___Win32_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "UTIL" /D "WIN32" /D "NO_ASM" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "zipnote - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zipnote___Win32_Debug"
+# PROP BASE Intermediate_Dir "zipnote___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zipnote___Win32_Debug"
+# PROP Intermediate_Dir "zipnote___Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "NO_ASM" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zipnote - Win32 ASM Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zipnote___Win32_ASM_Debug"
+# PROP BASE Intermediate_Dir "zipnote___Win32_ASM_Debug"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zipnote___Win32_ASM_Debug"
+# PROP Intermediate_Dir "zipnote___Win32_ASM_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zipnote - Win32 ASM Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zipnote___Win32_ASM_Release"
+# PROP BASE Intermediate_Dir "zipnote___Win32_ASM_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zipnote___Win32_ASM_Release"
+# PROP Intermediate_Dir "zipnote___Win32_ASM_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "zipnote - Win32 Release"
+# Name "zipnote - Win32 Debug"
+# Name "zipnote - Win32 ASM Debug"
+# Name "zipnote - Win32 ASM Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\globals.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32i64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipnote.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\crc32.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ebcdic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\osdep.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\revision.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\tailor.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ziperr.h
+# End Source File
+# End Group
+# Begin Group "Assembler Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\crc_i386.asm
+
+!IF "$(CFG)" == "zipnote - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zipnote - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zipnote - Win32 ASM Debug"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zipnote___Win32_ASM_Debug
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zipnote - Win32 ASM Release"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zipnote___Win32_ASM_Release
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win32/vc6/zipsplit.dsp b/win32/vc6/zipsplit.dsp
new file mode 100644
index 0000000..ae5565d
--- /dev/null
+++ b/win32/vc6/zipsplit.dsp
@@ -0,0 +1,248 @@
+# Microsoft Developer Studio Project File - Name="zipsplit" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=zipsplit - Win32 ASM Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zipsplit.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zipsplit.mak" CFG="zipsplit - Win32 ASM Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zipsplit - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipsplit - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipsplit - Win32 ASM Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "zipsplit - Win32 ASM Release" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zipsplit - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zipsplit___Win32_Release"
+# PROP BASE Intermediate_Dir "zipsplit___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zipsplit___Win32_Release"
+# PROP Intermediate_Dir "zipsplit___Win32_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "UTIL" /D "WIN32" /D "NO_ASM" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "zipsplit - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zipsplit___Win32_Debug"
+# PROP BASE Intermediate_Dir "zipsplit___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zipsplit___Win32_Debug"
+# PROP Intermediate_Dir "zipsplit___Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /D "NO_ASM" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zipsplit - Win32 ASM Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zipsplit___Win32_ASM_Debug"
+# PROP BASE Intermediate_Dir "zipsplit___Win32_ASM_Debug"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zipsplit___Win32_ASM_Debug"
+# PROP Intermediate_Dir "zipsplit___Win32_ASM_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "UTIL" /D "WIN32" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zipsplit - Win32 ASM Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zipsplit___Win32_ASM_Release"
+# PROP BASE Intermediate_Dir "zipsplit___Win32_ASM_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zipsplit___Win32_ASM_Release"
+# PROP Intermediate_Dir "zipsplit___Win32_ASM_Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "UTIL" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "zipsplit - Win32 Release"
+# Name "zipsplit - Win32 Debug"
+# Name "zipsplit - Win32 ASM Debug"
+# Name "zipsplit - Win32 ASM Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\globals.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32i64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipsplit.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\crc32.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ebcdic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\osdep.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\revision.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\tailor.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ziperr.h
+# End Source File
+# End Group
+# Begin Group "Assembler Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\crc_i386.asm
+
+!IF "$(CFG)" == "zipsplit - Win32 Release"
+
+!ELSEIF "$(CFG)" == "zipsplit - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "zipsplit - Win32 ASM Debug"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zipsplit___Win32_ASM_Debug
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zipsplit - Win32 ASM Release"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zipsplit___Win32_ASM_Release
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win32/vc6bz2/ReadVCBZ.txt b/win32/vc6bz2/ReadVCBZ.txt
new file mode 100644
index 0000000..3aafd6f
--- /dev/null
+++ b/win32/vc6bz2/ReadVCBZ.txt
@@ -0,0 +1,19 @@
+VC6bz2 Readme
+
+This directory has a VC6 project list that can be used to compile Zip
+and the utilities. The Zip project includes support for the bzip2
+compression method.
+
+To include bzip2 support, get a copy of the bzip2 source (bzip2-1.0.4
+or later from http://www.bzip.org/ for instance), expand the bzip2
+source into a directory, then copy the contents of the bzip2-1.0.4
+directory, for instance, into the zip bzip2 directory. Use this
+project to compile zip and bzip2 support should be included. See
+bzip2/install.txt for additional information.
+
+The vc6 directory is similar to this directory but does not include
+bzip2 support. Use that if you do not have a copy of bzip2 or do not
+need bzip2 support.
+
+Ed Gordon
+26 March 2007
diff --git a/win32/vc6bz2/zip.dsp b/win32/vc6bz2/zip.dsp
new file mode 100644
index 0000000..fee0af4
--- /dev/null
+++ b/win32/vc6bz2/zip.dsp
@@ -0,0 +1,381 @@
+# Microsoft Developer Studio Project File - Name="zip" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=zip - Win32 Debug bzip2
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zip.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zip.mak" CFG="zip - Win32 Debug bzip2"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zip - Win32 ASM Release bzip2" (based on "Win32 (x86) Console Application")
+!MESSAGE "zip - Win32 ASM Debug bzip2" (based on "Win32 (x86) Console Application")
+!MESSAGE "zip - Win32 Release bzip2" (based on "Win32 (x86) Console Application")
+!MESSAGE "zip - Win32 Debug bzip2" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zip - Win32 ASM Release bzip2"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zip___Win32_ASM_Release_bzip2"
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Release_bzip2"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zip___Win32_ASM_Release_bzip2"
+# PROP Intermediate_Dir "zip___Win32_ASM_Release_bzip2"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "ASM_CRC" /D "ASMV" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "ASM_CRC" /D "ASMV" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "zip - Win32 ASM Debug bzip2"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zip___Win32_ASM_Debug_bzip2"
+# PROP BASE Intermediate_Dir "zip___Win32_ASM_Debug_bzip2"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zip___Win32_ASM_Debug_bzip2"
+# PROP Intermediate_Dir "zip___Win32_ASM_Debug_bzip2"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "ASM_CRC" /D "ASMV" /FR /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "ASM_CRC" /D "ASMV" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FR /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "zip - Win32 Release bzip2"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "zip___Win32_Release_bzip2"
+# PROP BASE Intermediate_Dir "zip___Win32_Release_bzip2"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "zip___Win32_Release_bzip2"
+# PROP Intermediate_Dir "zip___Win32_Release_bzip2"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NO_ASM" /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "../../bzip2" /D "NO_ASM" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF "$(CFG)" == "zip - Win32 Debug bzip2"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "zip___Win32_Debug_bzip2"
+# PROP BASE Intermediate_Dir "zip___Win32_Debug_bzip2"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "zip___Win32_Debug_bzip2"
+# PROP Intermediate_Dir "zip___Win32_Debug_bzip2"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "NO_ASM" /D "WIN32" /FR /FD /GZ /c
+# SUBTRACT BASE CPP /WX
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../bzip2" /D "NO_ASM" /D "WIN32" /D "BZIP2_SUPPORT" /D "BZ_NO_STDIO" /FR /FD /GZ /c
+# SUBTRACT CPP /WX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "zip - Win32 ASM Release bzip2"
+# Name "zip - Win32 ASM Debug bzip2"
+# Name "zip - Win32 Release bzip2"
+# Name "zip - Win32 Debug bzip2"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\..\bzip2\blocksort.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bzip2\bzlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bzip2\compress.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bzip2\crctable.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crypt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bzip2\decompress.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\deflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\globals.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bzip2\huffman.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\nt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\bzip2\randtable.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\trees.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ttyio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32i64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zbz2err.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\zip.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zipup.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\bzip2\bzlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crc32.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\crypt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ebcdic.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\nt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\osdep.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\revision.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\tailor.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ttyio.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\win32zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\zip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ziperr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\zipup.h
+# End Source File
+# End Group
+# Begin Group "Assembler Files"
+
+# PROP Default_Filter "asm;obj"
+# Begin Source File
+
+SOURCE=..\crc_i386.asm
+
+!IF "$(CFG)" == "zip - Win32 ASM Release bzip2"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Release_bzip2
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 ASM Debug bzip2"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Debug_bzip2
+InputPath=..\crc_i386.asm
+InputName=crc_i386
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 Release bzip2"
+
+# PROP BASE Exclude_From_Build 1
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "zip - Win32 Debug bzip2"
+
+# PROP BASE Exclude_From_Build 1
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\match32.asm
+
+!IF "$(CFG)" == "zip - Win32 ASM Release bzip2"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Release_bzip2
+InputPath=..\match32.asm
+InputName=match32
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 ASM Debug bzip2"
+
+# Begin Custom Build - Assembling...
+IntDir=.\zip___Win32_ASM_Debug_bzip2
+InputPath=..\match32.asm
+InputName=match32
+
+"$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml /nologo /c /Cx /coff /Zi /Fo"$(IntDir)\$(InputName).obj" "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "zip - Win32 Release bzip2"
+
+# PROP BASE Exclude_From_Build 1
+# PROP Exclude_From_Build 1
+
+!ELSEIF "$(CFG)" == "zip - Win32 Debug bzip2"
+
+# PROP BASE Exclude_From_Build 1
+# PROP Exclude_From_Build 1
+
+!ENDIF
+
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win32/vc6bz2/zip.dsw b/win32/vc6bz2/zip.dsw
new file mode 100644
index 0000000..bab0fdd
--- /dev/null
+++ b/win32/vc6bz2/zip.dsw
@@ -0,0 +1,65 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zip"=.\zip.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zipcloak"=..\vc6\zipcloak.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zipnote"=..\vc6\zipnote.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "zipsplit"=..\vc6\zipsplit.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/win32/win32.c b/win32/win32.c
new file mode 100644
index 0000000..5798053
--- /dev/null
+++ b/win32/win32.c
@@ -0,0 +1,1488 @@
+/*
+ win32/win32.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+/*
+ * WIN32 specific functions for ZIP.
+ *
+ * The WIN32 version of ZIP heavily relies on the MSDOS and OS2 versions,
+ * since we have to do similar things to switch between NTFS, HPFS and FAT.
+ */
+
+
+#include "../zip.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+/* for LARGE_FILE_SUPPORT but may not be needed */
+#include <io.h>
+
+#ifdef __RSXNT__
+# include <alloca.h>
+# include "../win32/rsxntwin.h"
+#endif
+#include "../win32/win32zip.h"
+
+#define A_RONLY 0x01
+#define A_HIDDEN 0x02
+#define A_SYSTEM 0x04
+#define A_LABEL 0x08
+#define A_DIR 0x10
+#define A_ARCHIVE 0x20
+
+
+#define EAID 0x0009
+
+#if (defined(__MINGW32__) && !defined(USE_MINGW_GLOBBING))
+ int _CRT_glob = 0; /* suppress command line globbing by C RTL */
+#endif
+
+#ifndef UTIL
+
+extern int noisy;
+
+#ifdef NT_TZBUG_WORKAROUND
+local int FSusesLocalTime(const char *path);
+#ifdef UNICODE_SUPPORt
+local int FSusesLocalTimeW(const wchar_t *path);
+#endif
+#endif
+#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND))
+local int FileTime2utime(FILETIME *pft, time_t *ut);
+#endif
+#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID))
+local int VFatFileTime2utime(const FILETIME *pft, time_t *ut);
+#endif
+
+
+/* FAT / HPFS detection */
+
+int IsFileSystemOldFAT(char *dir)
+{
+ static char lastDrive = '\0'; /* cached drive of last GetVolumeInformation call */
+ static int lastDriveOldFAT = 0; /* cached OldFAT value of last GetVolumeInformation call */
+ char root[4];
+ DWORD vfnsize;
+ DWORD vfsflags;
+
+ /*
+ * We separate FAT and HPFS+other file systems here.
+ * I consider other systems to be similar to HPFS/NTFS, i.e.
+ * support for long file names and being case sensitive to some extent.
+ */
+
+ strncpy(root, dir, 3);
+ if ( isalpha((uch)root[0]) && (root[1] == ':') ) {
+ root[0] = to_up(dir[0]);
+ root[2] = '\\';
+ root[3] = 0;
+ }
+ else {
+ root[0] = '\\';
+ root[1] = 0;
+ }
+ if (lastDrive == root[0]) {
+ return lastDriveOldFAT;
+ }
+
+ if ( !GetVolumeInformation(root, NULL, 0,
+ NULL, &vfnsize, &vfsflags,
+ NULL, 0)) {
+ fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n");
+ return(FALSE);
+ }
+
+ lastDrive = root[0];
+ lastDriveOldFAT = vfnsize <= 12;
+
+ return lastDriveOldFAT;
+}
+
+#ifdef UNICODE_SUPPORT
+int IsFileSystemOldFATW(wchar_t *dir)
+{
+ static wchar_t lastDrive = (wchar_t)'\0'; /* cached drive of last GetVolumeInformation call */
+ static int lastDriveOldFAT = 0; /* cached OldFAT value of last GetVolumeInformation call */
+ wchar_t root[4];
+ DWORD vfnsize;
+ DWORD vfsflags;
+
+ /*
+ * We separate FAT and HPFS+other file systems here.
+ * I consider other systems to be similar to HPFS/NTFS, i.e.
+ * support for long file names and being case sensitive to some extent.
+ */
+
+ wcsncpy(root, dir, 3);
+ if ( iswalpha(root[0]) && (root[1] == (wchar_t)':') ) {
+ root[0] = towupper(dir[0]);
+ root[2] = (wchar_t)'\\';
+ root[3] = 0;
+ }
+ else {
+ root[0] = (wchar_t)'\\';
+ root[1] = 0;
+ }
+ if (lastDrive == root[0]) {
+ return lastDriveOldFAT;
+ }
+
+ if ( !GetVolumeInformationW(root, NULL, 0,
+ NULL, &vfnsize, &vfsflags,
+ NULL, 0)) {
+ fprintf(mesg, "zip diagnostic: GetVolumeInformation failed\n");
+ return(FALSE);
+ }
+
+ lastDrive = root[0];
+ lastDriveOldFAT = vfnsize <= 12;
+
+ return lastDriveOldFAT;
+}
+#endif
+
+
+/* access mode bits and time stamp */
+
+int GetFileMode(char *name)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+ OemToAnsi(name, ansi_name);
+ name = ansi_name;
+#endif
+
+ dwAttr = GetFileAttributes(name);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ zipwarn("reading file attributes failed: ", name);
+ /*
+ fprintf(mesg, "zip diagnostic: GetFileAttributes failed");
+ fflush();
+ */
+ return(0x20); /* the most likely, though why the error? security? */
+ }
+ return(
+ (dwAttr&FILE_ATTRIBUTE_READONLY ? A_RONLY :0)
+ | (dwAttr&FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN :0)
+ | (dwAttr&FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM :0)
+ | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR :0)
+ | (dwAttr&FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE :0));
+}
+
+#ifdef UNICODE_SUPPORT
+int GetFileModeW(wchar_t *namew)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ wchar_t *ansi_namew = (wchar_t *)alloca((wcslen(namew) + 1) * sizeof(wchar_t));
+
+ CharToAnsiW(namew, ansi_namew);
+ namew = ansi_namew;
+#endif
+
+ dwAttr = GetFileAttributesW(namew);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ char *name = wchar_to_local_string(namew);
+ zipwarn("reading file attributes failed: ", name);
+ free(name);
+ return(0x20); /* the most likely, though why the error? security? */
+ }
+ return(
+ (dwAttr&FILE_ATTRIBUTE_READONLY ? A_RONLY :0)
+ | (dwAttr&FILE_ATTRIBUTE_HIDDEN ? A_HIDDEN :0)
+ | (dwAttr&FILE_ATTRIBUTE_SYSTEM ? A_SYSTEM :0)
+ | (dwAttr&FILE_ATTRIBUTE_DIRECTORY ? A_DIR :0)
+ | (dwAttr&FILE_ATTRIBUTE_ARCHIVE ? A_ARCHIVE :0));
+}
+#endif
+
+
+int ClearArchiveBitW(wchar_t *namew)
+{
+DWORD dwAttr;
+ dwAttr = GetFileAttributesW(namew);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n");
+ return(0);
+ }
+
+ if (!SetFileAttributesW(namew, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) {
+ fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n");
+ perror("SetFileAttributes");
+ return(0);
+ }
+ return(1);
+}
+
+int ClearArchiveBit(char *name)
+{
+DWORD dwAttr;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+ OemToAnsi(name, ansi_name);
+ name = ansi_name;
+#endif
+
+ dwAttr = GetFileAttributes(name);
+ if ( dwAttr == 0xFFFFFFFF ) {
+ fprintf(mesg, "zip diagnostic: GetFileAttributes failed\n");
+ return(0);
+ }
+
+ if (!SetFileAttributes(name, (DWORD)(dwAttr & ~FILE_ATTRIBUTE_ARCHIVE))) {
+ fprintf(mesg, "zip diagnostic: SetFileAttributes failed\n");
+ perror("SetFileAttributes");
+ return(0);
+ }
+ return(1);
+}
+
+
+#ifdef NT_TZBUG_WORKAROUND
+local int FSusesLocalTime(const char *path)
+{
+ char *tmp0;
+ char rootPathName[4];
+ char tmp1[MAX_PATH], tmp2[MAX_PATH];
+ DWORD volSerNo, maxCompLen, fileSysFlags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+ OemToAnsi(path, ansi_path);
+ path = ansi_path;
+#endif
+
+ if (isalpha((uch)path[0]) && (path[1] == ':'))
+ tmp0 = (char *)path;
+ else
+ {
+ GetFullPathName(path, MAX_PATH, tmp1, &tmp0);
+ tmp0 = &tmp1[0];
+ }
+ strncpy(rootPathName, tmp0, 3); /* Build the root path name, */
+ rootPathName[3] = '\0'; /* e.g. "A:/" */
+
+ GetVolumeInformation((LPCTSTR)rootPathName, (LPTSTR)tmp1, (DWORD)MAX_PATH,
+ &volSerNo, &maxCompLen, &fileSysFlags,
+ (LPTSTR)tmp2, (DWORD)MAX_PATH);
+
+ /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
+ * local time!
+ */
+ return !strncmp(strupr(tmp2), "FAT", 3) ||
+ !strncmp(tmp2, "VFAT", 4) ||
+ !strncmp(tmp2, "HPFS", 4);
+
+} /* end function FSusesLocalTime() */
+
+# ifdef UNICODE_SUPPORT
+local int FSusesLocalTimeW(const wchar_t *path)
+{
+ wchar_t *tmp0;
+ wchar_t rootPathName[4];
+ wchar_t tmp1[MAX_PATH], tmp2[MAX_PATH];
+ DWORD volSerNo, maxCompLen, fileSysFlags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ wchar_t *ansi_path = (wchar_t *)alloca((wcslen(path) + 1) * sizeof(wchar_t));
+
+ CharToAnsiW(path, ansi_path);
+ path = ansi_path;
+#endif
+
+ if (iswalpha(path[0]) && (path[1] == (wchar_t)':'))
+ tmp0 = (wchar_t *)path;
+ else
+ {
+ GetFullPathNameW(path, MAX_PATH, tmp1, &tmp0);
+ tmp0 = &tmp1[0];
+ }
+ wcsncpy(rootPathName, tmp0, 3); /* Build the root path name, */
+ rootPathName[3] = (wchar_t)'\0'; /* e.g. "A:/" */
+
+ GetVolumeInformationW(rootPathName, tmp1, (DWORD)MAX_PATH,
+ &volSerNo, &maxCompLen, &fileSysFlags,
+ tmp2, (DWORD)MAX_PATH);
+
+ /* Volumes in (V)FAT and (OS/2) HPFS format store file timestamps in
+ * local time!
+ */
+ return !wcsncmp(_wcsupr(tmp2), L"FAT", 3) ||
+ !wcsncmp(tmp2, L"VFAT", 4) ||
+ !wcsncmp(tmp2, L"HPFS", 4);
+
+} /* end function FSusesLocalTimeW() */
+# endif
+
+#endif /* NT_TZBUG_WORKAROUND */
+
+
+#if (defined(USE_EF_UT_TIME) || defined(NT_TZBUG_WORKAROUND))
+
+#if (defined(__GNUC__) || defined(ULONG_LONG_MAX))
+ typedef long long LLONG64;
+ typedef unsigned long long ULLNG64;
+#elif (defined(__WATCOMC__) && (__WATCOMC__ >= 1100))
+ typedef __int64 LLONG64;
+ typedef unsigned __int64 ULLNG64;
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1100))
+ typedef __int64 LLONG64;
+ typedef unsigned __int64 ULLNG64;
+#elif (defined(__IBMC__) && (__IBMC__ >= 350))
+ typedef __int64 LLONG64;
+ typedef unsigned __int64 ULLNG64;
+#else
+# define NO_INT64
+#endif
+
+# define UNIX_TIME_ZERO_HI 0x019DB1DEUL
+# define UNIX_TIME_ZERO_LO 0xD53E8000UL
+# define NT_QUANTA_PER_UNIX 10000000L
+# define FTQUANTA_PER_UT_L (NT_QUANTA_PER_UNIX & 0xFFFF)
+# define FTQUANTA_PER_UT_H (NT_QUANTA_PER_UNIX >> 16)
+# define UNIX_TIME_UMAX_HI 0x0236485EUL
+# define UNIX_TIME_UMAX_LO 0xD4A5E980UL
+# define UNIX_TIME_SMIN_HI 0x0151669EUL
+# define UNIX_TIME_SMIN_LO 0xD53E8000UL
+# define UNIX_TIME_SMAX_HI 0x01E9FD1EUL
+# define UNIX_TIME_SMAX_LO 0xD4A5E980UL
+
+local int FileTime2utime(FILETIME *pft, time_t *ut)
+{
+#ifndef NO_INT64
+ ULLNG64 NTtime;
+
+ NTtime = ((ULLNG64)pft->dwLowDateTime +
+ ((ULLNG64)pft->dwHighDateTime << 32));
+
+ /* underflow and overflow handling */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+ if ((time_t)0x80000000L < (time_t)0L)
+ {
+ if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO +
+ ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) {
+ *ut = (time_t)LONG_MIN;
+ return FALSE;
+ }
+ if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO +
+ ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) {
+ *ut = (time_t)LONG_MAX;
+ return FALSE;
+ }
+ }
+ else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+ {
+ if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO +
+ ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) {
+ *ut = (time_t)0;
+ return FALSE;
+ }
+ if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO +
+ ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) {
+ *ut = (time_t)ULONG_MAX;
+ return FALSE;
+ }
+ }
+
+ NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO +
+ ((ULLNG64)UNIX_TIME_ZERO_HI << 32));
+ *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX);
+ return TRUE;
+#else /* NO_INT64 (64-bit integer arithmetics may not be supported) */
+ /* nonzero if `y' is a leap year, else zero */
+# define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0)
+ /* number of leap years from 1970 to `y' (not including `y' itself) */
+# define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400)
+ /* daycount at the end of month[m-1] */
+ static ZCONST ush ydays[] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+
+ time_t days;
+ SYSTEMTIME w32tm;
+
+ /* underflow and overflow handling */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+ if ((time_t)0x80000000L < (time_t)0L)
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
+ *ut = (time_t)LONG_MIN;
+ return FALSE;
+ if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
+ *ut = (time_t)LONG_MAX;
+ return FALSE;
+ }
+ }
+ else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
+ *ut = (time_t)0;
+ return FALSE;
+ }
+ if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
+ *ut = (time_t)ULONG_MAX;
+ return FALSE;
+ }
+ }
+
+ FileTimeToSystemTime(pft, &w32tm);
+
+ /* set `days' to the number of days into the year */
+ days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] +
+ (w32tm.wMonth > 2 && leap (w32tm.wYear));
+
+ /* now set `days' to the number of days since 1 Jan 1970 */
+ days += 365 * (time_t)(w32tm.wYear - 1970) +
+ (time_t)(nleap(w32tm.wYear));
+
+ *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour +
+ (time_t)(60 * w32tm.wMinute + w32tm.wSecond));
+ return TRUE;
+#endif /* ?NO_INT64 */
+} /* end function FileTime2utime() */
+#endif /* USE_EF_UT_TIME || NT_TZBUG_WORKAROUND */
+
+
+#if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID))
+
+local int VFatFileTime2utime(const FILETIME *pft, time_t *ut)
+{
+ FILETIME lft;
+ SYSTEMTIME w32tm;
+ struct tm ltm;
+
+ FileTimeToLocalFileTime(pft, &lft);
+ FileTimeToSystemTime(&lft, &w32tm);
+ /* underflow and overflow handling */
+ /* TODO: The range checks are not accurate, the actual limits may
+ * be off by one daylight-saving-time shift (typically 1 hour),
+ * depending on the current state of "is_dst".
+ */
+#ifdef CHECK_UTIME_SIGNED_UNSIGNED
+ if ((time_t)0x80000000L < (time_t)0L)
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) {
+ *ut = (time_t)LONG_MIN;
+ return FALSE;
+ if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) {
+ *ut = (time_t)LONG_MAX;
+ return FALSE;
+ }
+ }
+ else
+#endif /* CHECK_UTIME_SIGNED_UNSIGNED */
+ {
+ if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) &&
+ (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) {
+ *ut = (time_t)0;
+ return FALSE;
+ }
+ if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) ||
+ ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) &&
+ (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) {
+ *ut = (time_t)ULONG_MAX;
+ return FALSE;
+ }
+ }
+ ltm.tm_year = w32tm.wYear - 1900;
+ ltm.tm_mon = w32tm.wMonth - 1;
+ ltm.tm_mday = w32tm.wDay;
+ ltm.tm_hour = w32tm.wHour;
+ ltm.tm_min = w32tm.wMinute;
+ ltm.tm_sec = w32tm.wSecond;
+ ltm.tm_isdst = -1; /* let mktime determine if DST is in effect */
+ *ut = mktime(&ltm);
+
+ /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors.
+ * Normally, we would have to apply a consistency check because "-1"
+ * could also be a valid time. But, it is quite unlikely to read back odd
+ * time numbers from file systems that store time stamps in DOS format.
+ * (The only known exception is creation time on VFAT partitions.)
+ */
+ return (*ut != (time_t)-1L);
+
+} /* end function VFatFileTime2utime() */
+#endif /* NT_TZBUG_WORKAROUND && W32_STAT_BANDAID */
+
+
+#if 0 /* Currently, this is not used at all */
+
+long GetTheFileTime(char *name, iztimes *z_ut)
+{
+HANDLE h;
+FILETIME Modft, Accft, Creft, lft;
+WORD dh, dl;
+#ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(name) + 1);
+
+ OemToAnsi(name, ansi_name);
+ name = ansi_name;
+#endif
+
+ h = CreateFile(name, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if ( h != INVALID_HANDLE_VALUE ) {
+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+ CloseHandle(h);
+#ifdef USE_EF_UT_TIME
+ if (ftOK && (z_ut != NULL)) {
+ FileTime2utime(&Modft, &(z_ut->mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ FileTime2utime(&Accft, &(z_ut->atime));
+ else
+ z_ut->atime = z_ut->mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ FileTime2utime(&Creft, &(z_ut->ctime));
+ else
+ z_ut->ctime = z_ut->mtime;
+ }
+#endif
+ FileTimeToLocalFileTime(&ft, &lft);
+ FileTimeToDosDateTime(&lft, &dh, &dl);
+ return(dh<<16) | dl;
+ }
+ else
+ return 0L;
+}
+
+#endif /* never */
+
+
+void ChangeNameForFAT(char *name)
+{
+ char *src, *dst, *next, *ptr, *dot, *start;
+ static char invalid[] = ":;,=+\"[]<>| \t";
+
+ if ( isalpha((uch)name[0]) && (name[1] == ':') )
+ start = name + 2;
+ else
+ start = name;
+
+ src = dst = start;
+ if ( (*src == '/') || (*src == '\\') )
+ src++, dst++;
+
+ while ( *src )
+ {
+ for ( next = src; *next && (*next != '/') && (*next != '\\'); next++ );
+
+ for ( ptr = src, dot = NULL; ptr < next; ptr++ )
+ if ( *ptr == '.' )
+ {
+ dot = ptr; /* remember last dot */
+ *ptr = '_';
+ }
+
+ if ( dot == NULL )
+ for ( ptr = src; ptr < next; ptr++ )
+ if ( *ptr == '_' )
+ dot = ptr; /* remember last _ as if it were a dot */
+
+ if ( dot && (dot > src) &&
+ ((next - dot <= 4) ||
+ ((next - src > 8) && (dot - src > 3))) )
+ {
+ if ( dot )
+ *dot = '.';
+
+ for ( ptr = src; (ptr < dot) && ((ptr - src) < 8); ptr++ )
+ *dst++ = *ptr;
+
+ for ( ptr = dot; (ptr < next) && ((ptr - dot) < 4); ptr++ )
+ *dst++ = *ptr;
+ }
+ else
+ {
+ if ( dot && (next - src == 1) )
+ *dot = '.'; /* special case: "." as a path component */
+
+ for ( ptr = src; (ptr < next) && ((ptr - src) < 8); ptr++ )
+ *dst++ = *ptr;
+ }
+
+ *dst++ = *next; /* either '/' or 0 */
+
+ if ( *next )
+ {
+ src = next + 1;
+
+ if ( *src == 0 ) /* handle trailing '/' on dirs ! */
+ *dst = 0;
+ }
+ else
+ break;
+ }
+
+ for ( src = start; *src != 0; ++src )
+ if ( (strchr(invalid, *src) != NULL) || (*src == ' ') )
+ *src = '_';
+}
+
+char *GetLongPathEA(char *name)
+{
+ return(NULL); /* volunteers ? */
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *GetLongPathEAW(wchar_t *name)
+{
+ return(NULL); /* volunteers ? */
+}
+#endif
+
+
+int IsFileNameValid(x)
+char *x;
+{
+ WIN32_FIND_DATA fd;
+ HANDLE h;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_name = (char *)alloca(strlen(x) + 1);
+
+ OemToAnsi(x, ansi_name);
+ x = ansi_name;
+#endif
+
+ if ((h = FindFirstFile(x, &fd)) == INVALID_HANDLE_VALUE)
+ return FALSE;
+ FindClose(h);
+ return TRUE;
+}
+
+char *getVolumeLabel(drive, vtime, vmode, vutim)
+ int drive; /* drive name: 'A' .. 'Z' or '\0' for current drive */
+ ulg *vtime; /* volume label creation time (DOS format) */
+ ulg *vmode; /* volume label file mode */
+ time_t *vutim;/* volume label creationtime (UNIX format) */
+
+/* If a volume label exists for the given drive, return its name and
+ pretend to set its time and mode. The returned name is static data. */
+{
+ char rootpath[4];
+ static char vol[14];
+ DWORD fnlen, flags;
+
+ *vmode = A_ARCHIVE | A_LABEL; /* this is what msdos returns */
+ *vtime = dostime(1980, 1, 1, 0, 0, 0); /* no true date info available */
+ *vutim = dos2unixtime(*vtime);
+ strcpy(rootpath, "x:\\");
+ rootpath[0] = (char)drive;
+ if (GetVolumeInformation(drive ? rootpath : NULL, vol, 13, NULL,
+ &fnlen, &flags, NULL, 0))
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ return (AnsiToOem(vol, vol), vol);
+#else
+ return vol;
+#endif
+ else
+ return NULL;
+}
+
+#endif /* !UTIL */
+
+
+
+int ZipIsWinNT(void) /* returns TRUE if real NT, FALSE if Win95 or Win32s */
+{
+ static DWORD g_PlatformId = 0xFFFFFFFF; /* saved platform indicator */
+
+ if (g_PlatformId == 0xFFFFFFFF) {
+ /* note: GetVersionEx() doesn't exist on WinNT 3.1 */
+ if (GetVersion() < 0x80000000)
+ g_PlatformId = TRUE;
+ else
+ g_PlatformId = FALSE;
+ }
+ return (int)g_PlatformId;
+}
+
+
+#ifndef UTIL
+#ifdef __WATCOMC__
+# include <io.h>
+# define _get_osfhandle _os_handle
+/* gaah -- Watcom's docs claim that _get_osfhandle exists, but it doesn't. */
+#endif
+
+#ifdef HAVE_FSEEKABLE
+/*
+ * return TRUE if file is seekable
+ */
+int fseekable(fp)
+FILE *fp;
+{
+ return GetFileType((HANDLE)_get_osfhandle(fileno(fp))) == FILE_TYPE_DISK;
+}
+#endif /* HAVE_FSEEKABLE */
+#endif /* !UTIL */
+
+
+#if 0 /* seems to be never used; try it out... */
+char *StringLower(char *szArg)
+{
+ char *szPtr;
+/* unsigned char *szPtr; */
+ for ( szPtr = szArg; *szPtr; szPtr++ )
+ *szPtr = lower[*szPtr];
+ return szArg;
+}
+#endif /* never */
+
+
+
+#ifdef W32_STAT_BANDAID
+
+/* All currently known variants of WIN32 operating systems (Windows 95/98,
+ * WinNT 3.x, 4.0, 5.0) have a nasty bug in the OS kernel concerning
+ * conversions between UTC and local time: In the time conversion functions
+ * of the Win32 API, the timezone offset (including seasonal daylight saving
+ * shift) between UTC and local time evaluation is erratically based on the
+ * current system time. The correct evaluation must determine the offset
+ * value as it {was/is/will be} for the actual time to be converted.
+ *
+ * The C runtime lib's stat() returns utc time-stamps so that
+ * localtime(timestamp) corresponds to the (potentially false) local
+ * time shown by the OS' system programs (Explorer, command shell dir, etc.)
+ *
+ * For the NTFS file system (and other filesystems that store time-stamps
+ * as UTC values), this results in st_mtime (, st_{c|a}time) fields which
+ * are not stable but vary according to the seasonal change of "daylight
+ * saving time in effect / not in effect".
+ *
+ * To achieve timestamp consistency of UTC (UT extra field) values in
+ * Zip archives, the Info-ZIP programs require work-around code for
+ * proper time handling in stat() (and other time handling routines).
+ */
+/* stat() functions under Windows95 tend to fail for root directories. *
+ * Watcom and Borland, at least, are affected by this bug. Watcom made *
+ * a partial fix for 11.0 but still missed some cases. This substitute *
+ * detects the case and fills in reasonable values. Otherwise we get *
+ * effects like failure to extract to a root dir because it's not found. */
+
+#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ int zstat_zipwin32(const char *path, z_stat *buf)
+#else
+ int zstat_zipwin32(const char *path, struct stat *buf)
+#endif
+{
+# ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ if (!zstat(path, buf))
+# else
+ if (!stat(path, buf))
+# endif
+ {
+#ifdef NT_TZBUG_WORKAROUND
+ /* stat was successful, now redo the time-stamp fetches */
+ int fs_uses_loctime = FSusesLocalTime(path);
+ HANDLE h;
+ FILETIME Modft, Accft, Creft;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path path
+#endif
+
+ Trace((stdout, "stat(%s) finds modtime %08lx\n", path, buf->st_mtime));
+ h = CreateFile(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (h != INVALID_HANDLE_VALUE) {
+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+ CloseHandle(h);
+
+ if (ftOK) {
+ if (!fs_uses_loctime) {
+ /* On a filesystem that stores UTC timestamps, we refill
+ * the time fields of the struct stat buffer by directly
+ * using the UTC values as returned by the Win32
+ * GetFileTime() API call.
+ */
+ FileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ FileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ FileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout,"NTFS, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ } else {
+ /* On VFAT and FAT-like filesystems, the FILETIME values
+ * are converted back to the stable local time before
+ * converting them to UTC unix time-stamps.
+ */
+ VFatFileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout, "VFAT, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ }
+ }
+ }
+# undef Ansi_Path
+#endif /* NT_TZBUG_WORKAROUND */
+ return 0;
+ }
+#ifdef W32_STATROOT_FIX
+ else
+ {
+ DWORD flags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(path) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path path
+#endif
+
+ flags = GetFileAttributes(Ansi_Path);
+ if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
+ Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
+ path));
+#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ memset(buf, 0, sizeof(z_stat));
+#else
+ memset(buf, 0, sizeof(struct stat));
+#endif
+ buf->st_atime = buf->st_ctime = buf->st_mtime =
+ dos2unixtime(DOSTIME_MINIMUM);
+ /* !!! you MUST NOT add a cast to the type of "st_mode" here;
+ * !!! different compilers do not agree on the "st_mode" size!
+ * !!! (And, some compiler may not declare the "mode_t" type
+ * !!! identifier, so you cannot use it, either.)
+ */
+ buf->st_mode = S_IFDIR | S_IREAD |
+ ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
+ return 0;
+ } /* assumes: stat() won't fail on non-dirs without good reason */
+# undef Ansi_Path
+ }
+#endif /* W32_STATROOT_FIX */
+ return -1;
+}
+
+
+# ifdef UNICODE_SUPPORT
+
+int zstat_zipwin32w(const wchar_t *pathw, zw_stat *buf)
+{
+ if (!zwstat(pathw, buf))
+ {
+#ifdef NT_TZBUG_WORKAROUND
+ /* stat was successful, now redo the time-stamp fetches */
+ int fs_uses_loctime = FSusesLocalTimeW(pathw);
+ HANDLE h;
+ FILETIME Modft, Accft, Creft;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(pathw) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path pathw
+#endif
+
+ Trace((stdout, "stat(%s) finds modtime %08lx\n", pathw, buf->st_mtime));
+ h = CreateFileW(Ansi_Path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (h != INVALID_HANDLE_VALUE) {
+ BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft);
+ CloseHandle(h);
+
+ if (ftOK) {
+ if (!fs_uses_loctime) {
+ /* On a filesystem that stores UTC timestamps, we refill
+ * the time fields of the struct stat buffer by directly
+ * using the UTC values as returned by the Win32
+ * GetFileTime() API call.
+ */
+ FileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ FileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ FileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout,"NTFS, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ } else {
+ /* On VFAT and FAT-like filesystems, the FILETIME values
+ * are converted back to the stable local time before
+ * converting them to UTC unix time-stamps.
+ */
+ VFatFileTime2utime(&Modft, &(buf->st_mtime));
+ if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Accft, &(buf->st_atime));
+ else
+ buf->st_atime = buf->st_mtime;
+ if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0)
+ VFatFileTime2utime(&Creft, &(buf->st_ctime));
+ else
+ buf->st_ctime = buf->st_mtime;
+ Tracev((stdout, "VFAT, recalculated modtime %08lx\n",
+ buf->st_mtime));
+ }
+ }
+ }
+# undef Ansi_Path
+#endif /* NT_TZBUG_WORKAROUND */
+ return 0;
+ }
+#ifdef W32_STATROOT_FIX
+ else
+ {
+ DWORD flags;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ char *ansi_path = (char *)alloca(strlen(pathw) + 1);
+
+ OemToAnsi(path, ansi_path);
+# define Ansi_Path ansi_path
+#else
+# define Ansi_Path pathw
+#endif
+
+ flags = GetFileAttributesW(Ansi_Path);
+ if (flags != 0xFFFFFFFF && flags & FILE_ATTRIBUTE_DIRECTORY) {
+ Trace((stderr, "\nstat(\"%s\",...) failed on existing directory\n",
+ pathw));
+#ifdef LARGE_FILE_SUPPORT /* E. Gordon 9/12/03 */
+ memset(buf, 0, sizeof(z_stat));
+#else
+ memset(buf, 0, sizeof(struct stat));
+#endif
+ buf->st_atime = buf->st_ctime = buf->st_mtime =
+ dos2unixtime(DOSTIME_MINIMUM);
+ /* !!! you MUST NOT add a cast to the type of "st_mode" here;
+ * !!! different compilers do not agree on the "st_mode" size!
+ * !!! (And, some compiler may not declare the "mode_t" type
+ * !!! identifier, so you cannot use it, either.)
+ */
+ buf->st_mode = S_IFDIR | S_IREAD |
+ ((flags & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE);
+ return 0;
+ } /* assumes: stat() won't fail on non-dirs without good reason */
+# undef Ansi_Path
+ }
+#endif /* W32_STATROOT_FIX */
+ return -1;
+}
+
+# endif
+
+
+#endif /* W32_STAT_BANDAID */
+
+
+
+#ifdef W32_USE_IZ_TIMEZONE
+#include "timezone.h"
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule);
+
+static void conv_to_rule(LPSYSTEMTIME lpw32tm, struct rule * ZCONST ptrule)
+{
+ if (lpw32tm->wYear != 0) {
+ ptrule->r_type = JULIAN_DAY;
+ ptrule->r_day = ydays[lpw32tm->wMonth - 1] + lpw32tm->wDay;
+ } else {
+ ptrule->r_type = MONTH_NTH_DAY_OF_WEEK;
+ ptrule->r_mon = lpw32tm->wMonth;
+ ptrule->r_day = lpw32tm->wDayOfWeek;
+ ptrule->r_week = lpw32tm->wDay;
+ }
+ ptrule->r_time = (long)lpw32tm->wHour * SECSPERHOUR +
+ (long)(lpw32tm->wMinute * SECSPERMIN) +
+ (long)lpw32tm->wSecond;
+}
+
+int GetPlatformLocalTimezone(register struct state * ZCONST sp,
+ void (*fill_tzstate_from_rules)(struct state * ZCONST sp_res,
+ ZCONST struct rule * ZCONST start,
+ ZCONST struct rule * ZCONST end))
+{
+ TIME_ZONE_INFORMATION tzinfo;
+ DWORD res;
+
+ /* read current timezone settings from registry if TZ envvar missing */
+ res = GetTimeZoneInformation(&tzinfo);
+ if (res != TIME_ZONE_ID_INVALID)
+ {
+ struct rule startrule, stoprule;
+
+ conv_to_rule(&(tzinfo.StandardDate), &stoprule);
+ conv_to_rule(&(tzinfo.DaylightDate), &startrule);
+ sp->timecnt = 0;
+ sp->ttis[0].tt_abbrind = 0;
+ if ((sp->charcnt =
+ WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1,
+ sp->chars, sizeof(sp->chars), NULL, NULL))
+ == 0)
+ sp->chars[sp->charcnt++] = '\0';
+ sp->ttis[1].tt_abbrind = sp->charcnt;
+ sp->charcnt +=
+ WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1,
+ sp->chars + sp->charcnt,
+ sizeof(sp->chars) - sp->charcnt, NULL, NULL);
+ if ((sp->charcnt - sp->ttis[1].tt_abbrind) == 0)
+ sp->chars[sp->charcnt++] = '\0';
+ sp->ttis[0].tt_gmtoff = - (tzinfo.Bias + tzinfo.StandardBias)
+ * MINSPERHOUR;
+ sp->ttis[1].tt_gmtoff = - (tzinfo.Bias + tzinfo.DaylightBias)
+ * MINSPERHOUR;
+ sp->ttis[0].tt_isdst = 0;
+ sp->ttis[1].tt_isdst = 1;
+ sp->typecnt = (startrule.r_mon == 0 && stoprule.r_mon == 0) ? 1 : 2;
+
+ if (sp->typecnt > 1)
+ (*fill_tzstate_from_rules)(sp, &startrule, &stoprule);
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif /* W32_USE_IZ_TIMEZONE */
+
+
+
+#ifndef WINDLL
+/* This replacement getch() function was originally created for Watcom C
+ * and then additionally used with CYGWIN. Since UnZip 5.4, all other Win32
+ * ports apply this replacement rather that their supplied getch() (or
+ * alike) function. There are problems with unabsorbed LF characters left
+ * over in the keyboard buffer under Win95 (and 98) when ENTER was pressed.
+ * (Under Win95, ENTER returns two(!!) characters: CR-LF.) This problem
+ * does not appear when run on a WinNT console prompt!
+ */
+
+/* Watcom 10.6's getch() does not handle Alt+<digit><digit><digit>. */
+/* Note that if PASSWD_FROM_STDIN is defined, the file containing */
+/* the password must have a carriage return after the word, not a */
+/* Unix-style newline (linefeed only). This discards linefeeds. */
+
+int getch_win32(void)
+{
+ HANDLE stin;
+ DWORD rc;
+ unsigned char buf[2];
+ int ret = -1;
+ DWORD odemode = ~(DWORD)0;
+
+# ifdef PASSWD_FROM_STDIN
+ stin = GetStdHandle(STD_INPUT_HANDLE);
+# else
+ stin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (stin == INVALID_HANDLE_VALUE)
+ return -1;
+# endif
+ if (GetConsoleMode(stin, &odemode))
+ SetConsoleMode(stin, ENABLE_PROCESSED_INPUT); /* raw except ^C noticed */
+ if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
+ ret = buf[0];
+ /* when the user hits return we get CR LF. We discard the LF, not the CR,
+ * because when we call this for the first time after a previous input
+ * such as the one for "replace foo? [y]es, ..." the LF may still be in
+ * the input stream before whatever the user types at our prompt. */
+ if (ret == '\n')
+ if (ReadFile(stin, &buf, 1, &rc, NULL) && rc == 1)
+ ret = buf[0];
+ if (odemode != ~(DWORD)0)
+ SetConsoleMode(stin, odemode);
+# ifndef PASSWD_FROM_STDIN
+ CloseHandle(stin);
+# endif
+ return ret;
+}
+
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s.\n\n";
+#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__))
+ char buf[80];
+#if (defined(_MSC_VER) && (_MSC_VER > 900))
+ char buf2[80];
+#endif
+#endif
+
+/* Define the compiler name and version strings */
+#if defined(_MSC_VER) /* MSC == MSVC++, including the SDK compiler */
+ sprintf(buf, "Microsoft C %d.%02d ", _MSC_VER/100, _MSC_VER%100);
+# define COMPILER_NAME1 buf
+# if (_MSC_VER == 800)
+# define COMPILER_NAME2 "(Visual C++ v1.1)"
+# elif (_MSC_VER == 850)
+# define COMPILER_NAME2 "(Windows NT v3.5 SDK)"
+# elif (_MSC_VER == 900)
+# define COMPILER_NAME2 "(Visual C++ v2.x)"
+# elif (_MSC_VER > 900)
+ sprintf(buf2, "(Visual C++ v%d.%d)", _MSC_VER/100 - 6, _MSC_VER%100/10);
+# define COMPILER_NAME2 buf2
+# else
+# define COMPILER_NAME2 "(bad version)"
+# endif
+#elif defined(__WATCOMC__)
+# if (__WATCOMC__ % 10 > 0)
+/* We do this silly test because __WATCOMC__ gives two digits for the */
+/* minor version, but Watcom packaging prefers to show only one digit. */
+ sprintf(buf, "Watcom C/C++ %d.%02d", __WATCOMC__ / 100,
+ __WATCOMC__ % 100);
+# else
+ sprintf(buf, "Watcom C/C++ %d.%d", __WATCOMC__ / 100,
+ (__WATCOMC__ % 100) / 10);
+# endif /* __WATCOMC__ % 10 > 0 */
+# define COMPILER_NAME1 buf
+# define COMPILER_NAME2 ""
+#elif defined(__TURBOC__)
+# ifdef __BORLANDC__
+# define COMPILER_NAME1 "Borland C++"
+# if (__BORLANDC__ == 0x0452) /* __BCPLUSPLUS__ = 0x0320 */
+# define COMPILER_NAME2 " 4.0 or 4.02"
+# elif (__BORLANDC__ == 0x0460) /* __BCPLUSPLUS__ = 0x0340 */
+# define COMPILER_NAME2 " 4.5"
+# elif (__BORLANDC__ == 0x0500) /* __TURBOC__ = 0x0500 */
+# define COMPILER_NAME2 " 5.0"
+# elif (__BORLANDC__ == 0x0520) /* __TURBOC__ = 0x0520 */
+# define COMPILER_NAME2 " 5.2 (C++ Builder 1.0)"
+# elif (__BORLANDC__ == 0x0530) /* __BCPLUSPLUS__ = 0x0530 */
+# define COMPILER_NAME2 " 5.3 (C++ Builder 3.0)"
+# elif (__BORLANDC__ == 0x0540) /* __BCPLUSPLUS__ = 0x0540 */
+# define COMPILER_NAME2 " 5.4 (C++ Builder 4.0)"
+# elif (__BORLANDC__ == 0x0550) /* __BCPLUSPLUS__ = 0x0550 */
+# define COMPILER_NAME2 " 5.5 (C++ Builder 5.0)"
+# elif (__BORLANDC__ == 0x0551) /* __BCPLUSPLUS__ = 0x0551 */
+# define COMPILER_NAME2 " 5.5.1 (C++ Builder 5.0.1)"
+# elif (__BORLANDC__ == 0x0560) /* __BCPLUSPLUS__ = 0x0560 */
+# define COMPILER_NAME2 " 5.6 (C++ Builder 6)"
+# else
+# define COMPILER_NAME2 " later than 5.6"
+# endif
+# else /* !__BORLANDC__ */
+# define COMPILER_NAME1 "Turbo C"
+# if (__TURBOC__ >= 0x0400) /* Kevin: 3.0 -> 0x0401 */
+# define COMPILER_NAME2 "++ 3.0 or later"
+# elif (__TURBOC__ == 0x0295) /* [661] vfy'd by Kevin */
+# define COMPILER_NAME2 "++ 1.0"
+# endif
+# endif /* __BORLANDC__ */
+#elif defined(__GNUC__)
+# ifdef __RSXNT__
+# if (defined(__DJGPP__) && !defined(__EMX__))
+ sprintf(buf, "rsxnt(djgpp v%d.%02d) / gcc ",
+ __DJGPP__, __DJGPP_MINOR__);
+# define COMPILER_NAME1 buf
+# elif defined(__DJGPP__)
+ sprintf(buf, "rsxnt(emx+djgpp v%d.%02d) / gcc ",
+ __DJGPP__, __DJGPP_MINOR__);
+# define COMPILER_NAME1 buf
+# elif (defined(__GO32__) && !defined(__EMX__))
+# define COMPILER_NAME1 "rsxnt(djgpp v1.x) / gcc "
+# elif defined(__GO32__)
+# define COMPILER_NAME1 "rsxnt(emx + djgpp v1.x) / gcc "
+# elif defined(__EMX__)
+# define COMPILER_NAME1 "rsxnt(emx)+gcc "
+# else
+# define COMPILER_NAME1 "rsxnt(unknown) / gcc "
+# endif
+# elif defined(__CYGWIN__)
+# define COMPILER_NAME1 "Cygnus win32 / gcc "
+# elif defined(__MINGW32__)
+# define COMPILER_NAME1 "mingw32 / gcc "
+# else
+# define COMPILER_NAME1 "gcc "
+# endif
+# define COMPILER_NAME2 __VERSION__
+#elif defined(__LCC__)
+# define COMPILER_NAME1 "LCC-Win32"
+# define COMPILER_NAME2 ""
+#else
+# define COMPILER_NAME1 "unknown compiler (SDK?)"
+# define COMPILER_NAME2 ""
+#endif
+
+/* Define the compile date string */
+#ifdef __DATE__
+# define COMPILE_DATE " on " __DATE__
+#else
+# define COMPILE_DATE ""
+#endif
+
+ printf(CompiledWith, COMPILER_NAME1, COMPILER_NAME2,
+ "\nWindows 9x / Windows NT", " (32-bit)", COMPILE_DATE);
+
+ return;
+
+} /* end function version_local() */
+#endif /* !WINDLL */
+
+
+/* --------------------------------------------------- */
+/* Large File Support
+ *
+ * Moved to Win32i64.c to avoid conflicts in same name functions
+ * in WiZ using UnZip and Zip libraries.
+ * 9/25/2003
+ */
+
+
+/* --------------------------------------------------- */
+/* Unicode Support for Win32
+ *
+ */
+
+#ifdef UNICODE_SUPPORT
+# if 0
+
+ /* get the wide command line and convert to argvw */
+ /* windows ignores argv and gets argvw separately */
+ zchar **get_wide_argv(argv)
+ char **argv;
+ {
+ int i;
+ int argc;
+ int size;
+ zchar **argvw = NULL;
+ zchar *commandline = NULL;
+ zchar **a = NULL;
+
+ commandline = GetCommandLineW();
+ a = CommandLineToArgvW(commandline, &argc);
+
+ if (a == NULL) {
+ /* failed */
+ ZIPERR(ZE_COMPERR, "get_wide_argv");
+ }
+
+ /* copy args so can use free_args() */
+ if ((argvw = (zchar **)malloc((argc + 1) * sizeof(zchar *))) == NULL) {
+ ZIPERR(ZE_MEM, "get_wide_argv");
+ }
+ for (i = 0; i < argc; i++) {
+ size = zstrlen(a[i]) + 1;
+ if ((argvw[i] = (zchar *)malloc(size * sizeof(zchar))) == NULL) {
+ ZIPERR(ZE_MEM, "get_wide_argv");
+ }
+ if ((argvw[i] = copy_zstring(a[i])) == NULL) {
+ ZIPERR(ZE_MEM, "get_wide_argv");
+ }
+ }
+ argvw[argc] = L'\0';
+
+ /* free original argvw */
+ LocalFree(a);
+
+ return argvw;
+ }
+# endif
+
+
+/* convert wide character string to multi-byte character string */
+/* win32 version */
+char *wide_to_local_string(wide_string)
+ zwchar *wide_string;
+{
+ int i;
+ wchar_t wc;
+ int bytes_char;
+ int default_used;
+ int wsize = 0;
+ int max_bytes = 9;
+ char buf[9];
+ char *buffer = NULL;
+ char *local_string = NULL;
+
+ if (wide_string == NULL)
+ return NULL;
+
+ for (wsize = 0; wide_string[wsize]; wsize++) ;
+
+ if (max_bytes < MB_CUR_MAX)
+ max_bytes = MB_CUR_MAX;
+
+ if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wide_to_local_string");
+ }
+
+ /* convert it */
+ buffer[0] = '\0';
+ for (i = 0; i < wsize; i++) {
+ if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
+ /* wchar_t probably 2 bytes */
+ /* could do surrogates if state_dependent and wctomb can do */
+ wc = zwchar_to_wchar_t_default_char;
+ } else {
+ wc = (wchar_t)wide_string[i];
+ }
+ /* Unter some vendor's C-RTL, the Wide-to-MultiByte conversion functions
+ * (like wctomb() et. al.) do not use the same codepage as the other
+ * string arguments I/O functions (fopen, mkdir, rmdir etc.).
+ * Therefore, we have to fall back to the underlying Win32-API call to
+ * achieve a consistent behaviour for all supported compiler environments.
+ * Failing RTLs are for example:
+ * Borland (locale uses OEM-CP as default, but I/O functions expect ANSI
+ * names)
+ * Watcom (only "C" locale, wctomb() always uses OEM CP)
+ * (in other words: all supported environments except the Microsoft RTLs)
+ */
+ bytes_char = WideCharToMultiByte(
+ CP_ACP, WC_COMPOSITECHECK,
+ &wc, 1,
+ (LPSTR)buf, sizeof(buf),
+ NULL, &default_used);
+ if (default_used)
+ bytes_char = -1;
+ if (unicode_escape_all) {
+ if (bytes_char == 1 && (uch)buf[0] <= 0x7f) {
+ /* ASCII */
+ strncat(buffer, buf, 1);
+ } else {
+ /* use escape for wide character */
+ char *e = wide_char_to_escape_string(wide_string[i]);
+ strcat(buffer, e);
+ free(e);
+ }
+ } else if (bytes_char > 0) {
+ /* multi-byte char */
+ strncat(buffer, buf, bytes_char);
+ } else {
+ /* no MB for this wide */
+ if (use_wide_to_mb_default) {
+ /* default character */
+ strcat(buffer, wide_to_mb_default_string);
+ } else {
+ /* use escape for wide character */
+ char *e = wide_char_to_escape_string(wide_string[i]);
+ strcat(buffer, e);
+ free(e);
+ }
+ }
+ }
+ if ((local_string = (char *)realloc(buffer, strlen(buffer) + 1)) == NULL) {
+ free(buffer);
+ ZIPERR(ZE_MEM, "wide_to_local_string");
+ }
+
+ return local_string;
+}
+
+/* convert multi-byte character string to wide character string */
+/* win32 version */
+zwchar *local_to_wide_string(local_string)
+ char *local_string;
+{
+ int wsize;
+ wchar_t *wc_string;
+ zwchar *wide_string;
+
+ /* for now try to convert as string - fails if a bad char in string */
+ wsize = MultiByteToWideChar(CP_ACP, 0,
+ local_string, -1, NULL, 0);
+ if (wsize == (size_t)-1) {
+ /* could not convert */
+ return NULL;
+ }
+
+ /* convert it */
+ if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
+ ZIPERR(ZE_MEM, "local_to_wide_string");
+ }
+ wsize = MultiByteToWideChar(CP_ACP, 0,
+ local_string, -1,
+ wc_string, wsize + 1);
+ wc_string[wsize] = (wchar_t) 0;
+
+ /* in case wchar_t is not zwchar */
+ if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
+ free(wc_string);
+ ZIPERR(ZE_MEM, "local_to_wide_string");
+ }
+ for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ;
+ wide_string[wsize] = (zwchar)0;
+ free(wc_string);
+
+ return wide_string;
+}
+#endif /* UNICODE_SUPPORT */
+
+
+/*
+# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+/* convert oem to ansi character string */
+char *oem_to_local_string(local_string, oem_string)
+ char *local_string;
+ char *oem_string;
+{
+ /* convert OEM to ANSI character set */
+ OemToChar(oem_string, local_string);
+
+ return local_string;
+}
+/*
+# endif
+*/
+
+
+/*
+#if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+/* convert local to oem character string */
+char *local_to_oem_string(oem_string, local_string)
+ char *oem_string;
+ char *local_string;
+{
+ /* convert to OEM display character set */
+ CharToOem(local_string, oem_string);
+ return oem_string;
+}
+/*
+#endif
+*/
+
diff --git a/win32/win32i64.c b/win32/win32i64.c
new file mode 100644
index 0000000..a07eb1a
--- /dev/null
+++ b/win32/win32i64.c
@@ -0,0 +1,115 @@
+/*
+ win32/win32i64.c - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+
+#include "../zip.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+#include <windows.h>
+/* for LARGE_FILE_SUPPORT but may not be needed */
+#include <io.h>
+
+
+/* --------------------------------------------------- */
+/* Large File Support
+ *
+ * Initial functions by E. Gordon and R. Nausedat
+ * 9/10/2003
+ *
+ * These implement 64-bit file support for Windows. The
+ * defines and headers are in win32/osdep.h.
+ *
+ * These moved from win32.c by Mike White to avoid conflicts
+ * in WiZ of same name functions in UnZip and Zip libraries.
+ * 9/25/04 EG
+ */
+
+#if defined(LARGE_FILE_SUPPORT) && !defined(__CYGWIN__)
+
+/* 64-bit buffered ftello
+ *
+ * Win32 does not provide a 64-bit buffered
+ * ftell (in the published api anyway) so below provides
+ * hopefully close version.
+ * We have not gotten _telli64 to work with buffered
+ * streams. Below cheats by using fgetpos improperly and
+ * may not work on other ports.
+ */
+
+zoff_t zftello(stream)
+ FILE *stream;
+{
+ fpos_t fpos = 0;
+
+ if (fgetpos(stream, &fpos) != 0) {
+ return -1L;
+ } else {
+ return fpos;
+ }
+}
+
+
+/* 64-bit buffered fseeko
+ *
+ * Win32 does not provide a 64-bit buffered
+ * fseeko so use _lseeki64 and fflush. Note
+ * that SEEK_CUR can lose track of location
+ * if fflush is done between the last buffered
+ * io and this call.
+ */
+
+int zfseeko(stream, offset, origin)
+ FILE *stream;
+ zoff_t offset;
+ int origin;
+{
+ zoff_t location;
+
+ location = zftello(stream);
+ fflush(stream);
+ if (origin == SEEK_CUR) {
+ /* instead of synching up lseek easier just to figure and
+ use an absolute offset */
+ offset = location + offset;
+ location = _lseeki64(fileno(stream), offset, SEEK_SET);
+ } else {
+ location = _lseeki64(fileno(stream), offset, origin);
+ }
+ if (location == -1L) {
+ return -1L;
+ } else {
+ return 0;
+ }
+}
+#endif /* Win32 LARGE_FILE_SUPPORT */
+
+#if 0
+FILE* zfopen(filename,mode)
+char *filename;
+char *mode;
+{
+FILE* fTemp;
+
+ fTemp = fopen(filename,mode);
+ if( fTemp == NULL )
+ return NULL;
+
+ /* sorry, could not make VC60 and its rtl work properly without setting the file buffer to NULL. the */
+ /* problem seems to be _telli64 which seems to return the max stream position, comments are welcome */
+ setbuf(fTemp,NULL);
+
+ return fTemp;
+}
+#endif
+/* --------------------------------------------------- */
diff --git a/win32/win32zip.c b/win32/win32zip.c
new file mode 100644
index 0000000..07c8886
--- /dev/null
+++ b/win32/win32zip.c
@@ -0,0 +1,1980 @@
+/*
+ win32/win32zip.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef UTIL /* this file contains nothing used by UTIL */
+
+#include "../zip.h"
+
+#include <ctype.h>
+#if !defined(__EMX__) && !defined(__CYGWIN__)
+#include <direct.h> /* for rmdir() */
+#endif
+#include <time.h>
+
+#ifndef __BORLANDC__
+#include <sys/utime.h>
+#else
+#include <utime.h>
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h> /* for findfirst/findnext stuff */
+#ifdef __RSXNT__
+# include "../win32/rsxntwin.h"
+#endif
+
+#include <io.h>
+
+#define PAD 0
+#define PATH_END '/'
+#define HIDD_SYS_BITS (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)
+
+
+#ifdef UNICODE_SUPPORT
+typedef struct zdirscanw {
+ HANDLE d_hFindFile;
+ int d_first;
+ WIN32_FIND_DATAW d_fdw;
+} zDIRSCANW;
+#endif
+
+typedef struct zdirscan {
+ HANDLE d_hFindFile;
+ int d_first;
+ WIN32_FIND_DATA d_fd;
+} zDIRSCAN;
+
+#define INVALID_WIN32_FILE_ATTRIBS ~0
+#ifdef UNICODE_SUPPORT
+#define GetDirAttribsW(d) ((d)->d_fdw.dwFileAttributes)
+#endif
+#define GetDirAttribs(d) ((d)->d_fd.dwFileAttributes)
+
+#include "../win32/win32zip.h"
+#include "../win32/nt.h"
+
+/* Local functions */
+local zDIRSCAN * OpenDirScan OF((ZCONST char *n));
+local struct zdirscan * GetNextDirEntry OF((zDIRSCAN *d));
+local void CloseDirScan OF((zDIRSCAN *d));
+
+#ifdef UNICODE_SUPPORT
+local zDIRSCANW * OpenDirScanW OF((ZCONST wchar_t *wn));
+local struct zdirscanw * GetNextDirEntryW OF((zDIRSCANW *dw));
+local void CloseDirScanW OF((zDIRSCANW *dw));
+#endif
+
+local char *readd OF((zDIRSCAN *));
+#ifdef UNICODE_SUPPORT
+local wchar_t *readdw OF((zDIRSCANW *));
+#endif
+
+local int wild_recurse OF((char *, char *));
+#ifdef UNICODE_SUPPORT
+local int wild_recursew OF((wchar_t *, wchar_t *));
+#endif
+
+#ifdef NTSD_EAS
+ local void GetSD OF((char *path, char **bufptr, ush *size,
+ char **cbufptr, ush *csize));
+#endif
+#ifdef USE_EF_UT_TIME
+ local int GetExtraTime OF((struct zlist far *z, iztimes *z_utim));
+#endif
+local int procname_win32 OF((char *n, int caseflag, DWORD attribs));
+#ifdef UNICODE_SUPPORT
+local int procname_win32w OF((wchar_t *n, int caseflag, DWORD attribs));
+#endif
+
+/* Module level variables */
+extern char *label /* = NULL */ ; /* defined in fileio.c */
+local ulg label_time = 0;
+local ulg label_mode = 0;
+local time_t label_utim = 0;
+
+/* Module level constants */
+local ZCONST char wild_match_all[] = "*.*";
+
+
+#ifdef UNICODE_SUPPORT
+
+local zDIRSCANW *OpenDirScanW(nw)
+ZCONST wchar_t *nw; /* directory to open */
+/* Start searching for files in the MSDOS directory n */
+{
+ zDIRSCANW *dw; /* malloc'd return value */
+ wchar_t *pw; /* malloc'd temporary string */
+ wchar_t *qw;
+ size_t i;
+
+ if ((dw = (zDIRSCANW *)malloc(sizeof(zDIRSCANW))) == NULL) {
+ return NULL;
+ }
+
+ if ((pw = (wchar_t *)malloc(wcslen(nw) * sizeof(wchar_t) +
+ (2 + sizeof(wild_match_all)) * sizeof(wchar_t))) == NULL) {
+ if (dw != NULL) free((zvoid *)dw);
+ return NULL;
+ }
+ wcscpy(pw, nw);
+
+ qw = pw + wcslen(pw);
+ if ((qw - pw) > 0 && wcschr(pw, (wchar_t)':') == (qw - 1))
+ *qw++ = (wchar_t)'.';
+ if ((qw - pw) > 0 && wcschr(pw, (wchar_t)'/') != (qw - 1))
+ *qw++ = (wchar_t)'/';
+
+ for (i = 0; i < strlen(wild_match_all); i++) {
+ qw[i] = (wchar_t)wild_match_all[i];
+ }
+ qw[i] = (wchar_t)'\0';
+
+ dw->d_hFindFile = FindFirstFileW(pw, &dw->d_fdw);
+ free((zvoid *)pw);
+
+ if (dw->d_hFindFile == INVALID_HANDLE_VALUE)
+ {
+ free((zvoid *)dw);
+ return NULL;
+ }
+
+ dw->d_first = 1;
+ return dw;
+}
+
+#endif
+
+local zDIRSCAN *OpenDirScan(n)
+ZCONST char *n; /* directory to open */
+/* Start searching for files in the MSDOS directory n */
+{
+ zDIRSCAN *d; /* malloc'd return value */
+ char *p; /* malloc'd temporary string */
+ char *q;
+
+ if ((d = (zDIRSCAN *)malloc(sizeof(zDIRSCAN))) == NULL ||
+ (p = malloc(strlen(n) + (2 + sizeof(wild_match_all)))) == NULL) {
+ if (d != NULL) free((zvoid *)d);
+ return NULL;
+ }
+ strcpy(p, n);
+ q = p + strlen(p);
+ if ((q - p) > 0 && MBSRCHR(p, ':') == (q - 1))
+ *q++ = '.';
+ if ((q - p) > 0 && MBSRCHR(p, '/') != (q - 1))
+ *q++ = '/';
+ strcpy(q, wild_match_all);
+
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ OemToAnsi(p, p);
+#endif
+ d->d_hFindFile = FindFirstFile(p, &d->d_fd);
+ free((zvoid *)p);
+
+ if (d->d_hFindFile == INVALID_HANDLE_VALUE)
+ {
+ free((zvoid *)d);
+ return NULL;
+ }
+
+ d->d_first = 1;
+ return d;
+}
+
+
+#ifdef UNICODE_SUPPORT
+
+local struct zdirscanw *GetNextDirEntryW(dw)
+zDIRSCANW *dw; /* directory stream to read from */
+/* Return pointer to first or next directory entry, or NULL if end. */
+{
+ if (dw->d_first)
+ dw->d_first = 0;
+ else
+ {
+ if (!FindNextFileW(dw->d_hFindFile, &dw->d_fdw))
+ return NULL;
+ }
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ CharToOemW(dw->d_fdw.cFileName, dw->d_fdw.cFileName);
+#endif
+ return (struct zdirscanw *)dw;
+}
+
+#endif
+
+local struct zdirscan *GetNextDirEntry(d)
+zDIRSCAN *d; /* directory stream to read from */
+/* Return pointer to first or next directory entry, or NULL if end. */
+{
+ if (d->d_first)
+ d->d_first = 0;
+ else
+ {
+ if (!FindNextFile(d->d_hFindFile, &d->d_fd))
+ return NULL;
+ }
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ AnsiToOem(d->d_fd.cFileName, d->d_fd.cFileName);
+#endif
+ return (struct zdirscan *)d;
+}
+
+local void CloseDirScan(d)
+zDIRSCAN *d; /* directory stream to close */
+{
+ FindClose(d->d_hFindFile);
+ free((zvoid *)d);
+}
+
+#ifdef UNICODE_SUPPORT
+
+local void CloseDirScanW(dw)
+zDIRSCANW *dw; /* directory stream to close */
+{
+ FindClose(dw->d_hFindFile);
+ free((zvoid *)dw);
+}
+
+#endif
+
+
+#ifdef UNICODE_SUPPORT
+
+local wchar_t *readdw(dw)
+ zDIRSCANW *dw; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream dw, or NULL if
+ no more entries or an error occurs. */
+{
+ struct zdirscanw *ew;
+
+ do
+ ew = GetNextDirEntryW(dw);
+ while (ew &&
+ ((!hidden_files && ew->d_fdw.dwFileAttributes & HIDD_SYS_BITS) ||
+ (only_archive_set &&
+ !(ew->d_fdw.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) &&
+ !(ew->d_fdw.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))));
+ if (ew == NULL)
+ return (wchar_t *) NULL;
+ return ew->d_fdw.cFileName;
+}
+
+#endif
+
+local char *readd(d)
+zDIRSCAN *d; /* directory stream to read from */
+/* Return a pointer to the next name in the directory stream d, or NULL if
+ no more entries or an error occurs. */
+{
+ struct zdirscan *e;
+
+ do
+ e = GetNextDirEntry(d);
+ while (e &&
+ ((!hidden_files && e->d_fd.dwFileAttributes & HIDD_SYS_BITS) ||
+ (only_archive_set &&
+ !(e->d_fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) &&
+ !(e->d_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))));
+ /* When a wide character that is not supported by the current character
+ set is found, FindFirstFile and FindNextFile return a "?" in that spot.
+ A question mark is illegal in file names, so this flags that something
+ needs to be done. It seems the fix is to use the 8.3 name in
+ this case, as that allows directory scans to continue.
+ */
+ if (e == NULL)
+ return (char *) NULL;
+ if (strchr(e->d_fd.cFileName, '?') && e->d_fd.cAlternateFileName) {
+ /* Have '?' in name, assume wide character we can't handle is in
+ the name and use short name if there is one.
+ */
+ return e->d_fd.cAlternateFileName;
+ }
+ return e->d_fd.cFileName;
+}
+
+
+#if 0
+/* scan for the file in p and return Windows long name */
+char *get_win32_longpath(p, n)
+ char *p; /* path to get short name path for */
+ char **n; /* pointer to name in returned path */
+{
+ char *q; /* return string */
+ char *c;
+ int is_dir = 0;
+ char *f;
+ char *fp;
+ int nr;
+ int fplen;
+ int fplen2;
+ HANDLE d_hFindFile;
+ WIN32_FIND_DATA d_fd;
+ int slashes = 0;
+ int returnslashes = 0;
+
+ if (p == NULL)
+ return NULL;
+
+ /* count path components */
+ for (f = p; *f; f++) {
+ if (*f == '/' || *f == '\\') {
+ slashes++;
+ }
+ }
+ /* Ignore trailing slash */
+ if (*p && (*(f - 1) == '/' || *(f - 1) == '\\'))
+ slashes--;
+
+ /* get the length of the full path */
+ fplen = GetFullPathName(p, 0, NULL, NULL);
+
+ if ((fp = malloc(fplen + 1)) == NULL) {
+ return NULL;
+ }
+ /* get full path */
+ fplen2 = GetFullPathName(p, fplen, fp, &f);
+ if (fplen2 > fplen) {
+ /* something changed */
+ free(fp);
+ return NULL;
+ }
+ c = fp + strlen(fp) - 1;
+ if (*c == '\\' || *c == '/') {
+ is_dir = 1;
+ *c = '\0';
+ }
+
+ d_hFindFile = FindFirstFile(fp, &d_fd);
+ free(fp);
+
+ if (d_hFindFile == INVALID_HANDLE_VALUE)
+ {
+ return NULL;
+ }
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ AnsiToOem(d->d_fd.cFileName, d->d_fd.cFileName);
+#endif
+
+ FindClose(d_hFindFile);
+
+ if (d_fd.cFileName == NULL) {
+ return NULL;
+ }
+
+ /* get the length of the full path */
+ fplen = GetFullPathName(d_fd.cFileName, 0, NULL, NULL);
+
+ if ((fp = malloc(fplen + 1)) == NULL) {
+ return NULL;
+ }
+ /* get full path */
+ fplen2 = GetFullPathName(d_fd.cFileName, fplen, fp, &f);
+ if (fplen2 > fplen) {
+ /* something changed */
+ free(fp);
+ return NULL;
+ }
+
+ /* characters from end to start of last component */
+ nr = 0;
+
+ /* find start of relative path we came in with */
+ for (f = fp + strlen(fp); f != fp; f--) {
+ if (*f == ':')
+ break;
+ if (*f == '/' || *f == '\\') {
+ returnslashes++;
+ /* convert \ to / */
+ *f = '/';
+ if (nr == 0)
+ /* first slash from end */
+ nr = strlen(fp) - (f - fp);
+ if (returnslashes > slashes)
+ break;
+ }
+ if (*f == '\\' && *(f + 1) == '\\')
+ break;
+ }
+ if (f != fp)
+ /* on slash in middle */
+ f++;
+
+ if ((q = malloc(strlen(f) + 2)) == NULL) {
+ return NULL;
+ }
+ strcpy(q, f);
+ *n = q + (strlen(q) - nr + 1);
+ if (is_dir) {
+ strcat(q, "/");
+ }
+ free(fp);
+
+ return q;
+}
+#endif
+
+
+#if 0
+/* scan for the file in p and return Windows UTF-8 name */
+char *get_win32_utf8path(p)
+ char *p; /* path to get utf-8 name for */
+{
+ char *q; /* return string */
+ char *r = NULL;
+ int is_dir = 0;
+ char *f;
+ char *fcp;
+ char *fp;
+ wchar_t *qw;
+ char *lastc = '\0';
+ int fplen;
+ int fplen2;
+ int ulen;
+ int ulenw;
+ HANDLE d_hFindFile;
+ WIN32_FIND_DATAW d_fd;
+ int pathslashes = 0;
+ int componentslashes = 0;
+ int slashes = 0;
+
+ if (p == NULL)
+ return NULL;
+
+ /* count path components */
+ for (f = p; *f; PREINCSTR(f)) {
+ if (*f == '/' || *f == '\\') {
+ slashes++;
+ }
+ lastc = f;
+ }
+ /* do not count trailing / */
+ if (*lastc == '/' || *lastc == '\\') {
+ is_dir = 1;
+ slashes--;
+ }
+
+ /* Get the short path (as a bad long path could cause FindFirstFile to fail) */
+
+ /* get the length of the short path */
+ fplen = GetShortPathName(p, NULL, 0);
+
+ if ((fp = malloc(fplen + 1)) == NULL) {
+ return NULL;
+ }
+ /* get short path */
+ fplen2 = GetShortPathName(p, fp, fplen);
+ if (fplen2 > fplen) {
+ /* something changed */
+ free(fp);
+ return NULL;
+ }
+
+ for (pathslashes = 0; pathslashes <= slashes; pathslashes++)
+ {
+
+ /* get component path */
+ if ((fcp = malloc(fplen + 1)) == NULL) {
+ return NULL;
+ }
+ strcpy(fcp, fp);
+ componentslashes = 0;
+ for (f = fcp; *f; PREINCSTR(f)) {
+ if (*f == '/' || *f == '\\') {
+ componentslashes++;
+ if (componentslashes > pathslashes)
+ break;
+ }
+ lastc = f;
+ }
+ *f = '\0';
+
+
+ /* Get information for the file, including wide path */
+
+ /* get length */
+ ulenw = MultiByteToWideChar(
+ CP_ACP, /* ANSI code page */
+ 0, /* flags for character-type options */
+ fcp, /* string to convert */
+ -1, /* string length (-1 = NULL terminated) */
+ NULL, /* buffer */
+ 0 ); /* buffer length (0 = return length) */
+ if (ulenw == 0) {
+ /* failed */
+ free(fcp);
+ free(fp);
+ return NULL;
+ }
+ ulenw++;
+ /* get length in bytes */
+ ulen = sizeof(wchar_t) * (ulenw + 1);
+ if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
+ free(fcp);
+ free(fp);
+ return NULL;
+ }
+ /* convert multibyte to wide */
+ ulen = MultiByteToWideChar(
+ CP_ACP, /* ANSI code page */
+ 0, /* flags for character-type options */
+ fcp, /* string to convert */
+ -1, /* string length (-1 = NULL terminated) */
+ qw, /* buffer */
+ ulenw); /* buffer length (0 = return length) */
+ if (ulen == 0) {
+ /* failed */
+ free(qw);
+ free(fcp);
+ free(fp);
+ return 0;
+ }
+
+ d_hFindFile = FindFirstFileW(qw, &d_fd);
+ /* If this Win32 platform does not support Unicode wide paths
+ this returns INVALID_HANDLE_VALUE and the OS error is
+ "No such file or directory". We return NULL and go with
+ the UTF-8 version of z->iname in f->uname.
+ */
+ free(qw);
+ free(fcp);
+ FindClose(d_hFindFile);
+
+ if (d_hFindFile == INVALID_HANDLE_VALUE)
+ {
+ return NULL;
+ }
+
+ /* Get buffer length */
+ ulen = WideCharToMultiByte(
+ CP_UTF8, /* UTF-8 code page */
+ 0, /* flags */
+ d_fd.cFileName, /* string to convert */
+ -1, /* input chars (-1 = NULL terminated) */
+ NULL, /* buffer */
+ 0, /* size of buffer (0 = return needed size) */
+ NULL, /* default char */
+ NULL); /* used default char */
+ if (ulen == 0) {
+ /* failed */
+ return NULL;
+ }
+ ulen += 2;
+ if ((q = malloc(ulen + 1)) == NULL) {
+ return NULL;
+ }
+
+ /* Convert the Unicode string to UTF-8 */
+ if ((ulen = WideCharToMultiByte(
+ CP_UTF8, /* UTF-8 code page */
+ 0, /* flags */
+ d_fd.cFileName, /* string to convert */
+ -1, /* input chars (-1 = NULL terminated) */
+ q, /* buffer */
+ ulen, /* size of buffer (0 = return needed size) */
+ NULL, /* default char */
+ NULL)) == 0) /* used default char */
+ {
+ free(fp);
+ free(q);
+ return NULL;
+ }
+
+ if (r == NULL) {
+ /* first one */
+ r = q;
+ } else {
+ if ((r = realloc(r, strlen(r) + strlen(q) + 3)) == NULL) {
+ free(fp);
+ free(q);
+ return NULL;
+ }
+ strcat(r, "/");
+ strcat(r, q);
+ free(q);
+ }
+ }
+
+ free(fp);
+
+ if (is_dir) {
+ strcat(r, "/");
+ }
+
+ return r;
+}
+#endif
+
+
+#define ONENAMELEN 255
+
+/* whole is a pathname with wildcards, wildtail points somewhere in the */
+/* middle of it. All wildcards to be expanded must come AFTER wildtail. */
+
+
+#ifdef UNICODE_SUPPORT
+
+wchar_t *local_to_wchar_string(local_string)
+ char *local_string; /* path to get utf-8 name for */
+{
+ wchar_t *qw;
+ int ulen;
+ int ulenw;
+
+ if (local_string == NULL)
+ return NULL;
+
+ /* get length */
+ ulenw = MultiByteToWideChar(
+ CP_ACP, /* ANSI code page */
+ 0, /* flags for character-type options */
+ local_string, /* string to convert */
+ -1, /* string length (-1 = NULL terminated) */
+ NULL, /* buffer */
+ 0 ); /* buffer length (0 = return length) */
+ if (ulenw == 0) {
+ /* failed */
+ return NULL;
+ }
+ ulenw++;
+ /* get length in bytes */
+ ulen = sizeof(wchar_t) * (ulenw + 1);
+ if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
+ return NULL;
+ }
+ /* convert multibyte to wide */
+ ulen = MultiByteToWideChar(
+ CP_ACP, /* ANSI code page */
+ 0, /* flags for character-type options */
+ local_string, /* string to convert */
+ -1, /* string length (-1 = NULL terminated) */
+ qw, /* buffer */
+ ulenw); /* buffer length (0 = return length) */
+ if (ulen == 0) {
+ /* failed */
+ free(qw);
+ return NULL;
+ }
+
+ return qw;
+}
+
+
+wchar_t *utf8_to_wchar_string(utf8_string)
+ char *utf8_string; /* path to get utf-8 name for */
+{
+ wchar_t *qw;
+ int ulen;
+ int ulenw;
+
+ if (utf8_string == NULL)
+ return NULL;
+
+ /* get length */
+ ulenw = MultiByteToWideChar(
+ CP_UTF8, /* UTF-8 code page */
+ 0, /* flags for character-type options */
+ utf8_string, /* string to convert */
+ -1, /* string length (-1 = NULL terminated) */
+ NULL, /* buffer */
+ 0 ); /* buffer length (0 = return length) */
+ if (ulenw == 0) {
+ /* failed */
+ return NULL;
+ }
+ ulenw++;
+ /* get length in bytes */
+ ulen = sizeof(wchar_t) * (ulenw + 1);
+ if ((qw = (wchar_t *)malloc(ulen + 1)) == NULL) {
+ return NULL;
+ }
+ /* convert multibyte to wide */
+ ulen = MultiByteToWideChar(
+ CP_UTF8, /* UTF-8 code page */
+ 0, /* flags for character-type options */
+ utf8_string, /* string to convert */
+ -1, /* string length (-1 = NULL terminated) */
+ qw, /* buffer */
+ ulenw); /* buffer length (0 = return length) */
+ if (ulen == 0) {
+ /* failed */
+ free(qw);
+ return NULL;
+ }
+
+ return qw;
+}
+
+
+
+/* Convert wchar_t string to utf8 using Windows calls
+ so any characters needing more than one wchar_t are
+ are handled by Windows */
+char *wchar_to_utf8_string(wstring)
+ wchar_t *wstring;
+{
+ char *q; /* return string */
+ int ulen;
+
+ if (wstring == NULL)
+ return NULL;
+
+ /* Get buffer length */
+ ulen = WideCharToMultiByte(
+ CP_UTF8, /* UTF-8 code page */
+ 0, /* flags */
+ wstring, /* string to convert */
+ -1, /* input chars (-1 = NULL terminated) */
+ NULL, /* buffer */
+ 0, /* size of buffer (0 = return needed size) */
+ NULL, /* default char */
+ NULL); /* used default char */
+ if (ulen == 0) {
+ /* failed */
+ return NULL;
+ }
+ ulen += 2;
+ if ((q = malloc(ulen + 1)) == NULL) {
+ return NULL;
+ }
+
+ /* Convert the Unicode string to UTF-8 */
+ if ((ulen = WideCharToMultiByte(
+ CP_UTF8, /* UTF-8 code page */
+ 0, /* flags */
+ wstring, /* string to convert */
+ -1, /* input chars (-1 = NULL terminated) */
+ q, /* buffer */
+ ulen, /* size of buffer (0 = return needed size) */
+ NULL, /* default char */
+ NULL)) == 0) /* used default char */
+ {
+ free(q);
+ return NULL;
+ }
+
+ return q;
+}
+
+
+local int wild_recursew(whole, wildtail)
+ wchar_t *whole;
+ wchar_t *wildtail;
+{
+ zDIRSCANW *dirw;
+ wchar_t *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+ extent newlen;
+ int amatch = 0, e = ZE_MISS;
+
+ if (!isshexpw(wildtail)) {
+ if (GetFileAttributesW(whole) != 0xFFFFFFFF) { /* file exists? */
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ CharToOemW(whole, whole);
+#endif
+ return procnamew(whole, 0);
+ }
+ else
+ return ZE_MISS; /* woops, no wildcards! */
+ }
+
+ /* back up thru path components till existing dir found */
+ do {
+ name = wildtail + wcslen(wildtail) - 1;
+ for (;;)
+ if (name-- <= wildtail || *name == PATH_END) {
+ subwild = name + 1;
+ plug2 = *subwild;
+ *subwild = 0;
+ break;
+ }
+ if (glue)
+ *glue = plug;
+ glue = subwild;
+ plug = plug2;
+ dirw = OpenDirScanW(whole);
+ } while (!dirw && subwild > wildtail);
+ wildtail = subwild; /* skip past non-wild components */
+
+ if ((subwild = wcschr(wildtail + 1, PATH_END)) != NULL) {
+ /* this "+ 1" dodges the ^^^ hole left by *glue == 0 */
+ *(subwild++) = 0; /* wildtail = one component pattern */
+ newlen = wcslen(whole) + wcslen(subwild) + (ONENAMELEN + 2);
+ } else
+ newlen = wcslen(whole) + (ONENAMELEN + 1);
+ if (!dirw || ((newwhole = malloc(newlen * sizeof(wchar_t))) == NULL)) {
+ if (glue)
+ *glue = plug;
+ e = dirw ? ZE_MEM : ZE_MISS;
+ goto ohforgetit;
+ }
+ wcscpy(newwhole, whole);
+ newlen = wcslen(newwhole);
+ if (glue)
+ *glue = plug; /* repair damage to whole */
+ if (!isshexpw(wildtail)) {
+ e = ZE_MISS; /* non-wild name not found */
+ goto ohforgetit;
+ }
+
+ while ((name = readdw(dirw)) != NULL) {
+ if (wcscmp(name, L".") && wcscmp(name, L"..") &&
+ MATCHW(wildtail, name, 0)) {
+ wcscpy(newwhole + newlen, name);
+ if (subwild) {
+ name = newwhole + wcslen(newwhole);
+ *(name++) = (wchar_t)PATH_END;
+ wcscpy(name, subwild);
+ e = wild_recursew(newwhole, name);
+ } else
+ e = procname_win32w(newwhole, 0, GetDirAttribsW(dirw));
+ newwhole[newlen] = 0;
+ if (e == ZE_OK)
+ amatch = 1;
+ else if (e != ZE_MISS)
+ break;
+ }
+ }
+
+ ohforgetit:
+ if (dirw) CloseDirScanW(dirw);
+ if (subwild) *--subwild = PATH_END;
+ if (newwhole) free(newwhole);
+ if (e == ZE_MISS && amatch)
+ e = ZE_OK;
+ return e;
+}
+
+#endif
+
+
+local int wild_recurse(whole, wildtail)
+ char *whole;
+ char *wildtail;
+{
+ zDIRSCAN *dir;
+ char *subwild, *name, *newwhole = NULL, *glue = NULL, plug = 0, plug2;
+ extent newlen;
+ int amatch = 0, e = ZE_MISS;
+
+ if (!isshexp(wildtail)) {
+ if (GetFileAttributes(whole) != 0xFFFFFFFF) { /* file exists? */
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ AnsiToOem(whole, whole);
+#endif
+ return procname(whole, 0);
+ }
+ else
+ return ZE_MISS; /* woops, no wildcards! */
+ }
+
+ /* back up thru path components till existing dir found */
+ do {
+ name = wildtail + strlen(wildtail) - 1;
+ for (;;)
+ if (name-- <= wildtail || *name == PATH_END) {
+ subwild = name + 1;
+ plug2 = *subwild;
+ *subwild = 0;
+ break;
+ }
+ if (glue)
+ *glue = plug;
+ glue = subwild;
+ plug = plug2;
+ dir = OpenDirScan(whole);
+ } while (!dir && subwild > wildtail);
+ wildtail = subwild; /* skip past non-wild components */
+
+ if ((subwild = MBSCHR(wildtail + 1, PATH_END)) != NULL) {
+ /* this "+ 1" dodges the ^^^ hole left by *glue == 0 */
+ *(subwild++) = 0; /* wildtail = one component pattern */
+ newlen = strlen(whole) + strlen(subwild) + (ONENAMELEN + 2);
+ } else
+ newlen = strlen(whole) + (ONENAMELEN + 1);
+ if (!dir || ((newwhole = malloc(newlen)) == NULL)) {
+ if (glue)
+ *glue = plug;
+ e = dir ? ZE_MEM : ZE_MISS;
+ goto ohforgetit;
+ }
+ strcpy(newwhole, whole);
+ newlen = strlen(newwhole);
+ if (glue)
+ *glue = plug; /* repair damage to whole */
+ if (!isshexp(wildtail)) {
+ e = ZE_MISS; /* non-wild name not found */
+ goto ohforgetit;
+ }
+
+ while ((name = readd(dir)) != NULL) {
+ if (strcmp(name, ".") && strcmp(name, "..") &&
+ MATCH(wildtail, name, 0)) {
+ strcpy(newwhole + newlen, name);
+ if (subwild) {
+ name = newwhole + strlen(newwhole);
+ *(name++) = PATH_END;
+ strcpy(name, subwild);
+ e = wild_recurse(newwhole, name);
+ } else
+ e = procname_win32(newwhole, 0, GetDirAttribs(dir));
+ newwhole[newlen] = 0;
+ if (e == ZE_OK)
+ amatch = 1;
+ else if (e != ZE_MISS)
+ break;
+ }
+ }
+
+ ohforgetit:
+ if (dir) CloseDirScan(dir);
+ if (subwild) *--subwild = PATH_END;
+ if (newwhole) free(newwhole);
+ if (e == ZE_MISS && amatch)
+ e = ZE_OK;
+ return e;
+}
+
+
+#ifdef UNICODE_SUPPORT
+int has_win32_wide() {
+ DWORD r;
+
+ /* test if we have wide function support */
+
+ /* check if already set */
+ if (no_win32_wide != -1)
+ return !no_win32_wide;
+
+ /* assume we don't */
+ no_win32_wide = 1;
+
+ /* get attributes for this directory */
+ r = GetFileAttributes(".");
+
+ /* r should be 16 = FILE_ATTRIBUTE_DIRECTORY */
+ if (r == FILE_ATTRIBUTE_DIRECTORY) {
+ /* now see if it works for the wide version */
+ r = GetFileAttributesW(L".");
+ /* if this fails then we probably don't have wide functions */
+ if (r == 0xFFFFFFFF) {
+ /* error is probably "This function is only valid in Win32 mode." */
+ } else if (r == FILE_ATTRIBUTE_DIRECTORY) {
+ /* worked, so assume we have wide support */
+ no_win32_wide = 0;
+ }
+ }
+
+ return !no_win32_wide;
+}
+#endif
+
+
+int wild(w)
+ char *w; /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+ file system. Return an error code in the ZE_ class. */
+{
+ char *p; /* path */
+ char *q; /* diskless path */
+ int e; /* result */
+#ifdef UNICODE_SUPPORT
+ wchar_t *pw; /* wide path */
+ wchar_t *qw; /* wide diskless path */
+#endif
+
+ if (volume_label == 1) {
+ volume_label = 2;
+ label = getVolumeLabel((w != NULL && isascii((uch)w[0]) && w[1] == ':')
+ ? to_up(w[0]) : '\0',
+ &label_time, &label_mode, &label_utim);
+ if (label != NULL)
+ (void)newname(label, 0, 0);
+ if (w == NULL || (isascii((uch)w[0]) && w[1] == ':' && w[2] == '\0'))
+ return ZE_OK;
+ /* "zip -$ foo a:" can be used to force drive name */
+ }
+ /* special handling of stdin request */
+ if (strcmp(w, "-") == 0) /* if compressing stdin */
+ return newname(w, 0, 0);
+
+ /* Allocate and copy pattern, leaving room to add "." if needed */
+ if ((p = malloc(strlen(w) + 2)) == NULL)
+ return ZE_MEM;
+ strcpy(p, w);
+
+ /* Normalize path delimiter as '/' */
+ for (q = p; *q; INCSTR(q)) /* use / consistently */
+ if (*q == '\\')
+ *q = '/';
+
+#ifdef UNICODE_SUPPORT
+ if (!no_win32_wide) {
+ /* wide char version */
+ pw = local_to_wchar_string(p);
+
+ /* Separate the disk part of the path */
+ if ((qw = wcschr(pw, ':')) != NULL) {
+ if (wcschr(++qw, ':')) /* sanity check for safety of wild_recurse */
+ return ZE_MISS;
+ } else
+ qw = pw;
+
+ /* Normalize bare disk names */
+ if (qw > pw && !*qw)
+ wcscpy(qw, L".");
+ } else {
+ /* multibyte version */
+ /* Separate the disk part of the path */
+ if ((q = MBSCHR(p, ':')) != NULL) {
+ if (MBSCHR(++q, ':')) /* sanity check for safety of wild_recurse */
+ return ZE_MISS;
+ } else
+ q = p;
+
+ /* Normalize bare disk names */
+ if (q > p && !*q)
+ strcpy(q, ".");
+ }
+#else
+ /* multibyte version */
+ /* Separate the disk part of the path */
+ if ((q = MBSCHR(p, ':')) != NULL) {
+ if (MBSCHR(++q, ':')) /* sanity check for safety of wild_recurse */
+ return ZE_MISS;
+ } else
+ q = p;
+
+ /* Normalize bare disk names */
+ if (q > p && !*q)
+ strcpy(q, ".");
+#endif
+
+ /* Here we go */
+#ifdef UNICODE_SUPPORT
+ if (!no_win32_wide) {
+ /* use wide Unicode directory scan */
+ e = wild_recursew(pw, qw);
+
+ free(pw);
+ } else {
+ /* use multibyte directory scan */
+ e = wild_recurse(p, q);
+ }
+#else
+ e = wild_recurse(p, q);
+#endif
+ free((zvoid *)p);
+ return e;
+}
+
+
+local int procname_win32(n, caseflag, attribs)
+ char *n; /* name to process */
+ int caseflag; /* true to force case-sensitive match */
+ DWORD attribs;
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ zDIRSCAN *d; /* directory stream from OpenDirScan() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ z_stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (attribs != INVALID_WIN32_FILE_ATTRIBS)
+ {
+ /* Avoid calling stat() for performance reasons when it is already known
+ (from a previous directory scan) that the passed name corresponds to
+ a "real existing" file. The only information needed further down in
+ this function is the distinction between directory entries and other
+ (typically normal file) entries. This distinction can be derived from
+ the file's attributes that the directory lookup has already provided
+ "for free".
+ */
+ s.st_mode = ((attribs & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG);
+ }
+ else if (LSSTAT(n, &s)
+#ifdef __TURBOC__
+ /* For this compiler, stat() succeeds on wild card names! */
+ /* Unfortunately, this causes failure on names containing */
+ /* square bracket characters, which are legal in win32. */
+ || isshexp(n)
+#endif
+ )
+ {
+#ifdef UNICODE_SUPPORT
+ char *uname = NULL;
+#endif
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->oname);
+ m = 0;
+ }
+ }
+#ifdef UNICODE_SUPPORT
+ /* also check escaped Unicode names */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (z->zuname) {
+#ifdef WIN32
+ /* It seems something is lost in going from a listed
+ name from zip -su in a console window to using that
+ name in a command line. This kluge may fix it
+ and just takes zuname, converts to oem (i.e.ouname),
+ then converts it back which ends up not the same as
+ started with.
+ */
+ uname = z->wuname;
+#else
+ uname = z->zuname;
+#endif
+ if (MATCH(p, uname, caseflag))
+ {
+ z->mark = pcount ? filter(uname, caseflag) : 1;
+ if (verbose) {
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->oname);
+ fprintf(mesg, " Escaped Unicode: %s\n",
+ z->ouname);
+ }
+ m = 0;
+ }
+ }
+ }
+#endif
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ for (p = n; *p; INCSTR(p)) /* use / consistently */
+ if (*p == '\\')
+ *p = '/';
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add exclusions in directory recurse but ignored for single file */
+ DWORD dwAttr;
+
+ dwAttr = GetFileMode(n);
+
+ if ((hidden_files ||
+ !(dwAttr & FILE_ATTRIBUTE_HIDDEN || dwAttr & FILE_ATTRIBUTE_SYSTEM)) &&
+ (!only_archive_set || (dwAttr & FILE_ATTRIBUTE_ARCHIVE)))
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ }
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = (char *) malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0 || strcmp(n, "/.") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (lastchar(p) != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = OpenDirScan(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ CloseDirScan(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname_win32(a, caseflag, GetDirAttribs(d)))
+ != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ CloseDirScan(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+
+#ifdef UNICODE_SUPPORT
+local int procname_win32w(nw, caseflag, attribs)
+ wchar_t *nw; /* name to process */
+ int caseflag; /* true to force case-sensitive match */
+ DWORD attribs;
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ wchar_t *aw; /* path and name for recursion */
+ zDIRSCANW *dw; /* directory stream from OpenDirScan() */
+ wchar_t *ew; /* pointer to name from readd() */
+ int m; /* matched flag */
+ wchar_t *pw; /* path for recursion */
+ zw_stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (wcscmp(nw, L"-") == 0) /* if compressing stdin */
+ return newnamew(nw, 0, caseflag);
+ else if (attribs != INVALID_WIN32_FILE_ATTRIBS)
+ {
+ /* Avoid calling stat() for performance reasons when it is already known
+ (from a previous directory scan) that the passed name corresponds to
+ a "real existing" file. The only information needed further down in
+ this function is the distinction between directory entries and other
+ (typically normal file) entries. This distinction can be derived from
+ the file's attributes that the directory lookup has already provided
+ "for free".
+ */
+ s.st_mode = ((attribs & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG);
+ }
+ else if (LSSTATW(nw, &s)
+#ifdef __TURBOC__
+ /* For this compiler, stat() succeeds on wild card names! */
+ /* Unfortunately, this causes failure on names containing */
+ /* square bracket characters, which are legal in win32. */
+ || isshexpw(nw)
+#endif
+ )
+ {
+ wchar_t *unamew = NULL;
+ /* Not a file or directory--search for shell expression in zip file */
+ pw = ex2inw(nw, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCHW(pw, z->znamew, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->oname);
+ m = 0;
+ }
+ }
+ /* also check escaped Unicode names */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (z->zuname) {
+ unamew = z->znamew;
+ if (MATCHW(pw, unamew, caseflag))
+ {
+ z->mark = pcount ? filter(z->iname, caseflag) : 1;
+ if (verbose) {
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->oname);
+ fprintf(mesg, " Escaped Unicode: %s\n",
+ z->ouname);
+ }
+ m = 0;
+ }
+ }
+ }
+ free((zvoid *)pw);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ for (pw = nw; *pw; pw++) /* use / consistently */
+ if (*pw == (wchar_t)'\\')
+ *pw = (wchar_t)'/';
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add exclusions in directory recurse but ignored for single file */
+ DWORD dwAttr;
+
+ dwAttr = GetFileModeW(nw);
+
+ if ((hidden_files ||
+ !(dwAttr & FILE_ATTRIBUTE_HIDDEN || dwAttr & FILE_ATTRIBUTE_SYSTEM)) &&
+ (!only_archive_set || (dwAttr & FILE_ATTRIBUTE_ARCHIVE)))
+ {
+ /* add or remove name of file */
+ if ((m = newnamew(nw, 0, caseflag)) != ZE_OK)
+ return m;
+ }
+ } else {
+ /* Add trailing / to the directory name */
+ pw = (wchar_t *)malloc( (wcslen(nw)+2) * sizeof(wchar_t) );
+ if (pw == NULL)
+ return ZE_MEM;
+ if (wcscmp(nw, L".") == 0 || wcscmp(nw, L"/.") == 0) {
+ *pw = (wchar_t)'\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ wcscpy(pw, nw);
+ aw = pw + wcslen(pw);
+ if (pw[wcslen(pw) - 1] != (wchar_t)'/')
+ wcscpy(aw, L"/");
+ if (dirnames && (m = newnamew(pw, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)pw);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (dw = OpenDirScanW(nw)) != NULL)
+ {
+ while ((ew = readdw(dw)) != NULL) {
+ if (wcscmp(ew, L".") && wcscmp(ew, L".."))
+ {
+ if ((aw = malloc((wcslen(pw) + wcslen(ew) + 1) * sizeof(wchar_t))) == NULL)
+ {
+ CloseDirScanW(dw);
+ free((zvoid *)pw);
+ return ZE_MEM;
+ }
+ wcscat(wcscpy(aw, pw), ew);
+ if ((m = procname_win32w(aw, caseflag, GetDirAttribsW(dw)))
+ != ZE_OK) /* recurse on name */
+ {
+ char *a;
+ char *ad;
+
+ a = wchar_to_local_string(aw);
+ ad = local_to_display_string(a);
+
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", ad);
+ else
+ ziperr(m, a);
+ free(ad);
+ free(a);
+ }
+ free((zvoid *)aw);
+ }
+ }
+ CloseDirScanW(dw);
+ }
+ free((zvoid *)pw);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+#endif
+
+
+#ifdef UNICODE_SUPPORT
+int procnamew(nw, caseflag)
+ wchar_t *nw; /* name to process */
+ int caseflag; /* true to force case-sensitive match */
+{
+ return procname_win32w(nw, caseflag, INVALID_WIN32_FILE_ATTRIBS);
+}
+#endif
+
+int procname(n, caseflag)
+ char *n; /* name to process */
+ int caseflag; /* true to force case-sensitive match */
+{
+ return procname_win32(n, caseflag, INVALID_WIN32_FILE_ATTRIBS);
+}
+
+char *ex2in(x, isdir, pdosflag)
+ char *x; /* external file name */
+ int isdir; /* input: x is a directory */
+ int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ int dosflag;
+
+
+ dosflag = dosify || IsFileSystemOldFAT(x);
+ if (!dosify && use_longname_ea && (t = GetLongPathEA(x)) != NULL)
+ {
+ x = t;
+ dosflag = 0;
+ }
+
+ /* Find starting point in name before doing malloc */
+ /* Strip drive specification */
+ t = *x && isascii((uch)*x) && *(x + 1) == ':' ? x + 2 : x;
+ /* Strip "//host/share/" part of a UNC name */
+ if ((!strncmp(x,"//",2) || !strncmp(x,"\\\\",2)) &&
+ (x[2] != '\0' && x[2] != '/' && x[2] != '\\')) {
+ n = x + 2;
+ while (*n != '\0' && *n != '/' && *n != '\\')
+ INCSTR(n); /* strip host name */
+ if (*n != '\0') {
+ INCSTR(n);
+ while (*n != '\0' && *n != '/' && *n != '\\')
+ INCSTR(n); /* strip `share' name */
+ }
+ if (*n != '\0')
+ t = n + MB_CLEN(n);
+ }
+ /* Strip leading "/" to convert an absolute path into a relative path */
+ while (*t == '/' || *t == '\\')
+ t++;
+ /* Strip leading "./" as well as drive letter */
+ while (*t == '.' && (t[1] == '/' || t[1] == '\\'))
+ t += 2;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ for (n = t; *n; INCSTR(n))
+ if (*n == '\\')
+ *n = '/';
+
+ if (!pathput)
+ t = last(t, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ OemToAnsi(n, n);
+#endif
+ return n;
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *ex2inw(xw, isdir, pdosflag)
+ wchar_t *xw; /* external file name */
+ int isdir; /* input: x is a directory */
+ int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ wchar_t *nw; /* internal file name (malloc'ed) */
+ wchar_t *tw; /* shortened name */
+ int dosflag;
+
+
+ dosflag = dosify || IsFileSystemOldFATW(xw);
+ if (!dosify && use_longname_ea && (tw = GetLongPathEAW(xw)) != NULL)
+ {
+ xw = tw;
+ dosflag = 0;
+ }
+
+ /* Find starting point in name before doing malloc */
+ /* Strip drive specification */
+ tw = *xw && iswascii(*xw) && *(xw + 1) == (wchar_t)':' ? xw + 2 : xw;
+ /* Strip "//host/share/" part of a UNC name */
+ if ((!wcsncmp(xw,L"//",2) || !wcsncmp(xw,L"\\\\",2)) &&
+ (xw[2] != (wchar_t)'\0' && xw[2] != (wchar_t)'/' && xw[2] != (wchar_t)'\\')) {
+ nw = xw + 2;
+ while (*nw != (wchar_t)'\0' && *nw != (wchar_t)'/' && *nw != (wchar_t)'\\')
+ nw++; /* strip host name */
+ if (*nw != (wchar_t)'\0') {
+ nw++;
+ while (*nw != (wchar_t)'\0' && *nw != (wchar_t)'/' && *nw != (wchar_t)'\\')
+ nw++; /* strip `share' name */
+ }
+ if (*nw != (wchar_t)'\0')
+ tw = nw++;
+ }
+ /* Strip leading "/" to convert an absolute path into a relative path */
+ while (*tw == (wchar_t)'/' || *tw == (wchar_t)'\\')
+ tw++;
+ /* Strip leading "./" as well as drive letter */
+ while (*tw == (wchar_t)'.' && (tw[1] == (wchar_t)'/' || tw[1] == (wchar_t)'\\'))
+ tw += 2;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ for (nw = tw; *nw; nw++)
+ if (*nw == '\\')
+ *nw = '/';
+
+ if (!pathput)
+ tw = lastw(tw, PATH_END);
+
+ /* Malloc space for internal name and copy it */
+ if ((nw = malloc((wcslen(tw) + 1) * sizeof(wchar_t))) == NULL)
+ return NULL;
+ wcscpy(nw, tw);
+
+ if (dosify)
+ msnamew(nw);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+#if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ CharToAnsiW(nw, nw);
+#endif
+ return nw;
+}
+#endif
+
+
+char *in2ex(n)
+ char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ strcpy(x, n);
+# if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ AnsiToOem(x, x);
+# endif
+ return x;
+}
+
+#ifdef UNICODE_SUPPORT
+wchar_t *in2exw(nw)
+ wchar_t *nw; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ wchar_t *xw; /* external file name */
+
+ if ((xw = malloc((wcslen(nw) + 1 + PAD) * sizeof(wchar_t))) == NULL)
+ return NULL;
+ wcscpy(xw, nw);
+# if defined(__RSXNT__) /* RSXNT/EMX C rtl uses OEM charset */
+ CharToOemW(xw, xw);
+# endif
+ return xw;
+}
+#endif
+
+
+void stamp(f, d)
+ char *f; /* name of file to change */
+ ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+#if defined(__TURBOC__) && !defined(__BORLANDC__)
+ int h; /* file handle */
+
+ if ((h = open(f, 0)) != -1)
+ {
+ setftime(h, (struct ftime *)&d);
+ close(h);
+ }
+#else /* !__TURBOC__ */
+
+ struct utimbuf u; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u.actime and u.modtime */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ /* Set updated and accessed times of f */
+ utime(f, &u);
+#endif /* ?__TURBOC__ */
+}
+
+ulg filetime(f, a, n, t)
+ char *f; /* name of file to get info on */
+ ulg *a; /* return value: file attributes */
+ zoff_t *n; /* return value: file size */
+ iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ z_stat s; /* results of zstat() */
+
+ /* converted to malloc instead of using FNMAX - 11/8/04 EG */
+ char *name;
+ unsigned int len = strlen(f);
+ int isstdin = !strcmp(f, "-");
+
+ if (f == label) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (MBSRCHR(name, '/') == (name + len - 1))
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ /* zip64 support 08/31/2003 R.Nausedat */
+ if (isstdin) {
+ if (zfstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ time((time_t *)&s.st_mtime); /* some fstat()s return time zero */
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+
+ if (a != NULL) {
+#ifdef WIN32_OEM
+ /* When creating DOS-like archives with OEM-charset names, only the
+ standard FAT attributes should be used.
+ (Note: On a Win32 system, the UNIX style attributes from stat()
+ do not contain any additional information...)
+ */
+ *a = (isstdin ? 0L : (ulg)GetFileMode(name));
+#else
+ *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileMode(name));
+#endif
+ }
+ if (n != NULL)
+ /* device return -1 */
+ *n = (s.st_mode & S_IFMT) == S_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+ free(name);
+
+ return unix2dostime((time_t *)&s.st_mtime);
+}
+
+#ifdef UNICODE_SUPPORT
+ulg filetimew(fw, a, n, t)
+ wchar_t *fw; /* name of file to get info on */
+ ulg *a; /* return value: file attributes */
+ zoff_t *n; /* return value: file size */
+ iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ zw_stat sw; /* results of zstat() */
+
+ /* converted to malloc instead of using FNMAX - 11/8/04 EG */
+ wchar_t *namew;
+ unsigned int len = wcslen(fw);
+ int isstdin = !wcscmp(fw, L"-");
+ wchar_t *labelw = local_to_wchar_string(label);
+
+ if (labelw && wcscmp(fw, labelw) == 0) {
+ if (a != NULL)
+ *a = label_mode;
+ if (n != NULL)
+ *n = -2L; /* convention for a label name */
+ if (t != NULL)
+ t->atime = t->mtime = t->ctime = label_utim;
+ return label_time;
+ }
+ if ((namew = malloc((len + 1) * sizeof(wchar_t))) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ wcscpy(namew, fw);
+ if (wcsrchr(namew, (wchar_t)'/') == (namew + len - 1))
+ namew[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ /* zip64 support 08/31/2003 R.Nausedat */
+ if (isstdin) {
+ if (zwfstat(fileno(stdin), &sw) != 0) {
+ free(namew);
+ error("fstat(stdin)");
+ }
+ time((time_t *)&sw.st_mtime); /* some fstat()s return time zero */
+ } else if (LSSTATW(namew, &sw) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(namew);
+ return 0;
+ }
+
+ if (a != NULL) {
+#ifdef WIN32_OEM
+ /* When creating DOS-like archives with OEM-charset names, only the
+ standard FAT attributes should be used.
+ (Note: On a Win32 system, the UNIX style attributes from stat()
+ do not contain any additional information...)
+ */
+ *a = (isstdin ? 0L : (ulg)GetFileModeW(namew));
+#else
+ *a = ((ulg)sw.st_mode << 16) | (isstdin ? 0L : (ulg)GetFileModeW(namew));
+#endif
+ }
+ if (n != NULL)
+ /* device return -1 */
+ *n = (sw.st_mode & S_IFMT) == S_IFREG ? sw.st_size : -1L;
+ if (t != NULL) {
+ t->atime = sw.st_atime;
+ t->mtime = sw.st_mtime;
+ t->ctime = sw.st_ctime;
+ }
+ free(namew);
+
+ return unix2dostime((time_t *)&sw.st_mtime);
+}
+#endif
+
+
+
+#ifdef NTSD_EAS
+
+/* changed size, csize from size_t to ush 3/10/2005 EG */
+local void GetSD(char *path, char **bufptr, ush *size,
+ char **cbufptr, ush *csize)
+{
+ unsigned char stackbuffer[NTSD_BUFFERSIZE];
+ unsigned long bytes = NTSD_BUFFERSIZE;
+ unsigned char *buffer = stackbuffer;
+ unsigned char *DynBuffer = NULL;
+ ulg cbytes;
+ PEF_NTSD_L_HEADER pLocalHeader;
+ PEF_NTSD_C_HEADER pCentralHeader;
+ VOLUMECAPS VolumeCaps;
+
+ /* check target volume capabilities */
+ if (!ZipGetVolumeCaps(path, path, &VolumeCaps) ||
+ !(VolumeCaps.dwFileSystemFlags & FS_PERSISTENT_ACLS)) {
+ return;
+ }
+
+ VolumeCaps.bUsePrivileges = use_privileges;
+ VolumeCaps.dwFileAttributes = 0;
+ /* should set to file attributes, if possible */
+
+ if (!SecurityGet(path, &VolumeCaps, buffer, (LPDWORD)&bytes)) {
+
+ /* try to malloc the buffer if appropriate */
+ if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ DynBuffer = malloc(bytes);
+ if(DynBuffer == NULL) return;
+
+ buffer = DynBuffer; /* switch to the new buffer and try again */
+
+ if(!SecurityGet(path, &VolumeCaps, buffer, (LPDWORD)&bytes)) {
+ free(DynBuffer);
+ return;
+ }
+
+ } else {
+ return; /* bail */
+ }
+ }
+
+ /* # bytes to compress: compress type, CRC, data bytes */
+ cbytes = (2 + 4 + EB_DEFLAT_EXTRA) + bytes;
+
+
+ /* our two possible failure points. don't allow trashing of any data
+ if either fails - notice that *size and *csize don't get updated.
+ *bufptr leaks if malloc() was used and *cbufptr alloc fails - this
+ isn't relevant because it's probably indicative of a bigger problem. */
+
+ if(*size)
+ *bufptr = realloc(*bufptr, *size + EF_NTSD_L_LEN + cbytes);
+ else
+ *bufptr = malloc(EF_NTSD_L_LEN + cbytes);
+
+ if(*csize)
+ *cbufptr = realloc(*cbufptr, *csize + EF_NTSD_C_LEN);
+ else
+ *cbufptr = malloc(EF_NTSD_C_LEN);
+
+ if(*bufptr == NULL || *cbufptr == NULL) {
+ if(DynBuffer) free(DynBuffer);
+ return;
+ }
+
+ /* local header */
+
+ pLocalHeader = (PEF_NTSD_L_HEADER) (*bufptr + *size);
+
+ cbytes = memcompress(((char *)pLocalHeader + EF_NTSD_L_LEN), cbytes,
+ (char *)buffer, bytes);
+
+ if (cbytes > 0x7FFF) {
+ sprintf(errbuf, "security info too large to store (%ld bytes), %d max", bytes, 0x7FFF);
+ zipwarn(errbuf, "");
+ zipwarn("security info not stored: ", path);
+ if(DynBuffer) free(DynBuffer);
+ return;
+ }
+
+ *size += EF_NTSD_L_LEN + (ush)cbytes;
+
+ pLocalHeader->nID = EF_NTSD;
+ pLocalHeader->nSize = (USHORT)(EF_NTSD_L_LEN - EB_HEADSIZE
+ + cbytes);
+ pLocalHeader->lSize = bytes; /* uncompressed size */
+ pLocalHeader->Version = 0;
+
+ /* central header */
+
+ pCentralHeader = (PEF_NTSD_C_HEADER) (*cbufptr + *csize);
+ *csize += EF_NTSD_C_LEN;
+
+ pCentralHeader->nID = EF_NTSD;
+ pCentralHeader->nSize = EF_NTSD_C_LEN - EB_HEADSIZE; /* sbz */
+ pCentralHeader->lSize = bytes;
+
+ if (noisy) {
+ sprintf(errbuf, " (%ld bytes security)", bytes);
+ zipmessage_nl(errbuf, 0);
+ }
+
+ if(DynBuffer) free(DynBuffer);
+}
+#endif /* NTSD_EAS */
+
+
+#ifdef USE_EF_UT_TIME
+
+#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(3))
+#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+
+local int GetExtraTime(struct zlist far *z, iztimes *z_utim)
+{
+ char *eb_l_ptr;
+ char *eb_c_ptr;
+ ulg ultime;
+ /* brain-dead IBM compiler defines time_t as "double", so we have to convert
+ * it into unsigned long integer number...
+ */
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid) return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ if(z->ext)
+ eb_l_ptr = realloc(z->extra, (z->ext + EB_L_UT_SIZE));
+ else
+ eb_l_ptr = malloc(EB_L_UT_SIZE);
+
+ if (eb_l_ptr == NULL)
+ return ZE_MEM;
+
+ if(z->cext)
+ eb_c_ptr = realloc(z->cextra, (z->cext + EB_C_UT_SIZE));
+ else
+ eb_c_ptr = malloc(EB_C_UT_SIZE);
+
+ if (eb_c_ptr == NULL)
+ return ZE_MEM;
+
+ z->extra = eb_l_ptr;
+ eb_l_ptr += z->ext;
+ z->ext += EB_L_UT_SIZE;
+
+ eb_l_ptr[0] = 'U';
+ eb_l_ptr[1] = 'T';
+ eb_l_ptr[2] = EB_UT_LEN(3); /* length of data part of e.f. */
+ eb_l_ptr[3] = 0;
+ eb_l_ptr[4] = EB_UT_FL_MTIME | EB_UT_FL_ATIME | EB_UT_FL_CTIME;
+ ultime = (ulg)z_utim->mtime;
+ eb_l_ptr[5] = (char)(ultime);
+ eb_l_ptr[6] = (char)(ultime >> 8);
+ eb_l_ptr[7] = (char)(ultime >> 16);
+ eb_l_ptr[8] = (char)(ultime >> 24);
+ ultime = (ulg)z_utim->atime;
+ eb_l_ptr[9] = (char)(ultime);
+ eb_l_ptr[10] = (char)(ultime >> 8);
+ eb_l_ptr[11] = (char)(ultime >> 16);
+ eb_l_ptr[12] = (char)(ultime >> 24);
+ ultime = (ulg)z_utim->ctime;
+ eb_l_ptr[13] = (char)(ultime);
+ eb_l_ptr[14] = (char)(ultime >> 8);
+ eb_l_ptr[15] = (char)(ultime >> 16);
+ eb_l_ptr[16] = (char)(ultime >> 24);
+
+ z->cextra = eb_c_ptr;
+ eb_c_ptr += z->cext;
+ z->cext += EB_C_UT_SIZE;
+
+ memcpy(eb_c_ptr, eb_l_ptr, EB_C_UT_SIZE);
+ eb_c_ptr[EB_LEN] = EB_UT_LEN(1);
+
+ return ZE_OK;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+
+#ifdef NTSD_EAS
+ if(ZipIsWinNT()) {
+ /* store SECURITY_DECRIPTOR data in local header,
+ and size only in central headers */
+ GetSD(z->name, &z->extra, &z->ext, &z->cextra, &z->cext);
+ }
+#endif /* NTSD_EAS */
+
+#ifdef USE_EF_UT_TIME
+ /* store extended time stamps in both headers */
+ return GetExtraTime(z, z_utim);
+#else /* !USE_EF_UT_TIME */
+ return ZE_OK;
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ return rmdir(d);
+}
+
+#endif /* !UTIL */
diff --git a/win32/win32zip.h b/win32/win32zip.h
new file mode 100644
index 0000000..3d8bca5
--- /dev/null
+++ b/win32/win32zip.h
@@ -0,0 +1,42 @@
+/*
+ win32/win32zip.h - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _WIN32ZIP_H
+#define _WIN32ZIP_H
+
+/*
+ * NT specific functions for ZIP.
+ */
+
+int GetFileMode(char *name);
+#ifdef UNICODE_SUPPORT
+int GetFileModeW(wchar_t *name);
+#endif
+long GetTheFileTime(char *name, iztimes *z_times);
+
+int IsFileNameValid(char *name);
+int IsFileSystemOldFAT(char *dir);
+#ifdef UNICODE_SUPPORT
+int IsFileSystemOldFATW(wchar_t *dir);
+#endif
+void ChangeNameForFAT(char *name);
+
+char *getVolumeLabel(int drive, ulg *vtime, ulg *vmode, time_t *vutim);
+
+#if 0 /* never used ?? */
+char *StringLower(char *);
+#endif
+
+char *GetLongPathEA(char *name);
+#ifdef UNICODE_SUPPORT
+wchar_t *GetLongPathEAW(wchar_t *name);
+#endif
+
+#endif /* _WIN32ZIP_H */
diff --git a/win32/zip.def b/win32/zip.def
new file mode 100644
index 0000000..105e4b9
--- /dev/null
+++ b/win32/zip.def
@@ -0,0 +1,4 @@
+;module-definition file for Windows Zip DLL -- used by link.exe
+DESCRIPTION 'The world-famous zip utilities from Info-ZIP'
+
+
diff --git a/win32/zip.rc b/win32/zip.rc
new file mode 100644
index 0000000..3ecb961
--- /dev/null
+++ b/win32/zip.rc
@@ -0,0 +1,53 @@
+#include <windows.h>
+#if (defined(WIN32) && !defined(__EMX__) && !defined(__MINGW32__))
+#include <winver.h>
+#endif
+#define IZ_VERSION_SYMBOLS_ONLY
+#include "../revision.h"
+#undef IZ_VERSION_SYMBOLS_ONLY
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0
+ PRODUCTVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+#ifdef _UNICODE
+ BLOCK "040904B0"
+#else
+ BLOCK "040904E4"
+#endif
+ BEGIN
+ VALUE "CompanyName", IZ_COMPANY_NAME "\0"
+ VALUE "FileDescription", "Info-ZIP Zip for Win32 console\0"
+ VALUE "FileVersion", VERSION "\0"
+ VALUE "InternalName", "zip\0"
+ VALUE "LegalCopyright", "Copyright © Info-ZIP 1997 - 2008\0"
+ VALUE "OriginalFilename", "zip.exe\0"
+ VALUE "ProductName", "Zip\0"
+ VALUE "ProductVersion", VERSION "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+#ifdef _UNICODE
+ VALUE "Translation", 0x409, 1200
+#else
+ VALUE "Translation", 0x409, 1252
+#endif
+ END
+END
diff --git a/win32/zipup.h b/win32/zipup.h
new file mode 100644
index 0000000..9505b56
--- /dev/null
+++ b/win32/zipup.h
@@ -0,0 +1,48 @@
+/*
+ win32/zipup.h - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __CYGWIN__
+# include <share.h>
+#endif
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+#if (defined(_SH_DENYNO) && !defined(SH_DENYNO))
+# define SH_DENYNO _SH_DENYNO
+#endif
+#if (defined(SH_DENYNO) && !defined(_SH_DENYNO))
+# define _SH_DENYNO SH_DENYNO
+#endif
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+
+#if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__EMX__)
+# define zopen(n,p) sopen(n,p,SH_DENYNO)
+#elif defined(__CYGWIN__) || defined(__IBMC__)
+# define zopen(n,p) open(n,p)
+#else
+# define zopen(n,p) _sopen(n,p,_SH_DENYNO)
+#endif
+#ifdef UNICODE_SUPPORT
+# if defined(__CYGWIN__) || defined(__IBMC__)
+# define zwopen(n,p) wopen(n,p)
+# else
+# define zwopen(n,p) _wsopen(n,p,_SH_DENYNO)
+# endif
+#endif
+
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
diff --git a/windll/VBz64/VBZIP.VBP b/windll/VBz64/VBZIP.VBP
new file mode 100644
index 0000000..4161be5
--- /dev/null
+++ b/windll/VBz64/VBZIP.VBP
@@ -0,0 +1,33 @@
+Type=Exe
+Form=Vbzipfrm.frm
+Module=VBZipBas; VBZipBas.bas
+IconForm="Form1"
+Startup="Form1"
+HelpFile=""
+Title="VBZIP"
+ExeName32="VBZIP.exe"
+Command32=""
+Name="Project1"
+HelpContextID="0"
+CompatibleMode="0"
+MajorVer=1
+MinorVer=0
+RevisionVer=0
+AutoIncrementVer=0
+ServerSupportFiles=0
+VersionCompanyName="Mike"
+CompilationType=-1
+OptimizationType=0
+FavorPentiumPro(tm)=0
+CodeViewDebugInfo=0
+NoAliasing=0
+BoundsCheck=0
+OverflowCheck=0
+FlPointCheck=0
+FDIVCheck=0
+UnroundedFP=0
+StartMode=0
+Unattended=0
+Retained=0
+ThreadPerObject=0
+MaxNumberOfThreads=1
diff --git a/windll/VBz64/VBZIP.vbw b/windll/VBz64/VBZIP.vbw
new file mode 100644
index 0000000..7b4e7f5
--- /dev/null
+++ b/windll/VBz64/VBZIP.vbw
@@ -0,0 +1,2 @@
+Form1 = 7, 9, 712, 539, , 22, 22, 660, 466, C
+VBZipBas = 26, -4, 716, 492,
diff --git a/windll/VBz64/VBZipBas.bas b/windll/VBz64/VBZipBas.bas
new file mode 100644
index 0000000..99547a0
--- /dev/null
+++ b/windll/VBz64/VBZipBas.bas
@@ -0,0 +1,737 @@
+Attribute VB_Name = "VBZipBas"
+
+Option Explicit
+
+'---------------------------------------------------------------
+'-- Please Do Not Remove These Comments!!!
+'---------------------------------------------------------------
+'-- Sample VB 6 code to drive zip32z64.dll
+'-- Based on the code contributed to the Info-ZIP project
+'-- by Mike Le Voi
+'--
+'-- See the original VB example in a separate directory for
+'-- more information
+'--
+'-- Use this code at your own risk. Nothing implied or warranted
+'-- to work on your machine :-)
+'---------------------------------------------------------------
+'--
+'-- The Source Code Is Freely Available From Info-ZIP At:
+'-- ftp://ftp.info-zip.org/pub/infozip/infozip.html
+'--
+'-- A Very Special Thanks To Mr. Mike Le Voi
+'-- And Mr. Mike White Of The Info-ZIP
+'-- For Letting Me Use And Modify His Orginal
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.
+'---------------------------------------------------------------
+
+'---------------------------------------------------------------
+' This example is redesigned to work with Zip32z64.dll compiled from
+' Zip 3.0 with Zip64 enabled. This allows for archives with more
+' and larger files than allowed in previous versions.
+'
+' Modified 4/24/2004, 12/4/2007 by Ed Gordon
+'---------------------------------------------------------------
+
+'---------------------------------------------------------------
+' Usage notes:
+'
+' This code uses Zip32z64.dll. You DO NOT need to register the
+' DLL to use it. You also DO NOT need to reference it in your
+' VB project. You DO have to copy the DLL to your SYSTEM
+' directory, your VB project directory, or place it in a directory
+' on your command PATH.
+'
+' Note that Zip32z64 is probably not thread safe so you should avoid
+' using the dll in multiple threads at the same time without first
+' testing for interaction.
+'
+' All code provided under the Info-Zip license. If you have
+' any questions please contact Info-Zip.
+'
+' April 24 2004 EG
+'
+'---------------------------------------------------------------
+
+'-- C Style argv
+'-- Holds The Zip Archive Filenames
+'
+' Max for zFiles just over 8000 as each pointer takes up 4 bytes and
+' VB only allows 32 kB of local variables and that includes function
+' parameters. - 3/19/2004 EG
+'
+' Can put names in strZipFileNames instead of using this array,
+' which avoids this limit. File names are separated by spaces.
+' Enclose names in quotes if include spaces.
+Public Type ZIPnames
+ zFiles(1 To 100) As String
+End Type
+
+'-- Call Back "String"
+Public Type ZipCBChar
+ ch(4096) As Byte
+End Type
+
+'-- Version Structure
+Public Type VerType
+ Major As Byte
+ Minor As Byte
+ PatchLevel As Byte
+ NotUsed As Byte
+End Type
+Public Type ZipVerType
+ structlen As Long ' Length Of The Structure Being Passed
+ flag As Long ' Bit 0: is_beta bit 1: uses_zlib
+ Beta As String * 10 ' e.g., "g BETA" or ""
+ date As String * 20 ' e.g., "4 Sep 95" (beta) or "4 September 1995"
+ ZLIB As String * 10 ' e.g., "1.0.5" or NULL
+ encryption As Long ' 0 if encryption not available
+ ZipVersion As VerType
+ os2dllVersion As VerType
+ windllVersion As VerType
+End Type
+
+'-- ZPOPT Is Used To Set The Options In The ZIP32z64.DLL
+Public Type ZpOpt
+ date As String ' Date in either US 12/31/98 or 1998-12-31 format
+ szRootDir As String ' Root Directory Pathname (Up To 256 Bytes Long)
+ szTempDir As String ' Temp Directory Pathname (Up To 256 Bytes Long)
+ fTemp As Long ' 1 If Temp dir Wanted, Else 0
+ fSuffix As Long ' Include Suffixes (Not Yet Implemented!)
+ fEncrypt As Long ' 1 If Encryption Wanted, Else 0
+ fSystem As Long ' 1 To Include System/Hidden Files, Else 0
+ fVolume As Long ' 1 If Storing Volume Label, Else 0
+ fExtra As Long ' 1 If Excluding Extra Attributes, Else 0
+ fNoDirEntries As Long ' 1 If Ignoring Directory Entries (end with /), Else 0
+ fExcludeDate As Long ' 1 If Excluding Files After Specified Date, Else 0
+ fIncludeDate As Long ' 1 If Including Files After Specified Date, Else 0
+ fVerbose As Long ' 1 If Full Messages Wanted, Else 0
+ fQuiet As Long ' 1 If Minimum Messages Wanted, Else 0
+ fCRLF_LF As Long ' 1 If Translate CR/LF To LF, Else 0
+ fLF_CRLF As Long ' 1 If Translate LF To CR/LF, Else 0
+ fJunkDir As Long ' 1 If Junking Directory Names on entries, Else 0
+ fGrow As Long ' 1 If Allow Appending To Zip File, Else 0
+ fForce As Long ' 1 If Making Entries Using DOS File Names, Else 0
+ fMove As Long ' 1 If Deleting Files Added Or Updated, Else 0
+ fDeleteEntries As Long ' 1 If Files Passed Have To Be Deleted, Else 0
+ fUpdate As Long ' 1 If Updating Zip File-Overwrite Only If Newer, Else 0
+ fFreshen As Long ' 1 If Freshing Zip File-Overwrite Only, Else 0
+ fJunkSFX As Long ' 1 If Junking SFX Prefix, Else 0
+ fLatestTime As Long ' 1 If Setting Zip File Time To Time Of Latest File In Archive, Else 0
+ fComment As Long ' 1 If Putting Comment In Zip File, Else 0
+ fOffsets As Long ' 1 If Updating Archive Offsets For SFX Files, Else 0
+ fPrivilege As Long ' 1 If Not Saving Privileges, Else 0
+ fEncryption As Long ' Read Only Property!!!
+ szSplitSize As String ' Size of split if splitting, Else NULL (empty string)
+ ' This string contains the size that you want to
+ ' split the archive into. i.e. 100 for 100 bytes,
+ ' 2K for 2 k bytes, where K is 1024, m for meg
+ ' and g for gig.
+ szIncludeList As String ' If used, space separated list of Include filename
+ ' patterns where match includes file - put quotes
+ ' around each filename pattern.
+ IncludeListCount As Long ' place filler (not for VB) - (inits to 0) DO NOT USE
+ IncludeList As Long ' place filler (not for VB) - (inits to 0) DO NOT USE
+ szExcludeList As String ' If used, space separated list of Exclude filename
+ ' patterns where match excludes file - put quotes
+ ' around each filename pattern.
+ ExcludeListCount As Long ' place filler (not for VB) - (inits to 0) DO NOT USE
+ ExcludeList As Long ' place filler (not for VB) - (inits to 0) DO NOT USE
+ fRecurse As Long ' 1 (-r), 2 (-R) If Recursing Into Sub-Directories, Else 0
+ fRepair As Long ' 1 = Fix Archive, 2 = Try Harder To Fix, Else 0
+ flevel As Byte ' Compression Level - 0 = Stored 6 = Default 9 = Max
+End Type
+
+
+' Used by SetZipOptions
+Public Enum ZipModeType
+ Add = 0
+ Delete = 1
+ Update = 2
+ Freshen = 3
+End Enum
+Public Enum CompressionLevelType
+ c0_NoCompression = 0
+ c1_Fast = 1
+ c2_Fast = 2
+ c3_Fast = 3
+ c4_Med = 4
+ c5_Med = 5
+ c6_Default = 6
+ c7_Extra = 7
+ c8_Extra = 8
+ c9_Max = 9
+End Enum
+Public Enum Translate_LF_Type
+ No_Line_End_Trans = 0
+ LF_To_CRLF = 1
+ CRLF_To_LF = 2
+End Enum
+Public Enum RepairType
+ NoRepair = 0
+ TryFix = 1
+ TryFixHarder = 2
+End Enum
+Public Enum VerbosenessType
+ Quiet = 0
+ Normal = 1
+ Verbose = 2
+End Enum
+Public Enum RecurseType
+ NoRecurse = 0
+ r_RecurseIntoSubdirectories = 1
+ R_RecurseUsingPatterns = 2
+End Enum
+
+
+'-- This Structure Is Used For The ZIP32z64.DLL Function Callbacks
+' Assumes Zip32z64.dll with Zip64 enabled
+Public Type ZIPUSERFUNCTIONS
+ ZDLLPrnt As Long ' Callback ZIP32z64.DLL Print Function
+ ZDLLCOMMENT As Long ' Callback ZIP32z64.DLL Comment Function
+ ZDLLPASSWORD As Long ' Callback ZIP32z64.DLL Password Function
+ ZDLLSPLIT As Long ' Callback ZIP32z64.DLL Split Select Function
+ ' There are 2 versions of SERVICE, we use one does not need 64-bit data type
+ ZDLLSERVICE As Long ' Callback ZIP32z64.DLL Service Function
+ ZDLLSERVICE_NO_INT64 As Long ' Callback ZIP32z64.DLL Service Function
+End Type
+
+'-- Default encryption password (used in callback if not empty string)
+Public EncryptionPassword As String
+
+'-- For setting the archive comment
+Public ArchiveCommentText
+
+'-- version info
+Public ZipVersion As ZipVerType
+
+'-- Local Declarations
+Public ZOPT As ZpOpt
+Public ZUSER As ZIPUSERFUNCTIONS
+
+'-- This Assumes ZIP32z64.DLL Is In Your \windows\system directory
+'-- or a copy is in the program directory or in some other directory
+'-- listed in PATH
+Private Declare Function ZpInit Lib "zip32z64.dll" _
+ (ByRef Zipfun As ZIPUSERFUNCTIONS) As Long '-- Set Zip Callbacks
+
+Private Declare Function ZpArchive Lib "zip32z64.dll" _
+ (ByVal argc As Long, ByVal funame As String, _
+ ByRef argv As ZIPnames, ByVal strNames As String, ByRef Opts As ZpOpt) As Long '-- Real Zipping Action
+
+Private Declare Sub ZpVersion Lib "zip32z64.dll" _
+ (ByRef ZipVersion As ZipVerType) '-- Version of DLL
+
+
+'-------------------------------------------------------
+'-- Public Variables For Setting The ZPOPT Structure...
+'-- (WARNING!!!) You Must Set The Options That You
+'-- Want The ZIP32.DLL To Do!
+'-- Before Calling VBZip32!
+'--
+'-- NOTE: See The Above ZPOPT Structure Or The VBZip32
+'-- Function, For The Meaning Of These Variables
+'-- And How To Use And Set Them!!!
+'-- These Parameters Must Be Set Before The Actual Call
+'-- To The VBZip32 Function!
+'-------------------------------------------------------
+
+'-- Public Program Variables
+Public zArgc As Integer ' Number Of Files To Zip Up
+Public zZipArchiveName As String ' The Zip File Name ie: Myzip.zip
+Public zZipFileNames As ZIPnames ' File Names To Zip Up
+Public strZipFileNames As String ' String of names to Zip Up
+Public zZipInfo As String ' Holds The Zip File Information
+
+'-- Public Constants
+'-- For Zip & UnZip Error Codes!
+Public Const ZE_OK = 0 ' Success (No Error)
+Public Const ZE_EOF = 2 ' Unexpected End Of Zip File Error
+Public Const ZE_FORM = 3 ' Zip File Structure Error
+Public Const ZE_MEM = 4 ' Out Of Memory Error
+Public Const ZE_LOGIC = 5 ' Internal Logic Error
+Public Const ZE_BIG = 6 ' Entry Too Large To Split Error
+Public Const ZE_NOTE = 7 ' Invalid Comment Format Error
+Public Const ZE_TEST = 8 ' Zip Test (-T) Failed Or Out Of Memory Error
+Public Const ZE_ABORT = 9 ' User Interrupted Or Termination Error
+Public Const ZE_TEMP = 10 ' Error Using A Temp File
+Public Const ZE_READ = 11 ' Read Or Seek Error
+Public Const ZE_NONE = 12 ' Nothing To Do Error
+Public Const ZE_NAME = 13 ' Missing Or Empty Zip File Error
+Public Const ZE_WRITE = 14 ' Error Writing To A File
+Public Const ZE_CREAT = 15 ' Could't Open To Write Error
+Public Const ZE_PARMS = 16 ' Bad Command Line Argument Error
+Public Const ZE_OPEN = 18 ' Could Not Open A Specified File To Read Error
+
+'-- These Functions Are For The ZIP32z64.DLL
+'--
+'-- Puts A Function Pointer In A Structure
+'-- For Use With Callbacks...
+Public Function FnPtr(ByVal lp As Long) As Long
+
+ FnPtr = lp
+
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Print Function
+Public Function ZDLLPrnt(ByRef fname As ZipCBChar, ByVal x As Long) As Long
+
+ Dim s0 As String
+ Dim xx As Long
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ s0 = ""
+
+ '-- Get Zip32.DLL Message For processing
+ For xx = 0 To x
+ If fname.ch(xx) = 0 Then
+ Exit For
+ Else
+ s0 = s0 + Chr(fname.ch(xx))
+ End If
+ Next
+
+ '----------------------------------------------
+ '-- This Is Where The DLL Passes Back Messages
+ '-- To You! You Can Change The Message Printing
+ '-- Below Here!
+ '----------------------------------------------
+
+ '-- Display Zip File Information
+ '-- zZipInfo = zZipInfo & s0
+ Form1.Print s0;
+
+ DoEvents
+
+ ZDLLPrnt = 0
+
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Service Function
+Public Function ZDLLServ(ByRef mname As ZipCBChar, _
+ ByVal LowSize As Long, _
+ ByVal HighSize As Long) As Long
+
+ Dim s0 As String
+ Dim xx As Long
+ Dim FS As Currency ' for large file sizes
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ FS = (HighSize * &H10000 * &H10000) + LowSize
+ ' Form1.Print "ZDLLServ returned File Size High " & HighSize & _
+ ' " Low " & LowSize & " = " & FS & " bytes"
+
+ s0 = ""
+ '-- Get Zip32.DLL Message For processing
+ For xx = 0 To 4096 ' x
+ If mname.ch(xx) = 0 Then
+ Exit For
+ Else
+ s0 = s0 + Chr(mname.ch(xx))
+ End If
+ Next
+ ' At this point, s0 contains the message passed from the DLL
+ ' It is up to the developer to code something useful here :)
+ ZDLLServ = 0 ' Setting this to 1 will abort the zip!
+
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Password Function
+Public Function ZDLLPass(ByRef p As ZipCBChar, _
+ ByVal n As Long, ByRef m As ZipCBChar, _
+ ByRef Name As ZipCBChar) As Integer
+
+ Dim filename As String
+ Dim prompt As String
+ Dim xx As Integer
+ Dim szpassword As String
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ ZDLLPass = 1
+
+ '-- User Entered A Password So Proccess It
+
+ '-- Enter or Verify
+ For xx = 0 To 255
+ If m.ch(xx) = 0 Then
+ Exit For
+ Else
+ prompt = prompt & Chr(m.ch(xx))
+ End If
+ Next
+
+ '-- If There Is A Password Have The User Enter It!
+ '-- This Can Be Changed
+
+ '-- Now skip asking if default password set
+ If EncryptionPassword <> "" Then
+ szpassword = EncryptionPassword
+ Else
+ szpassword = InputBox("Please Enter The Password!", prompt)
+ End If
+
+ '-- The User Did Not Enter A Password So Exit The Function
+ If szpassword = "" Then Exit Function
+
+ For xx = 0 To n - 1
+ p.ch(xx) = 0
+ Next
+
+ For xx = 0 To Len(szpassword) - 1
+ p.ch(xx) = Asc(Mid(szpassword, xx + 1, 1))
+ Next
+
+ p.ch(xx) = Chr(0) ' Put Null Terminator For C
+
+ ZDLLPass = 0
+
+End Function
+
+'-- Callback For ZIP32z64.DLL - DLL Comment Function
+Public Function ZDLLComm(ByRef s1 As ZipCBChar) As Integer
+
+ Dim comment As String
+ Dim xx%, szcomment$
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ ZDLLComm = 1
+ If Not IsEmpty(ArchiveCommentText) Then
+ ' use text given to SetZipOptions
+ szcomment = ArchiveCommentText
+ Else
+ For xx = 0 To 4095
+ szcomment = szcomment & Chr(s1.ch(xx))
+ If s1.ch(xx) = 0 Then
+ Exit For
+ End If
+ Next
+ comment = InputBox("Enter or edit the comment", Default:=szcomment)
+ If comment = "" Then
+ ' either empty comment or Cancel button
+ If MsgBox("Remove comment?" & Chr(13) & "Hit No to keep existing comment", vbYesNo) = vbYes Then
+ szcomment = comment
+ Else
+ Exit Function
+ End If
+ End If
+ szcomment = comment
+ End If
+ 'If szcomment = "" Then Exit Function
+ For xx = 0 To Len(szcomment) - 1
+ s1.ch(xx) = Asc(Mid$(szcomment, xx + 1, 1))
+ Next xx
+ s1.ch(xx) = 0 ' Put null terminator for C
+
+End Function
+
+' This function can be used to set options in VB
+Public Function SetZipOptions(ByRef ZipOpts As ZpOpt, _
+ Optional ByVal ZipMode As ZipModeType = Add, _
+ Optional ByVal RootDirToZipFrom As String = "", _
+ Optional ByVal CompressionLevel As CompressionLevelType = c6_Default, _
+ Optional ByVal RecurseSubdirectories As RecurseType = NoRecurse, _
+ Optional ByVal Verboseness As VerbosenessType = Normal, _
+ Optional ByVal i_IncludeFiles As String = "", _
+ Optional ByVal x_ExcludeFiles As String = "", _
+ Optional ByVal UpdateSFXOffsets As Boolean = False, Optional ByVal JunkDirNames As Boolean = False, _
+ Optional ByVal Encrypt As Boolean = False, Optional ByVal Password As String = "", _
+ Optional ByVal Repair As RepairType = NoRepair, Optional ByVal NoDirEntries As Boolean = False, _
+ Optional ByVal GrowExistingArchive As Boolean = False, _
+ Optional ByVal JunkSFXPrefix As Boolean = False, Optional ByVal ForceUseOfDOSNames As Boolean = False, _
+ Optional ByVal Translate_LF As Translate_LF_Type = No_Line_End_Trans, _
+ Optional ByVal Move_DeleteAfterAddedOrUpdated As Boolean = False, _
+ Optional ByVal SetZipTimeToLatestTime As Boolean = False, _
+ Optional ByVal IncludeSystemAndHiddenFiles As Boolean = False, _
+ Optional ByVal ExcludeEarlierThanDate As String = "", _
+ Optional ByVal IncludeEarlierThanDate As String = "", _
+ Optional ByVal IncludeVolumeLabel As Boolean = False, _
+ Optional ByVal ArchiveComment As Boolean = False, _
+ Optional ByVal ArchiveCommentTextString = Empty, _
+ Optional ByVal UsePrivileges As Boolean = False, _
+ Optional ByVal ExcludeExtraAttributes As Boolean = False, Optional ByVal SplitSize As String = "", _
+ Optional ByVal TempDirPath As String = "") As Boolean
+
+ Dim SplitNum As Long
+ Dim SplitMultS As String
+ Dim SplitMult As Long
+
+ ' set some defaults
+ ZipOpts.date = vbNullString
+ ZipOpts.szRootDir = vbNullString
+ ZipOpts.szTempDir = vbNullString
+ ZipOpts.fTemp = 0
+ ZipOpts.fSuffix = 0
+ ZipOpts.fEncrypt = 0
+ ZipOpts.fSystem = 0
+ ZipOpts.fVolume = 0
+ ZipOpts.fExtra = 0
+ ZipOpts.fNoDirEntries = 0
+ ZipOpts.fExcludeDate = 0
+ ZipOpts.fIncludeDate = 0
+ ZipOpts.fVerbose = 0
+ ZipOpts.fQuiet = 0
+ ZipOpts.fCRLF_LF = 0
+ ZipOpts.fLF_CRLF = 0
+ ZipOpts.fJunkDir = 0
+ ZipOpts.fGrow = 0
+ ZipOpts.fForce = 0
+ ZipOpts.fMove = 0
+ ZipOpts.fDeleteEntries = 0
+ ZipOpts.fUpdate = 0
+ ZipOpts.fFreshen = 0
+ ZipOpts.fJunkSFX = 0
+ ZipOpts.fLatestTime = 0
+ ZipOpts.fComment = 0
+ ZipOpts.fOffsets = 0
+ ZipOpts.fPrivilege = 0
+ ZipOpts.szSplitSize = vbNullString
+ ZipOpts.IncludeListCount = 0
+ ZipOpts.szIncludeList = vbNullString
+ ZipOpts.ExcludeListCount = 0
+ ZipOpts.szExcludeList = vbNullString
+ ZipOpts.fRecurse = 0
+ ZipOpts.fRepair = 0
+ ZipOpts.flevel = 0
+
+ If RootDirToZipFrom <> "" Then
+ ZipOpts.szRootDir = RootDirToZipFrom
+ End If
+ ZipOpts.flevel = Asc(CompressionLevel)
+ If UpdateSFXOffsets Then ZipOpts.fOffsets = 1
+
+ If i_IncludeFiles <> "" Then
+ ZipOpts.szIncludeList = i_IncludeFiles
+ End If
+ If x_ExcludeFiles <> "" Then
+ ZipOpts.szExcludeList = x_ExcludeFiles
+ End If
+
+ If ZipMode = Add Then
+ ' default
+ ElseIf ZipMode = Delete Then
+ ZipOpts.fDeleteEntries = 1
+ ElseIf ZipMode = Update Then
+ ZipOpts.fUpdate = 1
+ Else
+ ZipOpts.fFreshen = 1
+ End If
+ ZipOpts.fRepair = Repair
+ If GrowExistingArchive Then ZipOpts.fGrow = 1
+ If Move_DeleteAfterAddedOrUpdated Then ZipOpts.fMove = 1
+
+ If Verboseness = Quiet Then
+ ZipOpts.fQuiet = 1
+ ElseIf Verboseness = Verbose Then
+ ZipOpts.fVerbose = 1
+ End If
+
+ If ArchiveComment = False And Not IsEmpty(ArchiveCommentTextString) Then
+ MsgBox "Must set ArchiveComment = True to set ArchiveCommentTextString"
+ Exit Function
+ End If
+ If IsEmpty(ArchiveCommentTextString) Then
+ ArchiveCommentText = Empty
+ Else
+ ArchiveCommentText = ArchiveCommentTextString
+ End If
+ If ArchiveComment Then ZipOpts.fComment = 1
+
+ If NoDirEntries Then ZipOpts.fNoDirEntries = 1
+ If JunkDirNames Then ZipOpts.fJunkDir = 1
+ If Encrypt Then ZipOpts.fEncrypt = 1
+ EncryptionPassword = Password
+ If JunkSFXPrefix Then ZipOpts.fJunkSFX = 1
+ If ForceUseOfDOSNames Then ZipOpts.fForce = 1
+ If Translate_LF = LF_To_CRLF Then ZipOpts.fLF_CRLF = 1
+ If Translate_LF = CRLF_To_LF Then ZipOpts.fCRLF_LF = 1
+ ZipOpts.fRecurse = RecurseSubdirectories
+ If IncludeSystemAndHiddenFiles Then ZipOpts.fSystem = 1
+
+ If SetZipTimeToLatestTime Then ZipOpts.fLatestTime = 1
+ If ExcludeEarlierThanDate <> "" And IncludeEarlierThanDate <> "" Then
+ MsgBox "Both ExcludeEarlierThanDate and IncludeEarlierThanDate not " & Chr(10) & _
+ "supported at same time"
+ Exit Function
+ End If
+ If ExcludeEarlierThanDate <> "" Then
+ ZipOpts.fIncludeDate = 1
+ ZipOpts.date = ExcludeEarlierThanDate
+ End If
+ If IncludeEarlierThanDate <> "" Then
+ ZipOpts.fExcludeDate = 1
+ ZipOpts.date = IncludeEarlierThanDate
+ End If
+
+ If TempDirPath <> "" Then
+ ZipOpts.szTempDir = TempDirPath
+ ZipOpts.fTemp = 1
+ End If
+
+ If SplitSize <> "" Then
+ SplitSize = Trim(SplitSize)
+ SplitMultS = Right(SplitSize, 1)
+ SplitMultS = UCase(SplitMultS)
+ If (SplitMultS = "K") Then
+ SplitMult = 1024
+ SplitNum = Val(Left(SplitSize, Len(SplitSize) - 1))
+ ElseIf SplitMultS = "M" Then
+ SplitMult = 1024 * 1024&
+ SplitNum = Val(Left(SplitSize, Len(SplitSize) - 1))
+ ElseIf SplitMultS = "G" Then
+ SplitMult = 1024 * 1024 * 1024&
+ SplitNum = Val(Left(SplitSize, Len(SplitSize) - 1))
+ Else
+ SplitMult = 1024 * 1024&
+ SplitNum = Val(SplitSize)
+ End If
+ SplitNum = SplitNum * SplitMult
+ If SplitNum = 0 Then
+ MsgBox "SplitSize of 0 not supported"
+ Exit Function
+ ElseIf SplitNum < 64 * 1024& Then
+ MsgBox "SplitSize must be at least 64k"
+ Exit Function
+ End If
+ ZipOpts.szSplitSize = SplitSize
+ End If
+
+ If IncludeVolumeLabel Then ZipOpts.fVolume = 1
+ If UsePrivileges Then ZipOpts.fPrivilege = 1
+ If ExcludeExtraAttributes Then ZipOpts.fExtra = 1
+
+ SetZipOptions = True
+
+End Function
+
+Function ChopNulls(ByVal Str) As String
+ Dim A As Integer
+ Dim C As String
+
+ For A = 1 To Len(Str)
+ If Mid(Str, A, 1) = Chr(0) Then
+ ChopNulls = Left(Str, A - 1)
+ Exit Function
+ End If
+ Next
+ ChopNulls = Str
+
+End Function
+Sub DisplayVersion()
+
+ ' display version of DLL
+ Dim Beta As Boolean
+ Dim ZLIB As Boolean
+ Dim Zip64 As Boolean
+ Dim Flags As String
+ Dim A As Integer
+
+ ZipVersion.structlen = Len(ZipVersion)
+ ZpVersion ZipVersion
+ ' Check flag
+ If ZipVersion.flag And 1 Then
+ Flags = Flags & " Beta,"
+ Beta = True
+ Else
+ Flags = Flags & " No Beta,"
+ End If
+ If ZipVersion.flag And 2 Then
+ Flags = Flags & " ZLIB,"
+ ZLIB = True
+ Else
+ Flags = Flags & " No ZLIB,"
+ End If
+ If ZipVersion.flag And 4 Then
+ Flags = Flags & " Zip64, "
+ Zip64 = True
+ Else
+ Flags = Flags & " No Zip64, "
+ End If
+ If ZipVersion.encryption Then
+ Flags = Flags & "Encryption"
+ Else
+ Flags = Flags & " No encryption"
+ End If
+
+ Form1.Caption = "Using Zip32z64.DLL Version " & _
+ ZipVersion.ZipVersion.Major & "." & ZipVersion.ZipVersion.Minor & " " & _
+ ChopNulls(ZipVersion.Beta) & " [" & ChopNulls(ZipVersion.date) & "]" & _
+ " - FLAGS: " & Flags
+
+ If Not Zip64 Then
+ A = MsgBox("Zip32z64.dll not compiled with Zip64 enabled - continue?", _
+ vbOKCancel, _
+ "Wrong dll")
+ If A = vbCancel Then
+ End
+ End If
+ End If
+
+End Sub
+
+'-- Main ZIP32.DLL Subroutine.
+'-- This Is Where It All Happens!!!
+'--
+'-- (WARNING!) Do Not Change This Function!!!
+'--
+Public Function VBZip32() As Long
+
+ Dim retcode As Long
+ Dim FileNotFound As Boolean
+
+ ' On Error Resume Next '-- Nothing Will Go Wrong :-)
+ On Error GoTo ZipError
+
+ retcode = 0
+
+ '-- Set Address Of ZIP32.DLL Callback Functions
+ '-- (WARNING!) Do Not Change!!! (except as noted below)
+ ZUSER.ZDLLPrnt = FnPtr(AddressOf ZDLLPrnt)
+ ZUSER.ZDLLPASSWORD = FnPtr(AddressOf ZDLLPass)
+ ZUSER.ZDLLCOMMENT = FnPtr(AddressOf ZDLLComm)
+ ZUSER.ZDLLSERVICE_NO_INT64 = FnPtr(AddressOf ZDLLServ)
+
+ ' If you need to set destination of each split set this
+ 'ZUSER.ZDLLSPLIT = FnPtr(AddressOf ZDLLSplitSelect)
+
+ '-- Set ZIP32.DLL Callbacks - return 1 if DLL loaded 0 if not
+ retcode = ZpInit(ZUSER)
+ If retcode = 0 And FileNotFound Then
+ MsgBox "Probably could not find Zip32z64.DLL - have you copied" & Chr(10) & _
+ "it to the System directory, your program directory, " & Chr(10) & _
+ "or a directory on your command PATH?"
+ VBZip32 = retcode
+ Exit Function
+ End If
+
+ DisplayVersion
+
+ If strZipFileNames = "" Then
+ ' not using string of names to zip (so using array of names)
+ strZipFileNames = vbNullString
+ End If
+
+ '-- Go Zip It Them Up!
+ retcode = ZpArchive(zArgc, zZipArchiveName, zZipFileNames, strZipFileNames, ZOPT)
+
+ '-- Return The Function Code
+ VBZip32 = retcode
+
+ Exit Function
+
+ZipError:
+ MsgBox "Error: " & Err.Description
+ If Err = 48 Then
+ FileNotFound = True
+ End If
+ Resume Next
+
+End Function
+
diff --git a/windll/VBz64/Vbzipfrm.frm b/windll/VBz64/Vbzipfrm.frm
new file mode 100644
index 0000000..57c4df4
--- /dev/null
+++ b/windll/VBz64/Vbzipfrm.frm
@@ -0,0 +1,183 @@
+VERSION 5.00
+Begin VB.Form Form1
+ AutoRedraw = -1 'True
+ Caption = "Form1"
+ ClientHeight = 3150
+ ClientLeft = 60
+ ClientTop = 345
+ ClientWidth = 6570
+ BeginProperty Font
+ Name = "MS Sans Serif"
+ Size = 9.75
+ Charset = 0
+ Weight = 700
+ Underline = 0 'False
+ Italic = 0 'False
+ Strikethrough = 0 'False
+ EndProperty
+ LinkTopic = "Form1"
+ ScaleHeight = 3150
+ ScaleWidth = 6570
+ StartUpPosition = 1 'CenterOwner
+End
+Attribute VB_Name = "Form1"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = True
+Attribute VB_Exposed = False
+
+Option Explicit
+
+'---------------------------------------------------------------
+'-- Sample VB 6 code to drive zip32z64.dll
+'--
+'-- Based on code contributed to the Info-ZIP project by Mike Le Voi
+'--
+'-- See the Original VB example in a separate directory for
+'-- more information
+'--
+'-- Use this code at your own risk. Nothing implied or warranted
+'-- to work on your machine :-)
+'---------------------------------------------------------------
+'--
+'-- The Source Code Is Freely Available From Info-ZIP At:
+'-- ftp://ftp.info-zip.org/pub/infozip/infozip.html
+'-- and
+'-- http://sourceforge.net/projects/infozip/
+'--
+'-- A Very Special Thanks To Mr. Mike Le Voi
+'-- And Mr. Mike White Of The Info-ZIP project
+'-- For Letting Me Use And Modify His Orginal
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.
+'---------------------------------------------------------------
+'--
+'-- Contributed To The Info-ZIP Project By Raymond L. King
+'-- Modified June 21, 1998
+'-- By Raymond L. King
+'-- Custom Software Designers
+'--
+'-- Contact Me At: king@ntplx.net
+'-- ICQ 434355
+'-- Or Visit Our Home Page At: http://www.ntplx.net/~king
+'--
+'---------------------------------------------------------------
+
+'---------------------------------------------------------------
+' Zip32z64.dll is the new Zip32.dll based on Zip 3.0 and compiled
+' with Zip64 support enabled. See windll.txt in the windll directory
+' for more on Zip32z64 and the comments in VBZipBas.bas.
+'
+' Contact Info-Zip if problems. This code is
+' provided under the Info-Zip license.
+'
+' 4/24/2004, 12/4/2007 EG
+'---------------------------------------------------------------
+
+Private Sub Form_Click()
+
+ Dim retcode As Integer ' For Return Code From ZIP32.DLL
+ Dim iFiles As String
+ Dim FilesToZip() As String
+ Dim i As Long
+
+ Cls
+
+ '-- Set Options - Only The Common Ones Are Shown Here
+ '-- These Must Be Set Before Calling The VBZip32 Function
+
+ ' In VB 6 you can see the list of possible options and the defaults
+ ' by adding a space between any parameters which should make the tip box
+ ' appear. Delete a := and retype to see a list of choices.
+
+ ' Be warned: There are bugs in the previous dll. See the Original VB
+ ' example in the VB directory for details.
+
+ If Not SetZipOptions(ZOPT, _
+ ZipMode:=Add, _
+ CompressionLevel:=c6_Default) Then
+ ' Some additional options ...
+ ' RootDirToZipFrom:="", _
+ ' strip paths and just store names:
+ ' JunkDirNames:=False, _
+ ' do not store entries for the directories themselves:
+ ' NoDirEntries:=True _
+ ' include files only if match one of these patterns:
+ ' i_IncludeFiles:="*.vbp *.frm", _
+ ' exclude files that match these patterns:
+ ' x_ExcludeFiles:="*.bas", _
+ ' Verboseness:=Verbose, _
+ ' IncludeEarlierThanDate:="2004-4-1", _
+ ' RecurseSubdirectories:=r_RecurseIntoSubdirectories, _
+ ' Encrypt:=False, _
+ ' ArchiveComment:=False
+ ' date example (format mmddyyyy or yyyy-mm-dd):
+ ' ExcludeEarlierThanDate:="2002-12-10", _
+ ' split example (can only create, can't update split archives in VB):
+ ' SplitSize:="110k", _
+' Delete
+ ' If Not SetZipOptions(ZOPT, _
+ ' ZipMode:=Delete) Then
+
+ ' a problem if get here - error message already displayed so just exit
+ Exit Sub
+ End If
+
+
+ '-- Select Some Files - Wildcards Are Supported
+ '-- Change The Paths Here To Your Directory
+ '-- And Files!!!
+
+ ' default to current (VB project) directory and zip up project files
+ zZipArchiveName = "MyFirst.zip"
+
+
+ ' Files to zip - use one of below
+
+ '---------------
+ ' Example using file name array
+
+ ' Store the file paths
+ ' Change Dim of zFiles at top of VBZipBas.bas if more than 100 files
+ ' See note at top of VBZipBas.bas for limit on number of files
+
+' zArgc = 2 ' Number Of file paths below
+' zZipFileNames.zFiles(1) = "*.bas"
+' zZipFileNames.zFiles(2) = "*.frm"
+
+ '---------------
+ ' Example using file list string
+
+ ' List of files to zip as string of names with space between
+ ' Set zArgc = 0 as not using array
+ ' Using string for file list avoids above array limit
+
+ zArgc = 0
+' ReDim FilesToZip(1) ' dim to number of files below
+' FilesToZip(1) = "x:*.*"
+ ReDim FilesToZip(2) ' dim to number of files below
+ FilesToZip(1) = "*.bas"
+ FilesToZip(2) = "*.frm"
+
+ ' Build string of file names
+ ' Best to put double quotes around each in case of spaces
+ strZipFileNames = ""
+ For i = 1 To UBound(FilesToZip)
+ strZipFileNames = strZipFileNames & """" & FilesToZip(i) & """ "
+ Next
+ '---------------
+
+ '-- Go Zip Them Up!
+ retcode = VBZip32()
+
+ '-- Display The Returned Code Or Error!
+ Print "Return code:" & Str(retcode)
+
+End Sub
+
+Private Sub Form_Load()
+
+ Me.Show
+
+ Print "Click me!"
+
+End Sub
diff --git a/windll/VBz64/readVB64.txt b/windll/VBz64/readVB64.txt
new file mode 100644
index 0000000..2876b44
--- /dev/null
+++ b/windll/VBz64/readVB64.txt
@@ -0,0 +1,25 @@
+On Windows open this file in WordPad.
+
+Contents of the "windll/vbz64" sub-archive
+
+This directory contains a Visual Basic project example for using the
+zip32z64.dll library (Zip 3.0 with Zip64 enabled). See the comments in
+the form and project files for details.
+
+This new project and the new zip32z64.dll library are not compatible
+with previous VB examples using the zip32.dll interface as this new
+interface supports more files and handles file sizes larger than 2 GB.
+It should be simple to convert a VB program using zip32.dll to
+zip32z64.dll but the program may need some changes. For a compatible
+replacement use the dll compiled from Zip 2.32 (released separately)
+and see the zip32.dll example in the VB directory of this source tree.
+
+Note that the files may be saved in unix format with carriage returns
+stripped. These must be restored before the project can be successfully
+used. This can be done by using the -a option to unzip. Another way to
+do this is to open each file in WordPad, select and cut a line, paste
+the line back, and save the file. This will force WordPad to change the
+line ends in the entire file. Newer versions of WordPad may not do this.
+
+Ed Gordon
+4/26/2008
diff --git a/windll/Vb/VBZIP.vbw b/windll/Vb/VBZIP.vbw
new file mode 100644
index 0000000..2f8339a
--- /dev/null
+++ b/windll/Vb/VBZIP.vbw
@@ -0,0 +1,2 @@
+Form1 = 0, 0, 0, 0, C, 22, 22, 563, 389, C
+VBZipBas = 44, 44, 659, 489,
diff --git a/windll/Vb/VBZipBas.bas b/windll/Vb/VBZipBas.bas
new file mode 100644
index 0000000..2b766e9
--- /dev/null
+++ b/windll/Vb/VBZipBas.bas
@@ -0,0 +1,458 @@
+Attribute VB_Name = "VBZipBas"
+
+Option Explicit
+
+'---------------------------------------------------------------
+'-- Please Do Not Remove These Comments!!!
+'---------------------------------------------------------------
+'-- Sample VB 5 code to drive zip32.dll
+'-- Contributed to the Info-ZIP project by Mike Le Voi
+'--
+'-- Contact me at: mlevoi@modemss.brisnet.org.au
+'--
+'-- Visit my home page at: http://modemss.brisnet.org.au/~mlevoi
+'--
+'-- Use this code at your own risk. Nothing implied or warranted
+'-- to work on your machine :-)
+'---------------------------------------------------------------
+'--
+'-- The Source Code Is Freely Available From Info-ZIP At:
+'-- http://www.cdrom.com/pub/infozip/infozip.html
+'--
+'-- A Very Special Thanks To Mr. Mike Le Voi
+'-- And Mr. Mike White Of The Info-ZIP
+'-- For Letting Me Use And Modify His Orginal
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.
+'---------------------------------------------------------------
+'--
+'-- Contributed To The Info-ZIP Project By Raymond L. King
+'-- Modified June 21, 1998
+'-- By Raymond L. King
+'-- Custom Software Designers
+'--
+'-- Contact Me At: king@ntplx.net
+'-- ICQ 434355
+'-- Or Visit Our Home Page At: http://www.ntplx.net/~king
+'--
+'---------------------------------------------------------------
+'
+' This is the original example with some small changes. Only
+' use with the original Zip32.dll (compiled from Zip 2.31 or
+' later). Do not use this VB example with Zip32z64.dll
+' (compiled from Zip 3.0). To check the version of a dll,
+' right click on the file and check properties.
+'
+' 6/24/2008 Ed Gordon
+
+'---------------------------------------------------------------
+' Usage notes:
+'
+' This code uses Zip32.dll. You DO NOT need to register the
+' DLL to use it. You also DO NOT need to reference it in your
+' VB project. You DO have to copy the DLL to your SYSTEM
+' directory, your VB project directory, or place it in a directory
+' on your command PATH.
+'
+' A bug has been found in the Zip32.dll when called from VB. If
+' you try to pass any values other than NULL in the ZPOPT strings
+' Date, szRootDir, or szTempDir they get converted from the
+' VB internal wide character format to temporary byte strings by
+' the calling interface as they are supposed to. However when
+' ZpSetOptions returns the passed strings are deallocated unless the
+' VB debugger prevents it by a break between ZpSetOptions and
+' ZpArchive. When Zip32.dll uses these pointers later it
+' can result in unpredictable behavior. A kluge is available
+' for Zip32.dll, just replacing api.c in Zip 2.3, but better to just
+' use the new Zip32z64.dll where these bugs are fixed. However,
+' the kluge has been added to Zip 2.31 and later and these are
+' now stable. To determine the version of the dll you have
+' right click on it, select the Version tab, and verify the
+' Product Version is at least 2.31.
+'
+' Another bug is where -R is used with some other options and can
+' crash the dll. This is a bug in how zip processes the command
+' line and should be mostly fixed in Zip 2.31. If you run into
+' problems try using -r instead for recursion. The bug is fixed
+' in Zip 3.0 but note that Zip 3.0 creates dll zip32z64.dll and
+' it is not compatible with older VB including this example. See
+' the new VB example code included with Zip 3.0 for calling
+' interface changes.
+'
+' Note that Zip32 is probably not thread safe. It may be made
+' thread safe in a later version, but for now only one thread in
+' one program should use the DLL at a time. Unlike Zip, UnZip is
+' probably thread safe, but an exception to this has been
+' found. See the UnZip documentation for the latest on this.
+'
+' All code in this VB project is provided under the Info-Zip license.
+'
+' If you have any questions please contact Info-Zip at
+' http://www.info-zip.org.
+'
+' 4/29/2004 EG (Updated 3/1/2005, 6/24/2008 EG)
+'
+'---------------------------------------------------------------
+
+
+'-- C Style argv
+'-- Holds The Zip Archive Filenames
+' Max for this just over 8000 as each pointer takes up 4 bytes and
+' VB only allows 32 kB of local variables and that includes function
+' parameters. - 3/19/2004 EG
+'
+Public Type ZIPnames
+ zFiles(0 To 99) As String
+End Type
+
+'-- Call Back "String"
+Public Type ZipCBChar
+ ch(4096) As Byte
+End Type
+
+'-- ZPOPT Is Used To Set The Options In The ZIP32.DLL
+Public Type ZPOPT
+ Date As String ' US Date (8 Bytes Long) "12/31/98"?
+ szRootDir As String ' Root Directory Pathname (Up To 256 Bytes Long)
+ szTempDir As String ' Temp Directory Pathname (Up To 256 Bytes Long)
+ fTemp As Long ' 1 If Temp dir Wanted, Else 0
+ fSuffix As Long ' Include Suffixes (Not Yet Implemented!)
+ fEncrypt As Long ' 1 If Encryption Wanted, Else 0
+ fSystem As Long ' 1 To Include System/Hidden Files, Else 0
+ fVolume As Long ' 1 If Storing Volume Label, Else 0
+ fExtra As Long ' 1 If Excluding Extra Attributes, Else 0
+ fNoDirEntries As Long ' 1 If Ignoring Directory Entries, Else 0
+ fExcludeDate As Long ' 1 If Excluding Files Earlier Than Specified Date, Else 0
+ fIncludeDate As Long ' 1 If Including Files Earlier Than Specified Date, Else 0
+ fVerbose As Long ' 1 If Full Messages Wanted, Else 0
+ fQuiet As Long ' 1 If Minimum Messages Wanted, Else 0
+ fCRLF_LF As Long ' 1 If Translate CR/LF To LF, Else 0
+ fLF_CRLF As Long ' 1 If Translate LF To CR/LF, Else 0
+ fJunkDir As Long ' 1 If Junking Directory Names, Else 0
+ fGrow As Long ' 1 If Allow Appending To Zip File, Else 0
+ fForce As Long ' 1 If Making Entries Using DOS File Names, Else 0
+ fMove As Long ' 1 If Deleting Files Added Or Updated, Else 0
+ fDeleteEntries As Long ' 1 If Files Passed Have To Be Deleted, Else 0
+ fUpdate As Long ' 1 If Updating Zip File-Overwrite Only If Newer, Else 0
+ fFreshen As Long ' 1 If Freshing Zip File-Overwrite Only, Else 0
+ fJunkSFX As Long ' 1 If Junking SFX Prefix, Else 0
+ fLatestTime As Long ' 1 If Setting Zip File Time To Time Of Latest File In Archive, Else 0
+ fComment As Long ' 1 If Putting Comment In Zip File, Else 0
+ fOffsets As Long ' 1 If Updating Archive Offsets For SFX Files, Else 0
+ fPrivilege As Long ' 1 If Not Saving Privileges, Else 0
+ fEncryption As Long ' Read Only Property!!!
+ fRecurse As Long ' 1 (-r), 2 (-R) If Recursing Into Sub-Directories, Else 0
+ fRepair As Long ' 1 = Fix Archive, 2 = Try Harder To Fix, Else 0
+ flevel As Byte ' Compression Level - 0 = Stored 6 = Default 9 = Max
+End Type
+
+'-- This Structure Is Used For The ZIP32.DLL Function Callbacks
+Public Type ZIPUSERFUNCTIONS
+ ZDLLPrnt As Long ' Callback ZIP32.DLL Print Function
+ ZDLLCOMMENT As Long ' Callback ZIP32.DLL Comment Function
+ ZDLLPASSWORD As Long ' Callback ZIP32.DLL Password Function
+ ZDLLSERVICE As Long ' Callback ZIP32.DLL Service Function
+End Type
+
+'-- Local Declarations
+Public ZOPT As ZPOPT
+Public ZUSER As ZIPUSERFUNCTIONS
+
+'-- This Assumes ZIP32.DLL Is In Your \Windows\System Directory!
+'-- (alternatively, a copy of ZIP32.DLL needs to be located in the program
+'-- directory or in some other directory listed in PATH.)
+Private Declare Function ZpInit Lib "zip32.dll" _
+ (ByRef Zipfun As ZIPUSERFUNCTIONS) As Long '-- Set Zip Callbacks
+
+Private Declare Function ZpSetOptions Lib "zip32.dll" _
+ (ByRef Opts As ZPOPT) As Long '-- Set Zip Options
+
+Private Declare Function ZpGetOptions Lib "zip32.dll" _
+ () As ZPOPT '-- Used To Check Encryption Flag Only
+
+Private Declare Function ZpArchive Lib "zip32.dll" _
+ (ByVal argc As Long, ByVal funame As String, _
+ ByRef argv As ZIPnames) As Long '-- Real Zipping Action
+
+'-------------------------------------------------------
+'-- Public Variables For Setting The ZPOPT Structure...
+'-- (WARNING!!!) You Must Set The Options That You
+'-- Want The ZIP32.DLL To Do!
+'-- Before Calling VBZip32!
+'--
+'-- NOTE: See The Above ZPOPT Structure Or The VBZip32
+'-- Function, For The Meaning Of These Variables
+'-- And How To Use And Set Them!!!
+'-- These Parameters Must Be Set Before The Actual Call
+'-- To The VBZip32 Function!
+'-------------------------------------------------------
+Public zDate As String
+Public zRootDir As String
+Public zTempDir As String
+Public zSuffix As Integer
+Public zEncrypt As Integer
+Public zSystem As Integer
+Public zVolume As Integer
+Public zExtra As Integer
+Public zNoDirEntries As Integer
+Public zExcludeDate As Integer
+Public zIncludeDate As Integer
+Public zVerbose As Integer
+Public zQuiet As Integer
+Public zCRLF_LF As Integer
+Public zLF_CRLF As Integer
+Public zJunkDir As Integer
+Public zRecurse As Integer
+Public zGrow As Integer
+Public zForce As Integer
+Public zMove As Integer
+Public zDelEntries As Integer
+Public zUpdate As Integer
+Public zFreshen As Integer
+Public zJunkSFX As Integer
+Public zLatestTime As Integer
+Public zComment As Integer
+Public zOffsets As Integer
+Public zPrivilege As Integer
+Public zEncryption As Integer
+Public zRepair As Integer
+Public zLevel As Integer
+
+'-- Public Program Variables
+Public zArgc As Integer ' Number Of Files To Zip Up
+Public zZipFileName As String ' The Zip File Name ie: Myzip.zip
+Public zZipFileNames As ZIPnames ' File Names To Zip Up
+Public zZipInfo As String ' Holds The Zip File Information
+
+'-- Public Constants
+'-- For Zip & UnZip Error Codes!
+Public Const ZE_OK = 0 ' Success (No Error)
+Public Const ZE_EOF = 2 ' Unexpected End Of Zip File Error
+Public Const ZE_FORM = 3 ' Zip File Structure Error
+Public Const ZE_MEM = 4 ' Out Of Memory Error
+Public Const ZE_LOGIC = 5 ' Internal Logic Error
+Public Const ZE_BIG = 6 ' Entry Too Large To Split Error
+Public Const ZE_NOTE = 7 ' Invalid Comment Format Error
+Public Const ZE_TEST = 8 ' Zip Test (-T) Failed Or Out Of Memory Error
+Public Const ZE_ABORT = 9 ' User Interrupted Or Termination Error
+Public Const ZE_TEMP = 10 ' Error Using A Temp File
+Public Const ZE_READ = 11 ' Read Or Seek Error
+Public Const ZE_NONE = 12 ' Nothing To Do Error
+Public Const ZE_NAME = 13 ' Missing Or Empty Zip File Error
+Public Const ZE_WRITE = 14 ' Error Writing To A File
+Public Const ZE_CREAT = 15 ' Could't Open To Write Error
+Public Const ZE_PARMS = 16 ' Bad Command Line Argument Error
+Public Const ZE_OPEN = 18 ' Could Not Open A Specified File To Read Error
+
+'-- These Functions Are For The ZIP32.DLL
+'--
+'-- Puts A Function Pointer In A Structure
+'-- For Use With Callbacks...
+Public Function FnPtr(ByVal lp As Long) As Long
+
+ FnPtr = lp
+
+End Function
+
+'-- Callback For ZIP32.DLL - DLL Print Function
+Public Function ZDLLPrnt(ByRef fname As ZipCBChar, ByVal x As Long) As Long
+
+ Dim s0 As String
+ Dim xx As Long
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ s0 = ""
+
+ '-- Get Zip32.DLL Message For processing
+ For xx = 0 To x
+ If fname.ch(xx) = 0 Then
+ Exit For
+ Else
+ s0 = s0 + Chr(fname.ch(xx))
+ End If
+ Next
+
+ '----------------------------------------------
+ '-- This Is Where The DLL Passes Back Messages
+ '-- To You! You Can Change The Message Printing
+ '-- Below Here!
+ '----------------------------------------------
+
+ '-- Display Zip File Information
+ '-- zZipInfo = zZipInfo & s0
+ Form1.Print s0;
+
+ DoEvents
+
+ ZDLLPrnt = 0
+
+End Function
+
+'-- Callback For ZIP32.DLL - DLL Service Function
+Public Function ZDLLServ(ByRef mname As ZipCBChar, ByVal x As Long) As Long
+
+ ' x is the size of the file
+
+ Dim s0 As String
+ Dim xx As Long
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ s0 = ""
+ '-- Get Zip32.DLL Message For processing
+ For xx = 0 To 4096
+ If mname.ch(xx) = 0 Then
+ Exit For
+ Else
+ s0 = s0 + Chr(mname.ch(xx))
+ End If
+ Next
+ ' Form1.Print "-- " & s0 & " - " & x & " bytes"
+
+ ' This is called for each zip entry.
+ ' mname is usually the null terminated file name and x the file size.
+ ' s0 has trimmed file name as VB string.
+
+ ' At this point, s0 contains the message passed from the DLL
+ ' It is up to the developer to code something useful here :)
+ ZDLLServ = 0 ' Setting this to 1 will abort the zip!
+
+End Function
+
+'-- Callback For ZIP32.DLL - DLL Password Function
+Public Function ZDLLPass(ByRef p As ZipCBChar, _
+ ByVal n As Long, ByRef m As ZipCBChar, _
+ ByRef Name As ZipCBChar) As Integer
+
+ Dim prompt As String
+ Dim xx As Integer
+ Dim szpassword As String
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ ZDLLPass = 1
+
+ '-- If There Is A Password Have The User Enter It!
+ '-- This Can Be Changed
+ szpassword = InputBox("Please Enter The Password!")
+
+ '-- The User Did Not Enter A Password So Exit The Function
+ If szpassword = "" Then Exit Function
+
+ '-- User Entered A Password So Proccess It
+ For xx = 0 To 255
+ If m.ch(xx) = 0 Then
+ Exit For
+ Else
+ prompt = prompt & Chr(m.ch(xx))
+ End If
+ Next
+
+ For xx = 0 To n - 1
+ p.ch(xx) = 0
+ Next
+
+ For xx = 0 To Len(szpassword) - 1
+ p.ch(xx) = Asc(Mid(szpassword, xx + 1, 1))
+ Next
+
+ p.ch(xx) = Chr(0) ' Put Null Terminator For C
+
+ ZDLLPass = 0
+
+End Function
+
+'-- Callback For ZIP32.DLL - DLL Comment Function
+Public Function ZDLLComm(ByRef s1 As ZipCBChar) As Integer
+
+ Dim xx%, szcomment$
+
+ '-- Always Put This In Callback Routines!
+ On Error Resume Next
+
+ ZDLLComm = 1
+ szcomment = InputBox("Enter the comment")
+ If szcomment = "" Then Exit Function
+ For xx = 0 To Len(szcomment) - 1
+ s1.ch(xx) = Asc(Mid$(szcomment, xx + 1, 1))
+ Next xx
+ s1.ch(xx) = Chr(0) ' Put null terminator for C
+
+End Function
+
+'-- Main ZIP32.DLL Subroutine.
+'-- This Is Where It All Happens!!!
+'--
+'-- (WARNING!) Do Not Change This Function!!!
+'--
+Public Function VBZip32() As Long
+
+ Dim retcode As Long
+
+ On Error Resume Next '-- Nothing Will Go Wrong :-)
+
+ retcode = 0
+
+ '-- Set Address Of ZIP32.DLL Callback Functions
+ '-- (WARNING!) Do Not Change!!!
+ ZUSER.ZDLLPrnt = FnPtr(AddressOf ZDLLPrnt)
+ ZUSER.ZDLLPASSWORD = FnPtr(AddressOf ZDLLPass)
+ ZUSER.ZDLLCOMMENT = FnPtr(AddressOf ZDLLComm)
+ ZUSER.ZDLLSERVICE = FnPtr(AddressOf ZDLLServ)
+
+ '-- Set ZIP32.DLL Callbacks
+ retcode = ZpInit(ZUSER)
+ If retcode = 0 Then
+ MsgBox "Zip32.dll did not initialize. Is it in the current directory " & _
+ "or on the command path?", vbOKOnly, "VB Zip"
+ Exit Function
+ End If
+
+ '-- Setup ZIP32 Options
+ '-- (WARNING!) Do Not Change!
+ ZOPT.Date = zDate ' "12/31/79"? US Date?
+ ZOPT.szRootDir = zRootDir ' Root Directory Pathname
+ ZOPT.szTempDir = zTempDir ' Temp Directory Pathname
+ ZOPT.fSuffix = zSuffix ' Include Suffixes (Not Yet Implemented)
+ ZOPT.fEncrypt = zEncrypt ' 1 If Encryption Wanted
+ ZOPT.fSystem = zSystem ' 1 To Include System/Hidden Files
+ ZOPT.fVolume = zVolume ' 1 If Storing Volume Label
+ ZOPT.fExtra = zExtra ' 1 If Including Extra Attributes
+ ZOPT.fNoDirEntries = zNoDirEntries ' 1 If Ignoring Directory Entries
+ ZOPT.fExcludeDate = zExcludeDate ' 1 If Excluding Files Earlier Than A Specified Date
+ ZOPT.fIncludeDate = zIncludeDate ' 1 If Including Files Earlier Than A Specified Date
+ ZOPT.fVerbose = zVerbose ' 1 If Full Messages Wanted
+ ZOPT.fQuiet = zQuiet ' 1 If Minimum Messages Wanted
+ ZOPT.fCRLF_LF = zCRLF_LF ' 1 If Translate CR/LF To LF
+ ZOPT.fLF_CRLF = zLF_CRLF ' 1 If Translate LF To CR/LF
+ ZOPT.fJunkDir = zJunkDir ' 1 If Junking Directory Names
+ ZOPT.fGrow = zGrow ' 1 If Allow Appending To Zip File
+ ZOPT.fForce = zForce ' 1 If Making Entries Using DOS Names
+ ZOPT.fMove = zMove ' 1 If Deleting Files Added Or Updated
+ ZOPT.fDeleteEntries = zDelEntries ' 1 If Files Passed Have To Be Deleted
+ ZOPT.fUpdate = zUpdate ' 1 If Updating Zip File-Overwrite Only If Newer
+ ZOPT.fFreshen = zFreshen ' 1 If Freshening Zip File-Overwrite Only
+ ZOPT.fJunkSFX = zJunkSFX ' 1 If Junking SFX Prefix
+ ZOPT.fLatestTime = zLatestTime ' 1 If Setting Zip File Time To Time Of Latest File In Archive
+ ZOPT.fComment = zComment ' 1 If Putting Comment In Zip File
+ ZOPT.fOffsets = zOffsets ' 1 If Updating Archive Offsets For SFX Files
+ ZOPT.fPrivilege = zPrivilege ' 1 If Not Saving Privelages
+ ZOPT.fEncryption = zEncryption ' Read Only Property!
+ ZOPT.fRecurse = zRecurse ' 1 or 2 If Recursing Into Subdirectories
+ ZOPT.fRepair = zRepair ' 1 = Fix Archive, 2 = Try Harder To Fix
+ ZOPT.flevel = zLevel ' Compression Level - (0 To 9) Should Be 0!!!
+
+ '-- Set ZIP32.DLL Options
+ retcode = ZpSetOptions(ZOPT)
+
+ '-- Go Zip It Them Up!
+ retcode = ZpArchive(zArgc, zZipFileName, zZipFileNames)
+
+ '-- Return The Function Code
+ VBZip32 = retcode
+
+End Function
+
diff --git a/windll/Vb/Vbzip.vbp b/windll/Vb/Vbzip.vbp
new file mode 100644
index 0000000..b5e5827
--- /dev/null
+++ b/windll/Vb/Vbzip.vbp
@@ -0,0 +1,34 @@
+Type=Exe
+Form=Vbzipfrm.frm
+Module=VBZipBas; VBZipBas.bas
+IconForm="Form1"
+Startup="Form1"
+HelpFile=""
+Title="VBZIP"
+ExeName32="VBZIP.exe"
+Path32="..\..\.."
+Command32=""
+Name="Project1"
+HelpContextID="0"
+CompatibleMode="0"
+MajorVer=1
+MinorVer=0
+RevisionVer=0
+AutoIncrementVer=0
+ServerSupportFiles=0
+VersionCompanyName="Mike"
+CompilationType=-1
+OptimizationType=0
+FavorPentiumPro(tm)=0
+CodeViewDebugInfo=0
+NoAliasing=0
+BoundsCheck=0
+OverflowCheck=0
+FlPointCheck=0
+FDIVCheck=0
+UnroundedFP=0
+StartMode=0
+Unattended=0
+Retained=0
+ThreadPerObject=0
+MaxNumberOfThreads=1
diff --git a/windll/Vb/Vbzipfrm.frm b/windll/Vb/Vbzipfrm.frm
new file mode 100644
index 0000000..de323cd
--- /dev/null
+++ b/windll/Vb/Vbzipfrm.frm
@@ -0,0 +1,130 @@
+VERSION 5.00
+Begin VB.Form Form1
+ AutoRedraw = -1 'True
+ Caption = "Form1"
+ ClientHeight = 3150
+ ClientLeft = 60
+ ClientTop = 345
+ ClientWidth = 6570
+ BeginProperty Font
+ Name = "MS Sans Serif"
+ Size = 9.75
+ Charset = 0
+ Weight = 700
+ Underline = 0 'False
+ Italic = 0 'False
+ Strikethrough = 0 'False
+ EndProperty
+ LinkTopic = "Form1"
+ ScaleHeight = 3150
+ ScaleWidth = 6570
+ StartUpPosition = 1 'CenterOwner
+End
+Attribute VB_Name = "Form1"
+Attribute VB_GlobalNameSpace = False
+Attribute VB_Creatable = False
+Attribute VB_PredeclaredId = True
+Attribute VB_Exposed = False
+
+Option Explicit
+
+'---------------------------------------------------------------
+'-- Please Do Not Remove These Comments!!!
+'---------------------------------------------------------------
+'-- Sample VB 5 code to drive zip32.dll
+'-- Contributed to the Info-ZIP project by Mike Le Voi
+'--
+'-- Contact me at: mlevoi@modemss.brisnet.org.au
+'--
+'-- Visit my home page at: http://modemss.brisnet.org.au/~mlevoi
+'--
+'-- Use this code at your own risk. Nothing implied or warranted
+'-- to work on your machine :-)
+'---------------------------------------------------------------
+'--
+'-- The Source Code Is Freely Available From Info-ZIP At:
+'-- http://www.cdrom.com/pub/infozip/infozip.html
+'--
+'-- A Very Special Thanks To Mr. Mike Le Voi
+'-- And Mr. Mike White Of The Info-ZIP project
+'-- For Letting Me Use And Modify His Orginal
+'-- Visual Basic 5.0 Code! Thank You Mike Le Voi.
+'---------------------------------------------------------------
+'--
+'-- Contributed To The Info-ZIP Project By Raymond L. King
+'-- Modified June 21, 1998
+'-- By Raymond L. King
+'-- Custom Software Designers
+'--
+'-- Contact Me At: king@ntplx.net
+'-- ICQ 434355
+'-- Or Visit Our Home Page At: http://www.ntplx.net/~king
+'--
+'---------------------------------------------------------------
+' This is the original VB example (with some changes) for use
+' with Zip32.dll (Zip 2.31) but not Zip32z64.dll (Zip 3.0).
+'
+' Minor changes to use current directory and VB project files
+' for the example and to turn off encryption.
+'
+' The VB example provided with Zip 3.0 is more extensive. Even
+' if you plan to use the updated zip32.dll instead of the new
+' zip32z64.dll (Zip 3.0), there may be some things you might find
+' useful in the VB example there.
+'
+' 2/27/2005 Ed Gordon
+'---------------------------------------------------------------
+
+Private Sub Form_Click()
+
+ Dim retcode As Integer ' For Return Code From ZIP32.DLL
+
+ Cls
+
+ '-- Set Options - Only The Common Ones Are Shown Here
+ '-- These Must Be Set Before Calling The VBZip32 Function
+ zDate = vbNullString
+ 'zDate = "2005-1-31"
+ 'zExcludeDate = 1
+ 'zIncludeDate = 0
+ zJunkDir = 0 ' 1 = Throw Away Path Names
+ zRecurse = 0 ' 1 = Recurse -r 2 = Recurse -R 2 = Most Useful :)
+ zUpdate = 0 ' 1 = Update Only If Newer
+ zFreshen = 0 ' 1 = Freshen - Overwrite Only
+ zLevel = Asc(9) ' Compression Level (0 - 9)
+ zEncrypt = 0 ' Encryption = 1 For Password Else 0
+ zComment = 0 ' Comment = 1 if required
+
+ '-- Select Some Files - Wildcards Are Supported
+ '-- Change The Paths Here To Your Directory
+ '-- And Files!!!
+ ' Change ZIPnames in VBZipBas.bas if need more than 100 files
+ zArgc = 2 ' Number Of Elements Of mynames Array
+ zZipFileName = "MyFirst.zip"
+ zZipFileNames.zFiles(0) = "vbzipfrm.frm"
+ zZipFileNames.zFiles(1) = "vbzip.vbp"
+ zRootDir = "" ' This Affects The Stored Path Name
+
+ ' Older versions of Zip32.dll do not handle setting
+ ' zRootDir to anything other than "". If you need to
+ ' change root directory an alternative is to just change
+ ' directory. This requires Zip32.dll to be on the command
+ ' path. This should be fixed in Zip 2.31. 1/31/2005 EG
+
+ ' ChDir "a"
+
+ '-- Go Zip Them Up!
+ retcode = VBZip32
+
+ '-- Display The Returned Code Or Error!
+ Print "Return code:" & Str(retcode)
+
+End Sub
+
+Private Sub Form_Load()
+
+ Me.Show
+
+ Print "Click me!"
+
+End Sub
diff --git a/windll/Vb/readmeVB.txt b/windll/Vb/readmeVB.txt
new file mode 100644
index 0000000..1c36949
--- /dev/null
+++ b/windll/Vb/readmeVB.txt
@@ -0,0 +1,34 @@
+On Windows open this file in WordPad.
+
+Contents of the "windll/vb" sub-archive
+
+This directory contains a Visual Basic project example for
+using the zip32.dll library. This project updates the Zip 2.3 VB
+project example and includes some bug fixes and many additional notes
+but is still compatible with zip32.dll. See the comments in the form
+and project files for details. It has been tested on VB 5 and VB 6.
+
+Zip 2.31 itself had bug fixes as well, including some related to the
+dll, and you should now use a version of zip32.dll from that or later.
+This dll includes a fix for the VB dll bug where Date, szRootDir, and
+szTempDir were not passed in correctly and setting these to anything
+but NULL could impact the dll and maybe crash it. You can tell which
+version you have by right clicking on zip32.dll in a file listing,
+looking at properties, selecting the Version tab, and verifying the
+Product Version is at least 2.31.
+
+A new dll is available as part of this Zip 3.0 release and a
+new VB project is included in the VBz64 directory. This dll and
+project supports Zip64 and large files but is not backward compatible
+with Zip32.dll. You will need the new zip32z64.dll to use this project,
+which can be compiled from Zip 3.0. See windll/VBz64 for details.
+
+Note that the files may saved in unix format with carriage returns
+stripped. These must be restored before the project can be successfully
+used. This can be done by using the -a option to unzip. Another way to
+do this is to open each file in WordPad, select and cut a line, paste
+the line back, and save the file. This will force WordPad to format
+the entire file.
+
+Ed Gordon
+2/2/2007
diff --git a/windll/contents b/windll/contents
new file mode 100644
index 0000000..36da176
--- /dev/null
+++ b/windll/contents
@@ -0,0 +1,42 @@
+Contents of the "windll" sub-archive for Zip 2.2 and later:
+
+ contents this file
+ windll16.def definition file for 16-bit Zip DLL
+ windll32.def definition file for 32-bit Zip DLL
+ windll.c Contains the entry point for the DLL, "fake" printing,
+ and password functions.
+ windll.h header file for both 16 and 32-bit DLLs.
+ zipver.h versioning information for resource file, and also
+ used by WiZ application itself.
+ windll.rc resource file for both 16 and 32-bit DLLs
+ windll.txt simplistic explanation of how to use DLL.
+ structs.h header file used by both the dll and by WiZ which defines
+ several structures passed to the dll.
+ example.c a very simplistic example of how to load the dll, and make
+ a call into it.
+ example.h header file for example.c
+
+ borland\dll <dir> contains 16 and 32 bit make files for the zip dlls.
+ borland\lib <dir> contains 32 bit make files for the zip32 static library
+ visualc\dll <dir> contains Visual C++ 5.0 project and make files for
+ zip32 dll.
+ visualc\lib <dir> contains Visual C++ 5.0 project and make files for
+ zip32 static library.
+
+The Microsoft C port has not been tested as completely as the Borland port.
+Note that Borland C++ 5.0 is full of bugs version 4.5 is recommended instead.
+If you must use Borland C++ 5.0, using the Intel optimizing compiler is
+required to avoid crashes (possibly due to a bug in the stat() function
+in the normal Borland compiler.) This does have the advantage of giving you
+a smaller code size than the 4.52 compiler.
+
+Borland C++ 5.01 has resolved many of the problems seen with 5.0, and
+can now reliably be used.
+
+Note that I have been singularly unsuccessful in getting this to compile
+and run under MSVC 1.52c.
+
+Last updated October 13, 1997
+
+Mike White
+
diff --git a/windll/example.c b/windll/example.c
new file mode 100644
index 0000000..f1a1936
--- /dev/null
+++ b/windll/example.c
@@ -0,0 +1,375 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ A very simplistic example of how to load the zip dll and make a call into it.
+ Note that none of the command line options are implemented in this example.
+
+ */
+
+#ifndef WIN32
+# define WIN32
+#endif
+#define API
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <string.h>
+#ifdef __BORLANDC__
+#include <dir.h>
+#else
+#include <direct.h>
+#endif
+#include "example.h"
+#include "zipver.h"
+
+#ifdef WIN32
+#include <commctrl.h>
+#include <winver.h>
+#else
+#include <ver.h>
+#endif
+
+#ifdef WIN32
+#define ZIP_DLL_NAME "ZIP32.DLL\0"
+#else
+#define ZIP_DLL_NAME "ZIP16.DLL\0"
+#endif
+
+#define DLL_WARNING "Cannot find %s."\
+ " The Dll must be in the application directory, the path, "\
+ "the Windows directory or the Windows System directory."
+#define DLL_VERSION_WARNING "%s has the wrong version number."\
+ " Insure that you have the correct dll's installed, and that "\
+ "an older dll is not in your path or Windows System directory."
+
+int hFile; /* file handle */
+
+ZCL ZpZCL;
+LPZIPUSERFUNCTIONS lpZipUserFunctions;
+HANDLE hZUF = (HANDLE)NULL;
+HINSTANCE hUnzipDll;
+HANDLE hFileList;
+ZPOPT ZpOpt;
+#ifdef WIN32
+DWORD dwPlatformId = 0xFFFFFFFF;
+#endif
+HINSTANCE hZipDll;
+
+
+/* Forward References */
+_DLL_ZIP ZipArchive;
+_ZIP_USER_FUNCTIONS ZipInit;
+ZIPSETOPTIONS ZipSetOptions;
+
+void FreeUpMemory(void);
+int WINAPI DummyPassword(LPSTR, int, LPCSTR, LPCSTR);
+int WINAPI DummyPrint(char far *, unsigned long);
+int WINAPI WINAPI DummyComment(char far *);
+
+#ifdef WIN32
+BOOL IsNT(VOID);
+#endif
+
+/****************************************************************************
+
+ FUNCTION: Main(int argc, char **argv)
+
+****************************************************************************/
+#ifdef __BORLANDC__
+# ifdef WIN32
+#pragma argsused
+# endif
+#endif
+int main(int argc, char **argv)
+{
+LPSTR szFileList;
+char **index, *sz;
+int retcode, i, cc;
+DWORD dwVerInfoSize;
+DWORD dwVerHnd;
+char szFullPath[PATH_MAX];
+#ifdef WIN32
+char *ptr;
+#else
+HFILE hfile;
+OFSTRUCT ofs;
+#endif
+HANDLE hMem; /* handle to mem alloc'ed */
+
+if (argc < 3)
+ return 0; /* Exits if not proper number of arguments */
+
+hZUF = GlobalAlloc( GPTR, (DWORD)sizeof(ZIPUSERFUNCTIONS));
+if (!hZUF)
+ {
+ return 0;
+ }
+lpZipUserFunctions = (LPZIPUSERFUNCTIONS)GlobalLock(hZUF);
+
+if (!lpZipUserFunctions)
+ {
+ GlobalFree(hZUF);
+ return 0;
+ }
+
+lpZipUserFunctions->print = DummyPrint;
+lpZipUserFunctions->password = DummyPassword;
+lpZipUserFunctions->comment = DummyComment;
+
+/* Let's go find the dll */
+#ifdef WIN32
+if (SearchPath(
+ NULL, /* address of search path */
+ ZIP_DLL_NAME, /* address of filename */
+ NULL, /* address of extension */
+ PATH_MAX, /* size, in characters, of buffer */
+ szFullPath, /* address of buffer for found filename */
+ &ptr /* address of pointer to file component */
+ ) == 0)
+#else
+hfile = OpenFile(ZIP_DLL_NAME, &ofs, OF_SEARCH);
+if (hfile == HFILE_ERROR)
+#endif
+ {
+ char str[256];
+ wsprintf (str, DLL_WARNING, ZIP_DLL_NAME);
+ printf("%s\n", str);
+ FreeUpMemory();
+ return 0;
+ }
+#ifndef WIN32
+else
+ lstrcpy(szFullPath, ofs.szPathName);
+_lclose(hfile);
+#endif
+
+/* Now we'll check the zip dll version information */
+dwVerInfoSize =
+ GetFileVersionInfoSize(szFullPath, &dwVerHnd);
+
+if (dwVerInfoSize)
+ {
+ BOOL fRet, fRetName;
+ char str[256];
+ LPSTR lpstrVffInfo; /* Pointer to block to hold info */
+ LPSTR lszVer = NULL;
+ LPSTR lszVerName = NULL;
+ UINT cchVer = 0;
+
+ /* Get a block big enough to hold the version information */
+ hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
+ lpstrVffInfo = GlobalLock(hMem);
+
+ /* Get the version information */
+ GetFileVersionInfo(szFullPath, 0L, dwVerInfoSize, lpstrVffInfo);
+ fRet = VerQueryValue(lpstrVffInfo,
+ TEXT("\\StringFileInfo\\040904E4\\FileVersion"),
+ (LPVOID)&lszVer,
+ &cchVer);
+ fRetName = VerQueryValue(lpstrVffInfo,
+ TEXT("\\StringFileInfo\\040904E4\\CompanyName"),
+ (LPVOID)&lszVerName,
+ &cchVer);
+ if (!fRet || !fRetName ||
+ (lstrcmpi(lszVer, ZIP_DLL_VERSION) != 0) ||
+ (lstrcmpi(lszVerName, COMPANY_NAME) != 0))
+ {
+ wsprintf (str, DLL_VERSION_WARNING, ZIP_DLL_NAME);
+ printf("%s\n", str);
+ FreeUpMemory();
+ return 0;
+ }
+ /* free memory */
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ }
+else
+ {
+ char str[256];
+ wsprintf (str, DLL_VERSION_WARNING, ZIP_DLL_NAME);
+ printf("%s\n", str);
+ FreeUpMemory();
+ return 0;
+ }
+/* Okay, now we know that the dll exists, and has the proper version
+ * information in it. We can go ahead and load it.
+ */
+hZipDll = LoadLibrary(ZIP_DLL_NAME);
+#ifndef WIN32
+if (hZipDll > HINSTANCE_ERROR)
+#else
+if (hZipDll != NULL)
+#endif
+ {
+ (_DLL_ZIP)ZipArchive = (_DLL_ZIP)GetProcAddress(hZipDll, "ZpArchive");
+ (ZIPSETOPTIONS)ZipSetOptions = (ZIPSETOPTIONS)GetProcAddress(hZipDll, "ZpSetOptions");
+ if (!ZipArchive || !ZipSetOptions)
+ {
+ char str[256];
+ wsprintf (str, "Could not get entry point to %s", ZIP_DLL_NAME);
+ MessageBox((HWND)NULL, str, "Info-ZIP Example", MB_ICONSTOP | MB_OK);
+ FreeUpMemory();
+ return 0;
+ }
+ }
+else
+ {
+ char str[256];
+ wsprintf (str, "Could not load %s", ZIP_DLL_NAME);
+ printf("%s\n", str);
+ FreeUpMemory();
+ return 0;
+ }
+
+(_ZIP_USER_FUNCTIONS)ZipInit = (_ZIP_USER_FUNCTIONS)GetProcAddress(hZipDll, "ZpInit");
+if (!ZipInit)
+ {
+ printf("Cannot get address of ZpInit in Zip dll. Terminating...");
+ FreeLibrary(hZipDll);
+ FreeUpMemory();
+ return 0;
+ }
+if (!(*ZipInit)(lpZipUserFunctions))
+ {
+ printf("Application functions not set up properly. Terminating...");
+ FreeLibrary(hZipDll);
+ FreeUpMemory();
+ return 0;
+ }
+
+/* Here is where the action starts */
+ZpOpt.fSuffix = FALSE; /* include suffixes (not yet implemented) */
+ZpOpt.fEncrypt = FALSE; /* true if encryption wanted */
+ZpOpt.fSystem = FALSE; /* true to include system/hidden files */
+ZpOpt.fVolume = FALSE; /* true if storing volume label */
+ZpOpt.fExtra = FALSE; /* true if including extra attributes */
+ZpOpt.fNoDirEntries = FALSE; /* true if ignoring directory entries */
+ZpOpt.fVerbose = FALSE; /* true if full messages wanted */
+ZpOpt.fQuiet = FALSE; /* true if minimum messages wanted */
+ZpOpt.fCRLF_LF = FALSE; /* true if translate CR/LF to LF */
+ZpOpt.fLF_CRLF = FALSE; /* true if translate LF to CR/LF */
+ZpOpt.fJunkDir = FALSE; /* true if junking directory names */
+ZpOpt.fGrow = FALSE; /* true if allow appending to zip file */
+ZpOpt.fForce = FALSE; /* true if making entries using DOS names */
+ZpOpt.fMove = FALSE; /* true if deleting files added or updated */
+ZpOpt.fUpdate = FALSE; /* true if updating zip file--overwrite only
+ if newer */
+ZpOpt.fFreshen = FALSE; /* true if freshening zip file--overwrite only */
+ZpOpt.fJunkSFX = FALSE; /* true if junking sfx prefix*/
+ZpOpt.fLatestTime = FALSE; /* true if setting zip file time to time of
+ latest file in archive */
+ZpOpt.fComment = FALSE; /* true if putting comment in zip file */
+ZpOpt.fOffsets = FALSE; /* true if updating archive offsets for sfx
+ files */
+ZpOpt.fDeleteEntries = FALSE; /* true if deleting files from archive */
+ZpOpt.fRecurse = 0; /* subdir recursing mode: 1 = "-r", 2 = "-R" */
+ZpOpt.fRepair = 0; /* archive repair mode: 1 = "-F", 2 = "-FF" */
+ZpOpt.Date = NULL; /* Not using, set to NULL pointer */
+getcwd(szFullPath, PATH_MAX); /* Set directory to current directory */
+ZpOpt.szRootDir = szFullPath;
+
+ZpZCL.argc = argc - 2; /* number of files to archive - adjust for the
+ actual number of file names to be added */
+ZpZCL.lpszZipFN = argv[1]; /* archive to be created/updated */
+
+/* Copy over the appropriate portions of argv, basically stripping out argv[0]
+ (name of the executable) and argv[1] (name of the archive file)
+ */
+hFileList = GlobalAlloc( GPTR, 0x10000L);
+if ( hFileList )
+ {
+ szFileList = (char far *)GlobalLock(hFileList);
+ }
+index = (char **)szFileList;
+cc = (sizeof(char *) * ZpZCL.argc);
+sz = szFileList + cc;
+
+for (i = 0; i < ZpZCL.argc; i++)
+ {
+ cc = lstrlen(argv[i+2]);
+ lstrcpy(sz, argv[i+2]);
+ index[i] = sz;
+ sz += (cc + 1);
+ }
+ZpZCL.FNV = (char **)szFileList; /* list of files to archive */
+
+/* Set the options */
+ZipSetOptions(&ZpOpt);
+
+/* Go zip 'em up */
+retcode = ZipArchive(ZpZCL);
+if (retcode != 0)
+ printf("Error in archiving\n");
+
+GlobalUnlock(hFileList);
+GlobalFree(hFileList);
+FreeUpMemory();
+FreeLibrary(hZipDll);
+return 1;
+}
+
+void FreeUpMemory(void)
+{
+if (hZUF)
+ {
+ GlobalUnlock(hZUF);
+ GlobalFree(hZUF);
+ }
+}
+
+#ifdef WIN32
+/* This simply determines if we are running on NT */
+BOOL IsNT(VOID)
+{
+if(dwPlatformId != 0xFFFFFFFF)
+ return dwPlatformId;
+else
+/* note: GetVersionEx() doesn't exist on WinNT 3.1 */
+ {
+ if(GetVersion() < 0x80000000)
+ {
+ (BOOL)dwPlatformId = TRUE;
+ }
+ else
+ {
+ (BOOL)dwPlatformId = FALSE;
+ }
+ }
+return dwPlatformId;
+}
+#endif
+
+/* Password entry routine - see password.c in the wiz directory for how
+ this is actually implemented in Wiz. If you have an encrypted file,
+ this will probably give you great pain. Note that none of the
+ parameters are being used here, and this will give you warnings.
+ */
+int WINAPI DummyPassword(LPSTR p, int n, LPCSTR m, LPCSTR name)
+{
+return 1;
+}
+
+/* Dummy "print" routine that simply outputs what is sent from the dll */
+int WINAPI DummyPrint(char far *buf, unsigned long size)
+{
+printf("%s", buf);
+return (unsigned int) size;
+}
+
+
+/* Dummy "comment" routine. See comment.c in the wiz directory for how
+ this is actually implemented in Wiz. This will probably cause you
+ great pain if you ever actually make a call into it.
+ */
+int WINAPI DummyComment(char far *szBuf)
+{
+szBuf[0] = '\0';
+return TRUE;
+}
diff --git a/windll/example.h b/windll/example.h
new file mode 100644
index 0000000..da52598
--- /dev/null
+++ b/windll/example.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ Example header file
+*/
+#ifndef _EXAMPLE_H
+#define _EXAMPLE_H
+
+#include <windows.h>
+#include <assert.h> /* required for all Windows applications */
+#include <stdlib.h>
+#include <stdio.h>
+#include <commdlg.h>
+#include <dlgs.h>
+#include <windowsx.h>
+
+#ifndef EXPENTRY
+#define EXPENTRY WINAPI
+#endif
+
+#include "structs.h"
+
+/* Defines */
+#ifndef MSWIN
+#define MSWIN
+#endif
+
+typedef int (WINAPI * _DLL_ZIP)(ZCL);
+typedef int (WINAPI * _ZIP_USER_FUNCTIONS)(LPZIPUSERFUNCTIONS);
+typedef BOOL (WINAPI * ZIPSETOPTIONS)(LPZPOPT);
+
+/* Global variables */
+
+extern LPZIPUSERFUNCTIONS lpZipUserFunctions;
+
+extern HINSTANCE hZipDll;
+
+extern int hFile; /* file handle */
+
+/* Global functions */
+
+int WINAPI DisplayBuf(char far *, unsigned long int);
+extern _DLL_ZIP ZipArchive;
+extern _ZIP_USER_FUNCTIONS ZipInit;
+extern ZIPSETOPTIONS ZipSetOptions;
+
+#endif /* _EXAMPLE_H */
+
diff --git a/windll/structs.h b/windll/structs.h
new file mode 100644
index 0000000..0f36df6
--- /dev/null
+++ b/windll/structs.h
@@ -0,0 +1,30 @@
+/*
+ windll/structs.h - Zip 3
+
+ Copyright (c) 1990-2003 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2003-May-08 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _ZIP_STRUCTS_H
+#define _ZIP_STRUCTS_H
+
+#ifndef Far
+# define Far far
+#endif
+
+/* Porting definations between Win 3.1x and Win32 */
+#ifdef WIN32
+# define far
+# define _far
+# define __far
+# define near
+# define _near
+# define __near
+#endif
+
+#include "../api.h"
+
+#endif /* _ZIP_STRUCTS_H */
diff --git a/windll/visualc/dll/zip32z64.dsp b/windll/visualc/dll/zip32z64.dsp
new file mode 100644
index 0000000..46bea99
--- /dev/null
+++ b/windll/visualc/dll/zip32z64.dsp
@@ -0,0 +1,168 @@
+# Microsoft Developer Studio Project File - Name="zip32z64" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=zip32z64 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zip32z64.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zip32z64.mak" CFG="zip32z64 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zip32z64 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "zip32z64 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zip32z64 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release\app"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c
+# ADD CPP /nologo /Zp4 /MT /W3 /GX /O2 /I "..\..\.." /I "..\..\..\WINDLL" /I "..\..\..\WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG" /d "WIN32"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "zip32z64 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug\app"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c
+# ADD CPP /nologo /Zp4 /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\ZIP" /I "..\..\..\WINDLL" /I "..\..\..\WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG" /d "WIN32"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\Debug\app/zip32z64.dll" /pdbtype:sept
+# SUBTRACT LINK32 /map
+
+!ENDIF
+
+# Begin Target
+
+# Name "zip32z64 - Win32 Release"
+# Name "zip32z64 - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\..\api.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\crypt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\deflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\globals.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\win32\nt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\trees.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\ttyio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\win32\win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\win32\win32i64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\win32\win32zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\windll\windll.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\windll\windll.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\windll\windll32.def
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\zipfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\zipup.c
+# End Source File
+# End Target
+# End Project
diff --git a/windll/visualc/dll/zip32z64.dsw b/windll/visualc/dll/zip32z64.dsw
new file mode 100644
index 0000000..4643105
--- /dev/null
+++ b/windll/visualc/dll/zip32z64.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zip32z64"=.\zip32z64.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/windll/visualc/lib/zip32z64.dsp b/windll/visualc/lib/zip32z64.dsp
new file mode 100644
index 0000000..a610912
--- /dev/null
+++ b/windll/visualc/lib/zip32z64.dsp
@@ -0,0 +1,158 @@
+# Microsoft Developer Studio Project File - Name="zip32z64" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=zip32z64 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "zip32z64.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "zip32z64.mak" CFG="zip32z64 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "zip32z64 - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "zip32z64 - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "zip32z64 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release\libs"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\.." /I "..\..\..\win32" /I "..\..\..\windll" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /D "ZIPLIB" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "zip32z64 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug\libs"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\..\.." /I "..\..\..\win32" /I "..\..\..\windll" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "NO_ASM" /D "WINDLL" /D "MSDOS" /D "USE_ZIPMAIN" /D "ZIPLIB" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "zip32z64 - Win32 Release"
+# Name "zip32z64 - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\..\api.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\crc32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\crypt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\deflate.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\fileio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\globals.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\win32\nt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\trees.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\ttyio.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\win32\win32.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\win32\win32zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\windll\windll.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\windll\windll.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\zip.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\zipfile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\windll\ziplib.def
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\zipup.c
+# End Source File
+# End Target
+# End Project
diff --git a/windll/visualc/lib/zip32z64.dsw b/windll/visualc/lib/zip32z64.dsw
new file mode 100644
index 0000000..4643105
--- /dev/null
+++ b/windll/visualc/lib/zip32z64.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "zip32z64"=.\zip32z64.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/windll/windll.aps b/windll/windll.aps
new file mode 100644
index 0000000..73e3468
--- /dev/null
+++ b/windll/windll.aps
Binary files differ
diff --git a/windll/windll.c b/windll/windll.c
new file mode 100644
index 0000000..f825108
--- /dev/null
+++ b/windll/windll.c
@@ -0,0 +1,176 @@
+/*
+ windll/windll.c - Zip 3
+
+ Copyright (c) 1990-2004 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2003-May-08 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * windll.c by Mike White loosly based on Mark Adler's zip.c
+ */
+#include <windows.h>
+#include <process.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include "../zip.h"
+#include "windll.h"
+
+HINSTANCE hCurrentInst;
+#ifdef ZIPLIB
+/* DLL Entry Point */
+#ifdef __BORLANDC__
+#pragma argsused
+/* Borland seems to want DllEntryPoint instead of DllMain like MSVC */
+#define DllMain DllEntryPoint
+#endif
+#ifdef WIN32
+BOOL WINAPI DllMain( HINSTANCE hInstance,
+ DWORD dwReason,
+ LPVOID plvReserved)
+#else
+int WINAPI LibMain( HINSTANCE hInstance,
+ WORD wDataSegment,
+ WORD wHeapSize,
+ LPSTR lpszCmdLine )
+#endif
+{
+#ifndef WIN32
+/* The startup code for the DLL initializes the local heap(if there is one)
+ with a call to LocalInit which locks the data segment. */
+
+if ( wHeapSize != 0 )
+ {
+ UnlockData( 0 );
+ }
+hCurrentInst = hInstance;
+return 1; /* Indicate that the DLL was initialized successfully. */
+#else
+BOOL rc = TRUE;
+switch( dwReason )
+ {
+ case DLL_PROCESS_ATTACH:
+ // DLL is loaded. Do your initialization here.
+ // If cannot init, set rc to FALSE.
+ hCurrentInst = hInstance;
+ break;
+
+ case DLL_PROCESS_DETACH:
+ // DLL is unloaded. Do your cleanup here.
+ break;
+ default:
+ break;
+ }
+return rc;
+#endif
+}
+
+#ifdef __BORLANDC__
+#pragma argsused
+#endif
+int FAR PASCAL WEP ( int bSystemExit )
+{
+return 1;
+}
+#endif /* ZIPLIB */
+
+LPSTR szCommentBuf;
+HANDLE hStr;
+
+void comment(unsigned int comlen)
+{
+unsigned int i;
+if (comlen > 65534L)
+ comlen = (unsigned int) 65534L;
+hStr = GlobalAlloc( GPTR, (DWORD)65535L);
+if ( !hStr )
+ {
+ hStr = GlobalAlloc( GPTR, (DWORD) 2);
+ szCommentBuf = GlobalLock(hStr);
+ szCommentBuf[0] = '\0';
+ return;
+ }
+
+szCommentBuf = GlobalLock(hStr);
+if (comlen)
+ {
+ for (i = 0; i < comlen; i++)
+ szCommentBuf[i] = zcomment[i];
+ szCommentBuf[comlen] = '\0';
+ }
+else
+ szCommentBuf[0] = '\0';
+free(zcomment);
+zcomment = malloc(1);
+*zcomment = 0;
+lpZipUserFunctions->comment(szCommentBuf);
+return;
+}
+
+#define STDIO_BUF_SIZE 16384
+
+int __far __cdecl printf(const char *format, ...)
+{
+va_list argptr;
+HANDLE hMemory;
+LPSTR pszBuffer;
+int len;
+
+va_start(argptr, format);
+hMemory = GlobalAlloc(GMEM_MOVEABLE, STDIO_BUF_SIZE);
+WinAssert(hMemory);
+if (!hMemory)
+ {
+ return 0;
+ }
+pszBuffer = (LPSTR)GlobalLock(hMemory);
+WinAssert(pszBuffer);
+len = wvsprintf(pszBuffer, format, argptr);
+va_end(argptr);
+WinAssert(strlen(pszBuffer) < STDIO_BUF_SIZE);
+len = lpZipUserFunctions->print(pszBuffer, len);
+GlobalUnlock(hMemory);
+GlobalFree(hMemory);
+return len;
+}
+
+/* fprintf clone for code in zip.c, etc. */
+int __far __cdecl fprintf(FILE *file, const char *format, ...)
+{
+va_list argptr;
+HANDLE hMemory;
+LPSTR pszBuffer;
+int len;
+
+va_start(argptr, format);
+hMemory = GlobalAlloc(GMEM_MOVEABLE, STDIO_BUF_SIZE);
+WinAssert(hMemory);
+if (!hMemory)
+ {
+ return 0;
+ }
+pszBuffer = GlobalLock(hMemory);
+WinAssert(pszBuffer);
+len = wvsprintf(pszBuffer, format, argptr);
+va_end(argptr);
+WinAssert(strlen(pszBuffer) < STDIO_BUF_SIZE);
+if ((file == stderr) || (file == stdout))
+ {
+ len = lpZipUserFunctions->print(pszBuffer, len);
+ }
+else
+ len = write(fileno(file),(char far *)(pszBuffer), len);
+GlobalUnlock(hMemory);
+GlobalFree(hMemory);
+return len;
+}
+
+void __far __cdecl perror(const char *parm1)
+{
+printf("%s", parm1);
+}
+
+
diff --git a/windll/windll.h b/windll/windll.h
new file mode 100644
index 0000000..0a45fc1
--- /dev/null
+++ b/windll/windll.h
@@ -0,0 +1,63 @@
+/*
+ windll/windll.h - Zip 3
+
+ Copyright (c) 1990-2004 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2003-May-08 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ WiZ 1.0 header file for zip dll
+*/
+#ifndef _WINDLL_H
+#define _WINDLL_H
+
+#include "structs.h"
+
+#ifndef MSWIN
+#define MSWIN
+#endif
+
+#ifndef USE_ZIPMAIN
+# define USE_ZIPMAIN
+#endif
+
+#ifndef NDEBUG
+# define WinAssert(exp) \
+ {\
+ if (!(exp))\
+ {\
+ char szBuffer[40];\
+ sprintf(szBuffer, "File %s, Line %d",\
+ __FILE__, __LINE__) ;\
+ if (IDABORT == MessageBox((HWND)NULL, szBuffer,\
+ "Assertion Error",\
+ MB_ABORTRETRYIGNORE|MB_ICONSTOP))\
+ FatalExit(-1);\
+ }\
+ }
+
+#else
+# define WinAssert(exp)
+#endif
+
+#define cchFilesMax 4096
+
+extern int WINAPI ZpArchive(ZCL C, LPZPOPT Opts);
+extern HWND hGetFilesDlg;
+extern char szFilesToAdd[80];
+extern char rgszFiles[cchFilesMax];
+BOOL WINAPI CommentBoxProc(HWND hwndDlg, WORD wMessage, WPARAM wParam, LPARAM lParam);
+BOOL PasswordProc(HWND, WORD, WPARAM, LPARAM);
+void CenterDialog(HWND hwndParent, HWND hwndDlg);
+void comment(unsigned int);
+
+extern LPSTR szCommentBuf;
+extern HANDLE hStr;
+extern HWND hWndMain;
+void __far __cdecl perror(const char *);
+
+#endif /* _WINDLL_H */
+
diff --git a/windll/windll.rc b/windll/windll.rc
new file mode 100644
index 0000000..4fab86a
--- /dev/null
+++ b/windll/windll.rc
@@ -0,0 +1,57 @@
+#define APSTUDIO_READONLY_SYMBOLS
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include <windows.h>
+#if (defined(WIN32) && !defined(__EMX__) && !defined(__MINGW32__))
+#include <winver.h>
+#endif
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "../revision.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0
+ PRODUCTVERSION Z_MAJORVER,Z_MINORVER,Z_PATCHLEVEL,0
+ FILEFLAGSMASK 0x3L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+#ifdef _UNICODE
+ BLOCK "040904B0"
+#else
+ BLOCK "040904E4"
+#endif
+ BEGIN
+ VALUE "CompanyName", IZ_COMPANY_NAME "\0"
+ VALUE "FileDescription", "Info-ZIP's Zip dll\0"
+ VALUE "FileVersion", VERSION "\0"
+ VALUE "InternalName", "Zip32z64\0"
+ VALUE "LegalCopyright", "Info-ZIP 1997 - 2008\0"
+ VALUE "OriginalFilename", "ZIP32Z64.DLL\0"
+ VALUE "ProductName", "Info-ZIP's WiZ\0"
+ VALUE "ProductVersion", VERSION "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+#ifdef _UNICODE
+ VALUE "Translation", 0x409, 1200
+#else
+ VALUE "Translation", 0x409, 1252
+#endif
+ END
+END
diff --git a/windll/windll.txt b/windll/windll.txt
new file mode 100644
index 0000000..8df4bae
--- /dev/null
+++ b/windll/windll.txt
@@ -0,0 +1,147 @@
+The code set out below is not intended to be compiled, but is only intended as
+a very simplistic pointer to how to load and call the dll. You will have to
+look in the files referenced below for actual, working code.
+
+There is one entry point that uses the structure shown below:
+
+typedef struct {
+LPSTR Date; /* Date to include after */
+LPSTR szRootDir; /* Directory to use as base for zipping */
+LPSTR szTempDir; /* Temporary directory used during zipping */
+BOOL fTemp; /* Use temporary directory '-b' during zipping */
+BOOL fSuffix; /* include suffixes (not implemented in WiZ) */
+BOOL fEncrypt; /* encrypt files */
+BOOL fSystem; /* include system and hidden files */
+BOOL fVolume; /* Include volume label */
+BOOL fExtra; /* Exclude extra attributes */
+BOOL fNoDirEntries; /* Do not add directory entries */
+BOOL fExcludeDate; /* Exclude files earlier than specified date */
+BOOL fIncludeDate; /* Include only files earlier than specified date */
+BOOL fVerbose; /* Mention oddities in zip file structure */
+BOOL fQuiet; /* Quiet operation */
+BOOL fCRLF_LF; /* Translate CR/LF to LF */
+BOOL fLF_CRLF; /* Translate LF to CR/LF */
+BOOL fJunkDir; /* Junk directory names */
+BOOL fGrow; /* Allow appending to a zip file */
+BOOL fForce; /* Make entries using DOS names (k for Katz) */
+BOOL fMove; /* Delete files added or updated in zip file */
+BOOL fDeleteEntries; /* Delete files from zip file */
+BOOL fUpdate; /* Update zip file--overwrite only if newer */
+BOOL fFreshen; /* Freshen zip file--overwrite only */
+BOOL fJunkSFX; /* Junk SFX prefix */
+BOOL fLatestTime; /* Set zip file time to time of latest file in it */
+BOOL fComment; /* Put comment in zip file */
+BOOL fOffsets; /* Update archive offsets for SFX files */
+BOOL fPrivilege; /* Use privileges (WIN32 only) */
+BOOL fEncryption; /* TRUE if encryption supported, else FALSE.
+ this is a read-only flag */
+LPSTR szSplitSize; /* This string contains the size that you want to
+ split the archive into. i.e. 100 for 100 bytes,
+ 2K for 2 k bytes, where K is 1024, m for meg
+ and g for gig. If this string is not NULL it
+ will automatically be assumed that you wish to
+ split an archive. */
+LPSTR szIncludeList; /* Pointer to include file list string (for VB) */
+long IncludeListCount; /* Count of file names in the include list array */
+char **IncludeList; /* Pointer to include file list array. Note that the last
+ entry in the array must be NULL */
+LPSTR szExcludeList; /* Pointer to exclude file list (for VB) */
+long ExcludeListCount; /* Count of file names in the include list array */
+char **ExcludeList; /* Pointer to exclude file list array. Note that the last
+ entry in the array must be NULL */
+int fRecurse; /* Recurse into subdirectories. 1 => -r, 2 => -R */
+int fRepair; /* Repair archive. 1 => -F, 2 => -FF */
+char fLevel; /* Compression level (0 - 9) */
+} ZPOPT, _far *LPZPOPT;
+
+The main entry point is ZpArchive(ZCL, *Opts) where the structure shown below
+is passed to the DLL when it is called.
+
+typedef struct {
+int argc; = Count of files to zip
+LPSTR lpszZipFN; = Archive file name
+char **FNV; = file names to zip up. Think of this an argv
+LPSTR lpszAltFNL; /* pointer to a string containing a list of file names to zip up,
+ separated by whitespace. Intended for use only by VB users, all
+ others should set this to NULL. */
+} ZCL, _far *LPZCL;
+
+
+For examples of how the actual calls to the dll were set up in WiZ, look in
+the file makezip.c in the WiZ source directory.
+
+For examples of how the actual loading and unloading of the dll's themselves
+was done, look in wizmain.c in the WiZ source directory. Note that WiZ looks
+specifically for a particular version number of the dll, and also expects to
+find the company name to be Info-ZIP. This is to protect from getting different
+versions of the dll loaded, with resulting unknown behavior.
+
+There is a very simplistic example of how to load and call into the dll in
+example.c and example.h. Note that this example does not implement any
+command line switches at all, and is merely intended as a guide for those
+brave enough to enter a new world.
+
+There are three additional (at the moment) entry points:
+
+ZpInit, defined as
+
+int WINAPI ZpInit(ZIPUSERFUNCTIONS far * lpZipUserFunc);
+
+where ZIPUSERFUNCTIONS is defined as below.
+
+ZpVersion, defined as
+
+ZpVer * ZpVersion(void);
+
+where ZpVer is defined as:
+
+typedef struct _ZpVer {
+ ulg structlen; /* length of the struct being passed */
+ ulg flag; /* bit 0: is_beta bit 1: uses_zlib */
+ char *betalevel; /* e.g., "g BETA" or "" */
+ char *date; /* e.g., "4 Sep 95" (beta) or "4 September 1995" */
+ char *zlib_version; /* e.g., "0.95" or NULL */
+ BOOL fEncryption; /* TRUE if encryption enabled, FALSE otherwise */
+ _zip_version_type zip;
+ _zip_version_type os2dll;
+ _zip_version_type windll;
+} ZpVer;
+
+See api.c for exactly what ZpVersion does, but the short version of
+what it does is return the zip and dll versions in the ZpVer structure.
+The structure typedef's are in api.h. It will also tell you if encryption
+is enabled.
+
+The typedef's for the function pointers in the structure ZIPUSERFUNCTIONS
+are shown immediately below.
+
+typedef int (WINAPI DLLPRNT) (LPSTR, unsigned long);
+typedef int (WINAPI DLLPASSWORD) (LPSTR, int, LPCSTR, LPCSTR);
+typedef int (WINAPI DLLSPLIT) (LPSTR);
+#ifdef ZIP64_SUPPORT
+typedef int (WINAPI DLLSERVICE) (LPCSTR, __int64);
+typedef int (WINAPI DLLSERVICE_NO_INT64) (LPCSTR, unsigned long, unsigned long);
+#else
+typedef int (WINAPI DLLSERVICE) (LPCSTR, unsigned long);
+#endif
+#endif
+typedef int (WINAPI DLLCOMMENT)(LPSTR);
+
+
+typedef struct {
+DLLPRNT *print;
+DLLCOMMENT *comment;
+DLLPASSWORD *password;
+DLLSPLIT *split; /* This MUST be set to NULL unless you want to be queried
+ for a destination for each split archive. */
+#ifdef ZIP64_SUPPORT
+DLLSERVICE *ServiceApplication64;
+DLLSERVICE_NO_INT64 *ServiceApplication64_No_Int64;
+#else
+DLLSERVICE *ServiceApplication;
+#endif
+} ZIPUSERFUNCTIONS, far * LPZIPUSERFUNCTIONS;
+
+Last revised April 26, 2004.
+
+Mike White
diff --git a/windll/windll16.def b/windll/windll16.def
new file mode 100644
index 0000000..1173b5f
--- /dev/null
+++ b/windll/windll16.def
@@ -0,0 +1,15 @@
+;module-definition file for Windows Zip DLL -- used by link.exe
+LIBRARY ZIP16 ; Library module name
+DESCRIPTION 'Windows Info-ZIP Zip DLL 1.01 by Info-ZIP, Mike White 1996'
+
+CODE PRELOAD FIXED
+
+DATA PRELOAD MOVEABLE
+
+EXPORTS
+ ZpArchive
+ ZpVersion
+ ZpInit
+ ZpSetOptions
+ ZpGetOptions
+
diff --git a/windll/windll32.def b/windll/windll32.def
new file mode 100644
index 0000000..f1426ee
--- /dev/null
+++ b/windll/windll32.def
@@ -0,0 +1,14 @@
+;module-definition file for Windows Zip DLL -- used by link.exe
+
+LIBRARY ZIP32Z64 ; Library module name
+DESCRIPTION 'Windows Info-ZIP Zip DLL 3.0 by Info-ZIP, Mike White 2004'
+
+;CODE PRELOAD FIXED
+
+;DATA PRELOAD MOVEABLE
+
+EXPORTS
+ ZpArchive
+ ZpVersion
+ ZpInit
+
diff --git a/windll/ziplib.def b/windll/ziplib.def
new file mode 100644
index 0000000..a768740
--- /dev/null
+++ b/windll/ziplib.def
@@ -0,0 +1,15 @@
+;module-definition file for Windows Zip static library -- used by link.exe
+LIBRARY ZIP64 ; Library module name
+DESCRIPTION 'Windows Info-ZIP Zip Library 1.02 by Info-ZIP, Mike White 1997'
+
+CODE PRELOAD FIXED
+
+DATA PRELOAD MOVEABLE
+
+EXPORTS
+ ZpArchive
+ ZpVersion
+ ZpInit
+ ZpSetOptions
+ ZpGetOptions
+
diff --git a/zbz2err.c b/zbz2err.c
new file mode 100644
index 0000000..0e4f9f1
--- /dev/null
+++ b/zbz2err.c
@@ -0,0 +1,61 @@
+/*
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ zbz2err.c
+
+ This file contains the "fatal error" callback routine required by the
+ "minimal" (silent, non-stdio) setup of the bzip2 compression library.
+
+ The fatal bzip2 error bail-out routine is provided in a separate code
+ module, so that it can be easily overridden when the Zip package is
+ used as a static link library. One example is the WinDLL static library
+ usage for building a monolithic binary of the Windows application "WiZ"
+ that supports bzip2 both in compression and decompression operations.
+
+ Contains: bz_internal_error() (BZIP2_SUPPORT only)
+
+ Adapted from UnZip ubz2err.c, with all the DLL fine print stripped
+ out.
+
+ ---------------------------------------------------------------------------*/
+
+
+#define __ZBZ2ERR_C /* identifies this source module */
+
+#include "zip.h"
+
+#ifdef BZIP2_SUPPORT
+# ifdef BZIP2_USEBZIP2DIR
+# include "bzip2/bzlib.h"
+# else
+ /* If IZ_BZIP2 is defined as the location of the bzip2 files then
+ assume the location has been added to include path. For Unix
+ this is done by the configure script. */
+ /* Also do not need path for bzip2 include if OS includes support
+ for bzip2 library. */
+# include "bzlib.h"
+# endif
+
+/**********************************/
+/* Function bz_internal_error() */
+/**********************************/
+
+/* Call-back function for the bzip2 decompression code (compiled with
+ * BZ_NO_STDIO), required to handle fatal internal bug-type errors of
+ * the bzip2 library.
+ */
+void bz_internal_error(errcode)
+ int errcode;
+{
+ sprintf(errbuf, "fatal error (code %d) in bzip2 library", errcode);
+ ziperr(ZE_LOGIC, errbuf);
+} /* end function bz_internal_error() */
+
+#endif /* def BZIP2_SUPPORT */
diff --git a/zip.c b/zip.c
new file mode 100644
index 0000000..439821f
--- /dev/null
+++ b/zip.c
@@ -0,0 +1,6018 @@
+/*
+ zip.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * zip.c by Mark Adler.
+ */
+#define __ZIP_C
+
+#include "zip.h"
+#include <time.h> /* for tzset() declaration */
+#if defined(WIN32) || defined(WINDLL)
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+#ifdef WINDLL
+# include <setjmp.h>
+# include "windll/windll.h"
+#endif
+#define DEFCPYRT /* main module: enable copyright string defines! */
+#include "revision.h"
+#include "crc32.h"
+#include "crypt.h"
+#include "ttyio.h"
+#include <ctype.h>
+#include <errno.h>
+#ifdef VMS
+# include <stsdef.h>
+# include "vms/vmsmunch.h"
+# include "vms/vms.h"
+#endif
+
+#ifdef MACOS
+# include "macglob.h"
+ extern MacZipGlobals MacZip;
+ extern int error_level;
+#endif
+
+#if (defined(MSDOS) && !defined(__GO32__)) || defined(__human68k__)
+# include <process.h>
+# if (!defined(P_WAIT) && defined(_P_WAIT))
+# define P_WAIT _P_WAIT
+# endif
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+
+#ifdef UNICODE_TEST
+# ifdef WIN32
+# include <direct.h>
+# endif
+#endif
+
+#ifdef BZIP2_SUPPORT
+ /* If IZ_BZIP2 is defined as the location of the bzip2 files then
+ assume the location has been added to include path. For Unix
+ this is done by the configure script. */
+ /* Also do not need path for bzip2 include if OS includes support
+ for bzip2 library. */
+# include "bzlib.h"
+#endif
+
+#define MAXCOM 256 /* Maximum one-line comment size */
+
+
+/* Local option flags */
+#ifndef DELETE
+#define DELETE 0
+#endif
+#define ADD 1
+#define UPDATE 2
+#define FRESHEN 3
+#define ARCHIVE 4
+local int action = ADD; /* one of ADD, UPDATE, FRESHEN, DELETE, or ARCHIVE */
+local int comadd = 0; /* 1=add comments for new files */
+local int zipedit = 0; /* 1=edit zip comment and all file comments */
+local int latest = 0; /* 1=set zip file time to time of latest file */
+local int test = 0; /* 1=test zip file with unzip -t */
+local char *unzip_path = NULL; /* where to find unzip */
+local int tempdir = 0; /* 1=use temp directory (-b) */
+local int junk_sfx = 0; /* 1=junk the sfx prefix */
+#if defined(AMIGA) || defined(MACOS)
+local int filenotes = 0; /* 1=take comments from AmigaDOS/MACOS filenotes */
+#endif
+
+#ifdef EBCDIC
+int aflag = __EBCDIC; /* Convert EBCDIC to ASCII or stay EBCDIC ? */
+#endif
+#ifdef CMS_MVS
+int bflag = 0; /* Use text mode as default */
+#endif
+
+#ifdef QDOS
+char _version[] = VERSION;
+#endif
+
+#ifdef WINDLL
+jmp_buf zipdll_error_return;
+#ifdef ZIP64_SUPPORT
+ unsigned long low, high; /* returning 64 bit values for systems without an _int64 */
+ uzoff_t filesize64;
+#endif
+#endif
+
+#if CRYPT
+/* Pointer to crc_table, needed in crypt.c */
+# if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+ZCONST ulg near *crc_32_tab;
+# else
+ZCONST uLongf *crc_32_tab;
+# endif
+#endif /* CRYPT */
+
+/* Local functions */
+
+local void freeup OF((void));
+local int finish OF((int));
+#if (!defined(MACOS) && !defined(WINDLL))
+local void handler OF((int));
+local void license OF((void));
+#ifndef VMSCLI
+local void help OF((void));
+local void help_extended OF((void));
+#endif /* !VMSCLI */
+#endif /* !MACOS && !WINDLL */
+
+/* prereading of arguments is not supported in new command
+ line interpreter get_option() so read filters as arguments
+ are processed and convert to expected array later */
+local int add_filter OF((int flag, char *pattern));
+local int filterlist_to_patterns OF((void));
+/* not used
+ local int get_filters OF((int argc, char **argv));
+*/
+
+/* list to store file arguments */
+local long add_name OF((char *filearg));
+
+
+local int DisplayRunningStats OF((void));
+local int BlankRunningStats OF((void));
+
+#if !defined(WINDLL)
+local void version_info OF((void));
+# if !defined(MACOS)
+local void zipstdout OF((void));
+# endif /* !MACOS */
+local int check_unzip_version OF((char *unzippath));
+local void check_zipfile OF((char *zipname, char *zippath));
+#endif /* !WINDLL */
+
+/* structure used by add_filter to store filters */
+struct filterlist_struct {
+ char flag;
+ char *pattern;
+ struct filterlist_struct *next;
+};
+struct filterlist_struct *filterlist = NULL; /* start of list */
+struct filterlist_struct *lastfilter = NULL; /* last filter in list */
+
+/* structure used by add_filearg to store file arguments */
+struct filelist_struct {
+ char *name;
+ struct filelist_struct *next;
+};
+long filearg_count = 0;
+struct filelist_struct *filelist = NULL; /* start of list */
+struct filelist_struct *lastfile = NULL; /* last file in list */
+
+local void freeup()
+/* Free all allocations in the 'found' list, the 'zfiles' list and
+ the 'patterns' list. */
+{
+ struct flist far *f; /* steps through found list */
+ struct zlist far *z; /* pointer to next entry in zfiles list */
+
+ for (f = found; f != NULL; f = fexpel(f))
+ ;
+ while (zfiles != NULL)
+ {
+ z = zfiles->nxt;
+ if (zfiles->zname && zfiles->zname != zfiles->name)
+ free((zvoid *)(zfiles->zname));
+ if (zfiles->name)
+ free((zvoid *)(zfiles->name));
+ if (zfiles->iname)
+ free((zvoid *)(zfiles->iname));
+ if (zfiles->cext && zfiles->cextra && zfiles->cextra != zfiles->extra)
+ free((zvoid *)(zfiles->cextra));
+ if (zfiles->ext && zfiles->extra)
+ free((zvoid *)(zfiles->extra));
+ if (zfiles->com && zfiles->comment)
+ free((zvoid *)(zfiles->comment));
+ if (zfiles->oname)
+ free((zvoid *)(zfiles->oname));
+#ifdef UNICODE_SUPPORT
+ if (zfiles->uname)
+ free((zvoid *)(zfiles->uname));
+ if (zfiles->zuname)
+ free((zvoid *)(zfiles->zuname));
+ if (zfiles->ouname)
+ free((zvoid *)(zfiles->ouname));
+# ifdef WIN32
+ if (zfiles->namew)
+ free((zvoid *)(zfiles->namew));
+ if (zfiles->inamew)
+ free((zvoid *)(zfiles->inamew));
+ if (zfiles->znamew)
+ free((zvoid *)(zfiles->znamew));
+# endif
+#endif
+ farfree((zvoid far *)zfiles);
+ zfiles = z;
+ zcount--;
+ }
+
+ if (patterns != NULL) {
+ while (pcount-- > 0) {
+ if (patterns[pcount].zname != NULL)
+ free((zvoid *)(patterns[pcount].zname));
+ }
+ free((zvoid *)patterns);
+ patterns = NULL;
+ }
+
+ /* close logfile */
+ if (logfile) {
+ fclose(logfile);
+ }
+}
+
+local int finish(e)
+int e; /* exit code */
+/* Process -o and -m options (if specified), free up malloc'ed stuff, and
+ exit with the code e. */
+{
+ int r; /* return value from trash() */
+ ulg t; /* latest time in zip file */
+ struct zlist far *z; /* pointer into zfile list */
+
+ /* If latest, set time to zip file to latest file in zip file */
+ if (latest && zipfile && strcmp(zipfile, "-"))
+ {
+ diag("changing time of zip file to time of latest file in it");
+ /* find latest time in zip file */
+ if (zfiles == NULL)
+ zipwarn("zip file is empty, can't make it as old as latest entry", "");
+ else {
+ t = 0;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ /* Ignore directories in time comparisons */
+#ifdef USE_EF_UT_TIME
+ if (z->iname[z->nam-1] != (char)0x2f) /* ascii '/' */
+ {
+ iztimes z_utim;
+ ulg z_tim;
+
+ z_tim = ((get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+ unix2dostime(&z_utim.mtime) : z->tim);
+ if (t < z_tim)
+ t = z_tim;
+ }
+#else /* !USE_EF_UT_TIME */
+ if (z->iname[z->nam-1] != (char)0x2f /* ascii '/' */
+ && t < z->tim)
+ t = z->tim;
+#endif /* ?USE_EF_UT_TIME */
+ /* set modified time of zip file to that time */
+ if (t != 0)
+ stamp(zipfile, t);
+ else
+ zipwarn(
+ "zip file has only directories, can't make it as old as latest entry",
+ "");
+ }
+ }
+ if (tempath != NULL)
+ {
+ free((zvoid *)tempath);
+ tempath = NULL;
+ }
+ if (zipfile != NULL)
+ {
+ free((zvoid *)zipfile);
+ zipfile = NULL;
+ }
+ if (in_file != NULL)
+ {
+ fclose(in_file);
+ in_file = NULL;
+ }
+ if (in_path != NULL)
+ {
+ free((zvoid *)in_path);
+ in_path = NULL;
+ }
+ if (out_path != NULL)
+ {
+ free((zvoid *)out_path);
+ out_path = NULL;
+ }
+ if (zcomment != NULL)
+ {
+ free((zvoid *)zcomment);
+ zcomment = NULL;
+ }
+
+
+ /* If dispose, delete all files in the zfiles list that are marked */
+ if (dispose)
+ {
+ diag("deleting files that were added to zip file");
+ if ((r = trash()) != ZE_OK)
+ ZIPERR(r, "was deleting moved files and directories");
+ }
+
+
+ /* Done! */
+ freeup();
+ return e;
+}
+
+void ziperr(c, h)
+int c; /* error code from the ZE_ class */
+ZCONST char *h; /* message about how it happened */
+/* Issue a message for the error, clean up files and memory, and exit. */
+{
+#ifndef WINDLL
+#ifndef MACOS
+ static int error_level = 0;
+#endif
+
+ if (error_level++ > 0)
+ /* avoid recursive ziperr() printouts (his should never happen) */
+ EXIT(ZE_LOGIC); /* ziperr recursion is an internal logic error! */
+#endif /* !WINDLL */
+
+ if (mesg_line_started) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ }
+ if (logfile && logfile_line_started) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ }
+ if (h != NULL) {
+ if (PERR(c))
+ fprintf(mesg, "zip I/O error: %s", strerror(errno));
+ /* perror("zip I/O error"); */
+ fflush(mesg);
+ fprintf(mesg, "\nzip error: %s (%s)\n", ZIPERRORS(c), h);
+#ifdef DOS
+ check_for_windows("Zip");
+#endif
+ if (logfile) {
+ if (PERR(c))
+ fprintf(logfile, "zip I/O error: %s\n", strerror(errno));
+ fprintf(logfile, "\nzip error: %s (%s)\n", ZIPERRORS(c), h);
+ logfile_line_started = 0;
+ }
+ }
+ if (tempzip != NULL)
+ {
+ if (tempzip != zipfile) {
+ if (current_local_file)
+ fclose(current_local_file);
+ if (y != current_local_file && y != NULL)
+ fclose(y);
+#ifndef DEBUG
+ destroy(tempzip);
+#endif
+ free((zvoid *)tempzip);
+ } else {
+ /* -g option, attempt to restore the old file */
+
+ /* zip64 support 09/05/2003 R.Nausedat */
+ uzoff_t k = 0; /* keep count for end header */
+ uzoff_t cb = cenbeg; /* get start of central */
+
+ struct zlist far *z; /* steps through zfiles linked list */
+
+ fprintf(mesg, "attempting to restore %s to its previous state\n",
+ zipfile);
+ if (logfile)
+ fprintf(logfile, "attempting to restore %s to its previous state\n",
+ zipfile);
+
+ zfseeko(y, cenbeg, SEEK_SET);
+
+ tempzn = cenbeg;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ {
+ putcentral(z);
+ tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
+ k++;
+ }
+ putend(k, tempzn - cb, cb, zcomlen, zcomment);
+ fclose(y);
+ y = NULL;
+ }
+ }
+
+ if (key != NULL) {
+ free((zvoid *)key);
+ key = NULL;
+ }
+ if (tempath != NULL) {
+ free((zvoid *)tempath);
+ tempath = NULL;
+ }
+ if (zipfile != NULL) {
+ free((zvoid *)zipfile);
+ zipfile = NULL;
+ }
+ if (out_path != NULL) {
+ free((zvoid *)out_path);
+ out_path = NULL;
+ }
+ if (zcomment != NULL) {
+ free((zvoid *)zcomment);
+ zcomment = NULL;
+ }
+
+ freeup();
+#ifndef WINDLL
+ EXIT(c);
+#else
+ longjmp(zipdll_error_return, c);
+#endif
+}
+
+
+void error(h)
+ ZCONST char *h;
+/* Internal error, should never happen */
+{
+ ziperr(ZE_LOGIC, h);
+}
+
+#if (!defined(MACOS) && !defined(WINDLL))
+local void handler(s)
+int s; /* signal number (ignored) */
+/* Upon getting a user interrupt, turn echo back on for tty and abort
+ cleanly using ziperr(). */
+{
+#if defined(AMIGA) && defined(__SASC)
+ _abort();
+#else
+#if !defined(MSDOS) && !defined(__human68k__) && !defined(RISCOS)
+ echon();
+ putc('\n', mesg);
+#endif /* !MSDOS */
+#endif /* AMIGA && __SASC */
+ ziperr(ZE_ABORT, "aborting");
+ s++; /* keep some compilers happy */
+}
+#endif /* !MACOS && !WINDLL */
+
+void zipmessage_nl(a, nl)
+ZCONST char *a; /* message string to output */
+int nl; /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+ If nl true, print and add new line. If logfile is
+ open then also write message to log file. */
+{
+ if (noisy) {
+ if (a && strlen(a)) {
+ fprintf(mesg, "%s", a);
+ mesg_line_started = 1;
+ }
+ if (nl) {
+ if (mesg_line_started) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ }
+ } else if (a && strlen(a)) {
+ mesg_line_started = 1;
+ }
+ fflush(mesg);
+ }
+ if (logfile) {
+ if (a && strlen(a)) {
+ fprintf(logfile, "%s", a);
+ logfile_line_started = 1;
+ }
+ if (nl) {
+ if (logfile_line_started) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ }
+ } else if (a && strlen(a)) {
+ logfile_line_started = 1;
+ }
+ fflush(logfile);
+ }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b; /* message strings juxtaposed in output */
+/* Print a message to mesg and flush. Also write to log file if
+ open. Write new line first if current line has output already. */
+{
+ if (noisy) {
+ if (mesg_line_started)
+ fprintf(mesg, "\n");
+ fprintf(mesg, "%s%s\n", a, b);
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+ if (logfile) {
+ if (logfile_line_started)
+ fprintf(logfile, "\n");
+ fprintf(logfile, "%s%s\n", a, b);
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+}
+
+void zipwarn(a, b)
+ZCONST char *a, *b; /* message strings juxtaposed in output */
+/* Print a warning message to mesg (usually stderr) and return. */
+{
+ if (noisy) {
+ if (mesg_line_started)
+ fprintf(mesg, "\n");
+ fprintf(mesg, "\tzip warning: %s%s\n", a, b);
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+ if (logfile) {
+ if (logfile_line_started)
+ fprintf(logfile, "\n");
+ fprintf(logfile, "\tzip warning: %s%s\n", a, b);
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+}
+
+#ifndef WINDLL
+local void license()
+/* Print license information to stdout. */
+{
+ extent i; /* counter for copyright array */
+
+ for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
+ puts(swlicense[i]);
+}
+
+#ifdef VMSCLI
+void help()
+#else
+local void help()
+#endif
+/* Print help (along with license info) to stdout. */
+{
+ extent i; /* counter for help array */
+
+ /* help array */
+ static ZCONST char *text[] = {
+#ifdef VMS
+"Zip %s (%s). Usage: zip == \"$ disk:[dir]zip.exe\"",
+#else
+"Zip %s (%s). Usage:",
+#endif
+#ifdef MACOS
+"zip [-options] [-b fm] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
+" The default action is to add or replace zipfile entries from list.",
+" ",
+" -f freshen: only changed files -u update: only changed or new files",
+" -d delete entries in zipfile -m move into zipfile (delete OS files)",
+" -r recurse into directories -j junk (don't record) directory names",
+" -0 store only -l convert LF to CR LF (-ll CR LF to LF)",
+" -1 compress faster -9 compress better",
+" -q quiet operation -v verbose operation/print version info",
+" -c add one-line comments -z add zipfile comment",
+" -o make zipfile as old as latest entry",
+" -F fix zipfile (-FF try harder) -D do not add directory entries",
+" -T test zipfile integrity -X eXclude eXtra file attributes",
+# if CRYPT
+" -e encrypt -n don't compress these suffixes"
+# else
+" -h show this help -n don't compress these suffixes"
+# endif
+," -h2 show more help",
+" Macintosh specific:",
+" -jj record Fullpath (+ Volname) -N store finder-comments as comments",
+" -df zip only datafork of a file -S include finder invisible/system files"
+#else /* !MACOS */
+#ifdef VM_CMS
+"zip [-options] [-b fm] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
+#else /* !VM_CMS */
+"zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]",
+#endif /* ?VM_CMS */
+" The default action is to add or replace zipfile entries from list, which",
+" can include the special name - to compress standard input.",
+" If zipfile and list are omitted, zip compresses stdin to stdout.",
+" -f freshen: only changed files -u update: only changed or new files",
+" -d delete entries in zipfile -m move into zipfile (delete OS files)",
+" -r recurse into directories -j junk (don't record) directory names",
+#ifdef THEOS
+" -0 store only -l convert CR to CR LF (-ll CR LF to CR)",
+#else
+" -0 store only -l convert LF to CR LF (-ll CR LF to LF)",
+#endif
+" -1 compress faster -9 compress better",
+" -q quiet operation -v verbose operation/print version info",
+" -c add one-line comments -z add zipfile comment",
+" -@ read names from stdin -o make zipfile as old as latest entry",
+" -x exclude the following names -i include only the following names",
+#ifdef EBCDIC
+#ifdef CMS_MVS
+" -a translate to ASCII -B force binary read (text is default)",
+#else /* !CMS_MVS */
+" -a translate to ASCII",
+#endif /* ?CMS_MVS */
+#endif /* EBCDIC */
+#ifdef TANDEM
+" -Bn set Enscribe formatting options",
+#endif
+" -F fix zipfile (-FF try harder) -D do not add directory entries",
+" -A adjust self-extracting exe -J junk zipfile prefix (unzipsfx)",
+" -T test zipfile integrity -X eXclude eXtra file attributes",
+#ifdef VMS
+" -C preserve case of file names -C- down-case all file names",
+" -C2 preserve case of ODS2 names -C2- down-case ODS2 file names* (*=default)",
+" -C5 preserve case of ODS5 names* -C5- down-case ODS5 file names",
+" -V save VMS file attributes (-VV also save allocated blocks past EOF)",
+" -w store file version numbers\
+ -ww store file version numbers as \".nnn\"",
+#endif /* def VMS */
+#ifdef NTSD_EAS
+" -! use privileges (if granted) to obtain all aspects of WinNT security",
+#endif /* NTSD_EAS */
+#ifdef OS2
+" -E use the .LONGNAME Extended attribute (if found) as filename",
+#endif /* OS2 */
+#ifdef S_IFLNK
+" -y store symbolic links as the link instead of the referenced file",
+#endif /* !S_IFLNK */
+/*
+" -R PKZIP recursion (see manual)",
+*/
+#if defined(MSDOS) || defined(OS2)
+" -$ include volume label -S include system and hidden files",
+#endif
+#ifdef AMIGA
+# if CRYPT
+" -N store filenotes as comments -e encrypt",
+" -h show this help -n don't compress these suffixes"
+# else
+" -N store filenotes as comments -n don't compress these suffixes"
+# endif
+#else /* !AMIGA */
+# if CRYPT
+" -e encrypt -n don't compress these suffixes"
+# else
+" -h show this help -n don't compress these suffixes"
+# endif
+#endif /* ?AMIGA */
+#ifdef RISCOS
+," -h2 show more help -I don't scan thru Image files"
+#else
+," -h2 show more help"
+#endif
+#endif /* ?MACOS */
+#ifdef VMS
+," (Must quote upper-case options, like \"-V\", unless SET PROC/PARSE=EXTEND)"
+#endif /* def VMS */
+," "
+ };
+
+ for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+ {
+ printf(copyright[i], "zip");
+ putchar('\n');
+ }
+ for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+ {
+ printf(text[i], VERSION, REVDATE);
+ putchar('\n');
+ }
+}
+
+#ifdef VMSCLI
+void help_extended()
+#else
+local void help_extended()
+#endif
+/* Print extended help to stdout. */
+{
+ extent i; /* counter for help array */
+
+ /* help array */
+ static ZCONST char *text[] = {
+"",
+"Extended Help for Zip",
+"",
+"See the Zip Manual for more detailed help",
+"",
+"",
+"Zip stores files in zip archives. The default action is to add or replace",
+"zipfile entries.",
+"",
+"Basic command line:",
+" zip options archive_name file file ...",
+"",
+"Some examples:",
+" Add file.txt to z.zip (create z if needed): zip z file.txt",
+" Zip all files in current dir: zip z *",
+" Zip files in current dir and subdirs also: zip -r z .",
+"",
+"Basic modes:",
+" External modes (selects files from file system):",
+" add - add new files/update existing files in archive (default)",
+" -u update - add new files/update existing files only if later date",
+" -f freshen - update existing files only (no files added)",
+" -FS filesync - update if date or size changed, delete if no OS match",
+" Internal modes (selects entries in archive):",
+" -d delete - delete files from archive (see below)",
+" -U copy - select files in archive to copy (use with --out)",
+"",
+"Basic options:",
+" -r recurse into directories (see Recursion below)",
+" -m after archive created, delete original files (move into archive)",
+" -j junk directory names (store just file names)",
+" -q quiet operation",
+" -v verbose operation (just \"zip -v\" shows version information)",
+" -c prompt for one-line comment for each entry",
+" -z prompt for comment for archive (end with just \".\" line or EOF)",
+" -@ read names to zip from stdin (one path per line)",
+" -o make zipfile as old as latest entry",
+"",
+"",
+"Syntax:",
+" The full command line syntax is:",
+"",
+" zip [-shortopts ...] [--longopt ...] [zipfile [path path ...]] [-xi list]",
+"",
+" Any number of short option and long option arguments are allowed",
+" (within limits) as well as any number of path arguments for files",
+" to zip up. If zipfile exists, the archive is read in. If zipfile",
+" is \"-\", stream to stdout. If any path is \"-\", zip stdin.",
+"",
+"Options and Values:",
+" For short options that take values, use -ovalue or -o value or -o=value",
+" For long option values, use either --longoption=value or --longoption value",
+" For example:",
+" zip -ds 10 --temp-dir=path zipfile path1 path2 --exclude pattern pattern",
+" Avoid -ovalue (no space between) to avoid confusion",
+" In particular, be aware of 2-character options. For example:",
+" -d -s is (delete, split size) while -ds is (dot size)",
+" Usually better to break short options across multiple arguments by function",
+" zip -r -dbdcds 10m -lilalf logfile archive input_directory -ll",
+"",
+" All args after just \"--\" arg are read verbatim as paths and not options.",
+" zip zipfile path path ... -- verbatimpath verbatimpath ...",
+" Use -nw to also disable wildcards, so paths are read literally:",
+" zip zipfile -nw -- \"-leadingdashpath\" \"a[path].c\" \"path*withwildcard\"",
+" You may still have to escape or quote arguments to avoid shell expansion",
+"",
+"Wildcards:",
+" Internally zip supports the following wildcards:",
+" ? (or %% or #, depending on OS) matches any single character",
+" * matches any number of characters, including zero",
+" [list] matches char in list (regex), can do range [ac-f], all but [!bf]",
+" If port supports [], must escape [ as [[] or use -nw to turn off wildcards",
+" For shells that expand wildcards, escape (\\* or \"*\") so zip can recurse",
+" zip zipfile -r . -i \"*.h\"",
+"",
+" Normally * crosses dir bounds in path, e.g. 'a*b' can match 'ac/db'. If",
+" -ws option used, * does not cross dir bounds but ** does",
+"",
+" For DOS and Windows, [list] is now disabled unless the new option",
+" -RE enable [list] (regular expression) matching",
+" is used to avoid problems with file paths containing \"[\" and \"]\":",
+" zip files_ending_with_number -RE foo[0-9].c",
+"",
+"Include and Exclude:",
+" -i pattern pattern ... include files that match a pattern",
+" -x pattern pattern ... exclude files that match a pattern",
+" Patterns are paths with optional wildcards and match paths as stored in",
+" archive. Exclude and include lists end at next option, @, or end of line.",
+" zip -x pattern pattern @ zipfile path path ...",
+"",
+"Case matching:",
+" On most OS the case of patterns must match the case in the archive, unless",
+" the -ic option is used.",
+" -ic ignore case of archive entries",
+" This option not available on case-sensitive file systems. On others, case",
+" ignored when matching files on file system but matching against archive",
+" entries remains case sensitive for modes -f (freshen), -U (archive copy),",
+" and -d (delete) because archive paths are always case sensitive. With",
+" -ic, all matching ignores case, but it's then possible multiple archive",
+" entries that differ only in case will match.",
+"",
+"End Of Line Translation (text files only):",
+" -l change CR or LF (depending on OS) line end to CR LF (Unix->Win)",
+" -ll change CR LF to CR or LF (depending on OS) line end (Win->Unix)",
+" If first buffer read from file contains binary the translation is skipped",
+"",
+"Recursion:",
+" -r recurse paths, include files in subdirs: zip -r a path path ...",
+" -R recurse current dir and match patterns: zip -R a ptn ptn ...",
+" Use -i and -x with either to include or exclude paths",
+" Path root in archive starts at current dir, so if /a/b/c/file and",
+" current dir is /a/b, 'zip -r archive .' puts c/file in archive",
+"",
+"Date filtering:",
+" -t date exclude before (include files modified on this date and later)",
+" -tt date include before (include files modified before date)",
+" Can use both at same time to set a date range",
+" Dates are mmddyyyy or yyyy-mm-dd",
+"",
+"Deletion, File Sync:",
+" -d delete files",
+" Delete archive entries matching internal archive paths in list",
+" zip archive -d pattern pattern ...",
+" Can use -t and -tt to select files in archive, but NOT -x or -i, so",
+" zip archive -d \"*\" -t 2005-12-27",
+" deletes all files from archive.zip with date of 27 Dec 2005 and later",
+" Note the * (escape as \"*\" on Unix) to select all files in archive",
+"",
+" -FS file sync",
+" Similar to update, but files updated if date or size of entry does not",
+" match file on OS. Also deletes entry from archive if no matching file",
+" on OS.",
+" zip archive_to_update -FS -r dir_used_before",
+" Result generally same as creating new archive, but unchanged entries",
+" are copied instead of being read and compressed so can be faster.",
+" WARNING: -FS deletes entries so make backup copy of archive first",
+"",
+"Compression:",
+" -0 store files (no compression)",
+" -1 to -9 compress fastest to compress best (default is 6)",
+" -Z cm set compression method to cm:",
+" store - store without compression, same as option -0",
+" deflate - original zip deflate, same as -1 to -9 (default)",
+" if bzip2 is enabled:",
+" bzip2 - use bzip2 compression (need modern unzip)",
+"",
+"Encryption:",
+" -e use standard (weak) PKZip 2.0 encryption, prompt for password",
+" -P pswd use standard encryption, password is pswd",
+"",
+"Splits (archives created as a set of split files):",
+" -s ssize create split archive with splits of size ssize, where ssize nm",
+" n number and m multiplier (kmgt, default m), 100k -> 100 kB",
+" -sp pause after each split closed to allow changing disks",
+" WARNING: Archives created with -sp use data descriptors and should",
+" work with most unzips but may not work with some",
+" -sb ring bell when pause",
+" -sv be verbose about creating splits",
+" Split archives CANNOT be updated, but see --out and Copy Mode below",
+"",
+"Using --out (output to new archive):",
+" --out oa output to new archive oa",
+" Instead of updating input archive, create new output archive oa.",
+" Result is same as without --out but in new archive. Input archive",
+" unchanged.",
+" WARNING: --out ALWAYS overwrites any existing output file",
+" For example, to create new_archive like old_archive but add newfile1",
+" and newfile2:",
+" zip old_archive newfile1 newfile2 --out new_archive",
+" Cannot update split archive, so use --out to out new archive:",
+" zip in_split_archive newfile1 newfile2 --out out_split_archive",
+" If input is split, output will default to same split size",
+" Use -s=0 or -s- to turn off splitting to convert split to single file:",
+" zip in_split_archive -s 0 --out out_single_file_archive",
+" WARNING: If overwriting old split archive but need less splits,",
+" old splits not overwritten are not needed but remain",
+"",
+"Copy Mode (copying from archive to archive):",
+" -U (also --copy) select entries in archive to copy (reverse delete)",
+" Copy Mode copies entries from old to new archive with --out and is used by",
+" zip when either no input files on command line or -U (--copy) used.",
+" zip inarchive --copy pattern pattern ... --out outarchive",
+" To copy only files matching *.c into new archive, excluding foo.c:",
+" zip old_archive --copy \"*.c\" --out new_archive -x foo.c",
+" If no input files and --out, copy all entries in old archive:",
+" zip old_archive --out new_archive",
+"",
+"Streaming and FIFOs:",
+" prog1 | zip -ll z - zip output of prog1 to zipfile z, converting CR LF",
+" zip - -R \"*.c\" | prog2 zip *.c files in current dir and stream to prog2 ",
+" prog1 | zip | prog2 zip in pipe with no in or out acts like zip - -",
+" If Zip is Zip64 enabled, streaming stdin creates Zip64 archives by default",
+" that need PKZip 4.5 unzipper like UnZip 6.0",
+" WARNING: Some archives created with streaming use data descriptors and",
+" should work with most unzips but may not work with some",
+" Can use -fz- to turn off Zip64 if input not large (< 4 GB):",
+" prog_with_small_output | zip archive -fz-",
+"",
+" Zip now can read Unix FIFO (named pipes). Off by default to prevent zip",
+" from stopping unexpectedly on unfed pipe, use -FI to enable:",
+" zip -FI archive fifo",
+"",
+"Dots, counts:",
+" -db display running count of bytes processed and bytes to go",
+" (uncompressed size, except delete and copy show stored size)",
+" -dc display running count of entries done and entries to go",
+" -dd display dots every 10 MB (or dot size) while processing files",
+" -dg display dots globally for archive instead of for each file",
+" zip -qdgds 10m will turn off most output except dots every 10 MB",
+" -ds siz each dot is siz processed where siz is nm as splits (0 no dots)",
+" -du display original uncompressed size for each entry as added",
+" -dv display volume (disk) number in format in_disk>out_disk",
+" Dot size is approximate, especially for dot sizes less than 1 MB",
+" Dot options don't apply to Scanning files dots (dot/2sec) (-q turns off)",
+"",
+"Logging:",
+" -lf path open file at path as logfile (overwrite existing file)",
+" -la append to existing logfile",
+" -li include info messages (default just warnings and errors)",
+"",
+"Testing archives:",
+" -T test completed temp archive with unzip before updating archive",
+" -TT cmd use command cmd instead of 'unzip -tqq' to test archive",
+" On Unix, to use unzip in current directory, could use:",
+" zip archive file1 file2 -T -TT \"./unzip -tqq\"",
+" In cmd, {} replaced by temp archive path, else temp appended.",
+" The return code is checked for success (0 on Unix)",
+"",
+"Fixing archives:",
+" -F attempt to fix a mostly intact archive (try this first)",
+" -FF try to salvage what can (may get more but less reliable)",
+" Fix options copy entries from potentially bad archive to new archive.",
+" -F tries to read archive normally and copy only intact entries, while",
+" -FF tries to salvage what can and may result in incomplete entries.",
+" Must use --out option to specify output archive:",
+" zip -F bad.zip --out fixed.zip",
+" Use -v (verbose) with -FF to see details:",
+" zip reallybad.zip -FF -v --out fixed.zip",
+" Currently neither option fixes bad entries, as from text mode ftp get.",
+"",
+"Difference mode:",
+" -DF (also --dif) only include files that have changed or are",
+" new as compared to the input archive",
+" Difference mode can be used to create incremental backups. For example:",
+" zip --dif full_backup.zip -r somedir --out diff.zip",
+" will store all new files, as well as any files in full_backup.zip where",
+" either file time or size have changed from that in full_backup.zip,",
+" in new diff.zip. Output archive not excluded automatically if exists,",
+" so either use -x to exclude it or put outside what is being zipped.",
+"",
+"DOS Archive bit (Windows only):",
+" -AS include only files with the DOS Archive bit set",
+" -AC after archive created, clear archive bit of included files",
+" WARNING: Once the archive bits are cleared they are cleared",
+" Use -T to test the archive before the bits are cleared",
+" Can also use -sf to save file list before zipping files",
+"",
+"Show files:",
+" -sf show files to operate on and exit (-sf- logfile only)",
+" -su as -sf but show escaped UTF-8 Unicode names also if exist",
+" -sU as -sf but show escaped UTF-8 Unicode names instead",
+" Any character not in the current locale is escaped as #Uxxxx, where x",
+" is hex digit, if 16-bit code is sufficient, or #Lxxxxxx if 24-bits",
+" are needed. If add -UN=e, Zip escapes all non-ASCII characters.",
+"",
+"Unicode:",
+" If compiled with Unicode support, Zip stores UTF-8 path of entries.",
+" This is backward compatible. Unicode paths allow better conversion",
+" of entry names between different character sets.",
+"",
+" New Unicode extra field includes checksum to verify Unicode path",
+" goes with standard path for that entry (as utilities like ZipNote",
+" can rename entries). If these do not match, use below options to",
+" set what Zip does:",
+" -UN=Quit - if mismatch, exit with error",
+" -UN=Warn - if mismatch, warn, ignore UTF-8 (default)",
+" -UN=Ignore - if mismatch, quietly ignore UTF-8",
+" -UN=No - ignore any UTF-8 paths, use standard paths for all",
+" An exception to -UN=N are entries with new UTF-8 bit set (instead",
+" of using extra fields). These are always handled as Unicode.",
+"",
+" Normally Zip escapes all chars outside current char set, but leaves",
+" as is supported chars, which may not be OK in path names. -UN=Escape",
+" escapes any character not ASCII:",
+" zip -sU -UN=e archive",
+" Can use either normal path or escaped Unicode path on command line",
+" to match files in archive.",
+"",
+" Zip now stores UTF-8 in entry path and comment fields on systems",
+" where UTF-8 char set is default, such as most modern Unix, and",
+" and on other systems in new extra fields with escaped versions in",
+" entry path and comment fields for backward compatibility.",
+" Option -UN=UTF8 will force storing UTF-8 in entry path and comment",
+" fields:",
+" -UN=UTF8 - store UTF-8 in entry path and comment fields",
+" This option can be useful for multi-byte char sets on Windows where",
+" escaped paths and comments can be too long to be valid as the UTF-8",
+" versions tend to be shorter.",
+"",
+" Only UTF-8 comments on UTF-8 native systems supported. UTF-8 comments",
+" for other systems planned in next release.",
+"",
+"Self extractor:",
+" -A Adjust offsets - a self extractor is created by prepending",
+" the extractor executable to archive, but internal offsets",
+" are then off. Use -A to fix offsets.",
+" -J Junk sfx - removes prepended extractor executable from",
+" self extractor, leaving a plain zip archive.",
+"",
+"More option highlights (see manual for additional options and details):",
+" -b dir when creating or updating archive, create the temp archive in",
+" dir, which allows using seekable temp file when writing to a",
+" write once CD, such archives compatible with more unzips",
+" (could require additional file copy if on another device)",
+" -MM input patterns must match at least one file and matched files",
+" must be readable or exit with OPEN error and abort archive",
+" (without -MM, both are warnings only, and if unreadable files",
+" are skipped OPEN error (18) returned after archive created)",
+" -nw no wildcards (wildcards are like any other character)",
+" -sc show command line arguments as processed and exit",
+" -sd show debugging as Zip does each step",
+" -so show all available options on this system",
+" -X default=strip old extra fields, -X- keep old, -X strip most",
+" -ws wildcards don't span directory boundaries in paths",
+""
+ };
+
+ for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+ {
+ printf(text[i]);
+ putchar('\n');
+ }
+#ifdef DOS
+ check_for_windows("Zip");
+#endif
+}
+
+/*
+ * XXX version_info() in a separate file
+ */
+local void version_info()
+/* Print verbose info about program version and compile time options
+ to stdout. */
+{
+ extent i; /* counter in text arrays */
+ char *envptr;
+
+ /* Bzip2 option string storage (with version). */
+
+#ifdef BZIP2_SUPPORT
+ static char bz_opt_ver[81];
+ static char bz_opt_ver2[81];
+ static char bz_opt_ver3[81];
+#endif
+
+ /* Options info array */
+ static ZCONST char *comp_opts[] = {
+#ifdef ASM_CRC
+ "ASM_CRC",
+#endif
+#ifdef ASMV
+ "ASMV",
+#endif
+#ifdef DYN_ALLOC
+ "DYN_ALLOC",
+#endif
+#ifdef MMAP
+ "MMAP",
+#endif
+#ifdef BIG_MEM
+ "BIG_MEM",
+#endif
+#ifdef MEDIUM_MEM
+ "MEDIUM_MEM",
+#endif
+#ifdef SMALL_MEM
+ "SMALL_MEM",
+#endif
+#ifdef DEBUG
+ "DEBUG",
+#endif
+#ifdef USE_EF_UT_TIME
+ "USE_EF_UT_TIME (store Universal Time)",
+#endif
+#ifdef NTSD_EAS
+ "NTSD_EAS (store NT Security Descriptor)",
+#endif
+#if defined(WIN32) && defined(NO_W32TIMES_IZFIX)
+ "NO_W32TIMES_IZFIX",
+#endif
+#ifdef VMS
+#ifdef VMSCLI
+ "VMSCLI",
+#endif
+#ifdef VMS_IM_EXTRA
+ "VMS_IM_EXTRA",
+#endif
+#ifdef VMS_PK_EXTRA
+ "VMS_PK_EXTRA",
+#endif
+#endif /* VMS */
+#ifdef WILD_STOP_AT_DIR
+ "WILD_STOP_AT_DIR (wildcards do not cross directory boundaries)",
+#endif
+#ifdef WIN32_OEM
+ "WIN32_OEM (store file paths on Windows as OEM)",
+#endif
+#ifdef BZIP2_SUPPORT
+ bz_opt_ver,
+ bz_opt_ver2,
+ bz_opt_ver3,
+#endif
+#ifdef S_IFLNK
+# ifdef VMS
+ "SYMLINK_SUPPORT (symbolic links supported, if C RTL permits)",
+# else
+ "SYMLINK_SUPPORT (symbolic links supported)",
+# endif
+#endif
+#ifdef LARGE_FILE_SUPPORT
+# ifdef USING_DEFAULT_LARGE_FILE_SUPPORT
+ "LARGE_FILE_SUPPORT (default settings)",
+# else
+ "LARGE_FILE_SUPPORT (can read and write large files on file system)",
+# endif
+#endif
+#ifdef ZIP64_SUPPORT
+ "ZIP64_SUPPORT (use Zip64 to store large files in archives)",
+#endif
+#ifdef UNICODE_SUPPORT
+ "UNICODE_SUPPORT (store and read UTF-8 Unicode paths)",
+#endif
+
+#ifdef UNIX
+ "STORE_UNIX_UIDs_GIDs (store UID/GID sizes/values using new extra field)",
+# ifdef UIDGID_NOT_16BIT
+ "UIDGID_NOT_16BIT (old Unix 16-bit UID/GID extra field not used)",
+# else
+ "UIDGID_16BIT (old Unix 16-bit UID/GID extra field also used)",
+# endif
+#endif
+
+#if CRYPT && defined(PASSWD_FROM_STDIN)
+ "PASSWD_FROM_STDIN",
+#endif /* CRYPT & PASSWD_FROM_STDIN */
+ NULL
+ };
+
+ static ZCONST char *zipenv_names[] = {
+#ifndef VMS
+# ifndef RISCOS
+ "ZIP"
+# else /* RISCOS */
+ "Zip$Options"
+# endif /* ?RISCOS */
+#else /* VMS */
+ "ZIP_OPTS"
+#endif /* ?VMS */
+ ,"ZIPOPT"
+#ifdef AZTEC_C
+ , /* extremely lame compiler bug workaround */
+#endif
+#ifndef __RSXNT__
+# ifdef __EMX__
+ ,"EMX"
+ ,"EMXOPT"
+# endif
+# if (defined(__GO32__) && (!defined(__DJGPP__) || __DJGPP__ < 2))
+ ,"GO32"
+ ,"GO32TMP"
+# endif
+# if (defined(__DJGPP__) && __DJGPP__ >= 2)
+ ,"TMPDIR"
+# endif
+#endif /* !__RSXNT__ */
+#ifdef RISCOS
+ ,"Zip$Exts"
+#endif
+ };
+
+ for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+ {
+ printf(copyright[i], "zip");
+ putchar('\n');
+ }
+
+ for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+ {
+ printf(versinfolines[i], "Zip", VERSION, REVDATE);
+ putchar('\n');
+ }
+
+ version_local();
+
+ puts("Zip special compilation options:");
+#if WSIZE != 0x8000
+ printf("\tWSIZE=%u\n", WSIZE);
+#endif
+
+ /* Fill in bzip2 version. (32-char limit valid as of bzip 1.0.3.) */
+#ifdef BZIP2_SUPPORT
+ sprintf( bz_opt_ver,
+ "BZIP2_SUPPORT (bzip2 library version %.32s)", BZ2_bzlibVersion());
+ sprintf( bz_opt_ver2,
+ " bzip2 code and library copyright (c) Julian R Seward");
+ sprintf( bz_opt_ver3,
+ " (See the bzip2 license for terms of use)");
+#endif
+
+ for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+ {
+ printf("\t%s\n",comp_opts[i]);
+ }
+#ifdef USE_ZLIB
+ if (strcmp(ZLIB_VERSION, zlibVersion()) == 0)
+ printf("\tUSE_ZLIB [zlib version %s]\n", ZLIB_VERSION);
+ else
+ printf("\tUSE_ZLIB [compiled with version %s, using version %s]\n",
+ ZLIB_VERSION, zlibVersion());
+ i++; /* zlib use means there IS at least one compilation option */
+#endif
+#if CRYPT
+ printf("\t[encryption, version %d.%d%s of %s] (modified for Zip 3)\n\n",
+ CR_MAJORVER, CR_MINORVER, CR_BETA_VER, CR_VERSION_DATE);
+ for (i = 0; i < sizeof(cryptnote)/sizeof(char *); i++)
+ {
+ printf(cryptnote[i]);
+ putchar('\n');
+ }
+ ++i; /* crypt support means there IS at least one compilation option */
+#endif /* CRYPT */
+ if (i == 0)
+ puts("\t[none]");
+
+ puts("\nZip environment options:");
+ for (i = 0; i < sizeof(zipenv_names)/sizeof(char *); i++)
+ {
+ envptr = getenv(zipenv_names[i]);
+ printf("%16s: %s\n", zipenv_names[i],
+ ((envptr == (char *)NULL || *envptr == 0) ? "[none]" : envptr));
+ }
+#ifdef DOS
+ check_for_windows("Zip");
+#endif
+}
+#endif /* !WINDLL */
+
+
+#ifndef PROCNAME
+/* Default to case-sensitive matching of archive entries for the modes
+ that specifically operate on archive entries, as this archive may
+ have come from a system that allows paths in the archive to differ
+ only by case. Except for adding ARCHIVE (copy mode), this is how it
+ was done before. Note that some case-insensitive ports (WIN32, VMS)
+ define their own PROCNAME() in their respective osdep.h that use the
+ filter_match_case flag set to FALSE by the -ic option to enable
+ case-insensitive archive entry mathing. */
+# define PROCNAME(n) procname(n, (action == ARCHIVE || action == DELETE \
+ || action == FRESHEN) \
+ && filter_match_case)
+#endif /* PROCNAME */
+
+#ifndef WINDLL
+#ifndef MACOS
+local void zipstdout()
+/* setup for writing zip file on stdout */
+{
+ mesg = stderr;
+ if (isatty(1))
+ ziperr(ZE_PARMS, "cannot write zip file to terminal");
+ if ((zipfile = malloc(4)) == NULL)
+ ziperr(ZE_MEM, "was processing arguments");
+ strcpy(zipfile, "-");
+ /*
+ if ((r = readzipfile()) != ZE_OK)
+ ziperr(r, zipfile);
+ */
+}
+#endif /* !MACOS */
+
+local int check_unzip_version(unzippath)
+ char *unzippath;
+{
+#ifdef ZIP64_SUPPORT
+ /* Here is where we need to check for the version of unzip the user
+ * has. If creating a Zip64 archive need UnZip 6 or may fail.
+ */
+ char cmd[4004];
+ FILE *unzip_out = NULL;
+ char buf[1001];
+ float UnZip_Version = 0.0;
+
+ cmd[0] = '\0';
+ strncat(cmd, unzippath, 4000);
+ strcat(cmd, " -v");
+
+ if ((unzip_out = popen(cmd, "r")) == NULL) {
+ perror("unzip pipe error");
+ } else {
+ if (fgets(buf, 1000, unzip_out) == NULL) {
+ zipwarn("failed to get information from UnZip", "");
+ } else {
+ /* the first line should start with the version */
+ if (sscanf(buf, "UnZip %f ", &UnZip_Version) < 1) {
+ zipwarn("unexpected output of UnZip -v", "");
+ } else {
+ /* printf("UnZip %f\n", UnZip_Version); */
+
+ while (fgets(buf, 1000, unzip_out)) {
+ }
+ }
+ }
+ pclose(unzip_out);
+ }
+ if (UnZip_Version < 6.0 && zip64_archive) {
+ sprintf(buf, "Found UnZip version %4.2f", UnZip_Version);
+ zipwarn(buf, "");
+ zipwarn("Need UnZip 6.00 or later to test this Zip64 archive", "");
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+local void check_zipfile(zipname, zippath)
+ char *zipname;
+ char *zippath;
+ /* Invoke unzip -t on the given zip file */
+{
+#if (defined(MSDOS) && !defined(__GO32__)) || defined(__human68k__)
+ int status, len;
+ char *path, *p;
+ char *zipnam;
+
+ if ((zipnam = (char *)malloc(strlen(zipname) + 3)) == NULL)
+ ziperr(ZE_MEM, "was creating unzip zipnam");
+
+# ifdef MSDOS
+ /* Add quotes for MSDOS. 8/11/04 */
+ strcpy(zipnam, "\""); /* accept spaces in name and path */
+ strcat(zipnam, zipname);
+ strcat(zipnam, "\"");
+# else
+ strcpy(zipnam, zipname);
+# endif
+
+ if (unzip_path) {
+ /* if user gave us the unzip to use go with it */
+ char *here;
+ int len;
+ char *cmd;
+
+ /* Replace first {} with archive name. If no {} append name to string. */
+ here = strstr(unzip_path, "{}");
+
+ if ((cmd = (char *)malloc(strlen(unzip_path) + strlen(zipnam) + 3)) == NULL)
+ ziperr(ZE_MEM, "was creating unzip cmd");
+
+ if (here) {
+ /* have {} so replace with temp name */
+ len = here - unzip_path;
+ strcpy(cmd, unzip_path);
+ cmd[len] = '\0';
+ strcat(cmd, " ");
+ strcat(cmd, zipnam);
+ strcat(cmd, " ");
+ strcat(cmd, here + 2);
+ } else {
+ /* No {} so append temp name to end */
+ strcpy(cmd, unzip_path);
+ strcat(cmd, " ");
+ strcat(cmd, zipnam);
+ }
+
+ status = system(cmd);
+
+ free(unzip_path);
+ unzip_path = NULL;
+ free(cmd);
+ } else {
+ /* Here is where we need to check for the version of unzip the user
+ * has. If creating a Zip64 archive need UnZip 6 or may fail.
+ */
+ if (check_unzip_version("unzip") == 0)
+ ZIPERR(ZE_TEST, zipfile);
+
+ status = spawnlp(P_WAIT, "unzip", "unzip", verbose ? "-t" : "-tqq",
+ zipnam, NULL);
+# ifdef __human68k__
+ if (status == -1)
+ perror("unzip");
+# else
+/*
+ * unzip isn't in PATH range, assume an absolute path to zip in argv[0]
+ * and hope that unzip is in the same directory.
+ */
+ if (status == -1) {
+ p = MBSRCHR(zippath, '\\');
+ path = MBSRCHR((p == NULL ? zippath : p), '/');
+ if (path != NULL)
+ p = path;
+ if (p != NULL) {
+ len = (int)(p - zippath) + 1;
+ if ((path = malloc(len + sizeof("unzip.exe"))) == NULL)
+ ziperr(ZE_MEM, "was creating unzip path");
+ memcpy(path, zippath, len);
+ strcpy(&path[len], "unzip.exe");
+
+ if (check_unzip_version(path) == 0)
+ ZIPERR(ZE_TEST, zipfile);
+
+ status = spawnlp(P_WAIT, path, "unzip", verbose ? "-t" : "-tqq",
+ zipnam, NULL);
+ free(path);
+ }
+ if (status == -1)
+ perror("unzip");
+ }
+ }
+# endif /* ?__human68k__ */
+ free(zipnam);
+ if (status != 0) {
+
+#else /* (MSDOS && !__GO32__) || __human68k__ */
+ char *cmd;
+ int result;
+
+ /* Tell picky compilers to shut up about unused variables */
+ zippath = zippath;
+
+ if (unzip_path) {
+ /* user gave us a path to some unzip (may not be UnZip) */
+ char *here;
+ int len;
+
+ /* Replace first {} with archive name. If no {} append name to string. */
+ here = strstr(unzip_path, "{}");
+
+ if ((cmd = malloc(strlen(unzip_path) + strlen(zipname) + 3)) == NULL) {
+ ziperr(ZE_MEM, "building command string for testing archive");
+ }
+
+ if (here) {
+ /* have {} so replace with temp name */
+ len = here - unzip_path;
+ strcpy(cmd, unzip_path);
+ cmd[len] = '\0';
+ strcat(cmd, " ");
+# ifdef UNIX
+ strcat(cmd, "'"); /* accept space or $ in name */
+ strcat(cmd, zipname);
+ strcat(cmd, "'");
+# else
+ strcat(cmd, zipname);
+# endif
+ strcat(cmd, " ");
+ strcat(cmd, here + 2);
+ } else {
+ /* No {} so append temp name to end */
+ strcpy(cmd, unzip_path);
+ strcat(cmd, " ");
+# ifdef UNIX
+ strcat(cmd, "'"); /* accept space or $ in name */
+ strcat(cmd, zipname);
+ strcat(cmd, "'");
+# else
+ strcat(cmd, zipname);
+# endif
+ }
+ free(unzip_path);
+ unzip_path = NULL;
+
+ } else {
+ if ((cmd = malloc(20 + strlen(zipname))) == NULL) {
+ ziperr(ZE_MEM, "building command string for testing archive");
+ }
+
+ strcpy(cmd, "unzip -t ");
+# ifdef QDOS
+ strcat(cmd, "-Q4 ");
+# endif
+ if (!verbose) strcat(cmd, "-qq ");
+ if (check_unzip_version("unzip") == 0)
+ ZIPERR(ZE_TEST, zipfile);
+
+# ifdef UNIX
+ strcat(cmd, "'"); /* accept space or $ in name */
+ strcat(cmd, zipname);
+ strcat(cmd, "'");
+# else
+ strcat(cmd, zipname);
+# endif
+ }
+
+ result = system(cmd);
+# ifdef VMS
+ /* Convert success severity to 0, others to non-zero. */
+ result = ((result & STS$M_SEVERITY) != STS$M_SUCCESS);
+# endif /* def VMS */
+ free(cmd);
+ cmd = NULL;
+ if (result) {
+#endif /* ?((MSDOS && !__GO32__) || __human68k__) */
+
+ fprintf(mesg, "test of %s FAILED\n", zipfile);
+ ziperr(ZE_TEST, "original files unmodified");
+ }
+ if (noisy) {
+ fprintf(mesg, "test of %s OK\n", zipfile);
+ fflush(mesg);
+ }
+ if (logfile) {
+ fprintf(logfile, "test of %s OK\n", zipfile);
+ fflush(logfile);
+ }
+}
+#endif /* !WINDLL */
+
+/* get_filters() is replaced by the following
+local int get_filters(argc, argv)
+*/
+
+/* The filter patterns for options -x, -i, and -R are
+ returned by get_option() one at a time, so use a linked
+ list to store until all args are processed. Then convert
+ to array for processing.
+ */
+
+/* add a filter to the linked list */
+local int add_filter(flag, pattern)
+ int flag;
+ char *pattern;
+{
+ char *iname, *p = NULL;
+ FILE *fp;
+ struct filterlist_struct *filter = NULL;
+
+ /* should never happen */
+ if (flag != 'R' && flag != 'x' && flag != 'i') {
+ ZIPERR(ZE_LOGIC, "bad flag to add_filter");
+ }
+ if (pattern == NULL) {
+ ZIPERR(ZE_LOGIC, "null pattern to add_filter");
+ }
+
+ if (pattern[0] == '@') {
+ /* read file with 1 pattern per line */
+ if (pattern[1] == '\0') {
+ ZIPERR(ZE_PARMS, "missing file after @");
+ }
+ fp = fopen(pattern + 1, "r");
+ if (fp == NULL) {
+ sprintf(errbuf, "%c pattern file '%s'", flag, pattern);
+ ZIPERR(ZE_OPEN, errbuf);
+ }
+ while ((p = getnam(fp)) != NULL) {
+ if ((filter = (struct filterlist_struct *) malloc(sizeof(struct filterlist_struct))) == NULL) {
+ ZIPERR(ZE_MEM, "adding filter");
+ }
+ if (filterlist == NULL) {
+ /* first filter */
+ filterlist = filter; /* start of list */
+ lastfilter = filter;
+ } else {
+ lastfilter->next = filter; /* link to last filter in list */
+ lastfilter = filter;
+ }
+ iname = ex2in(p, 0, (int *)NULL);
+ free(p);
+ if (iname != NULL) {
+ lastfilter->pattern = in2ex(iname);
+ free(iname);
+ } else {
+ lastfilter->pattern = NULL;
+ }
+ lastfilter->flag = flag;
+ pcount++;
+ lastfilter->next = NULL;
+ }
+ fclose(fp);
+ } else {
+ /* single pattern */
+ if ((filter = (struct filterlist_struct *) malloc(sizeof(struct filterlist_struct))) == NULL) {
+ ZIPERR(ZE_MEM, "adding filter");
+ }
+ if (filterlist == NULL) {
+ /* first pattern */
+ filterlist = filter; /* start of list */
+ lastfilter = filter;
+ } else {
+ lastfilter->next = filter; /* link to last filter in list */
+ lastfilter = filter;
+ }
+ iname = ex2in(pattern, 0, (int *)NULL);
+ if (iname != NULL) {
+ lastfilter->pattern = in2ex(iname);
+ free(iname);
+ } else {
+ lastfilter->pattern = NULL;
+ }
+ lastfilter->flag = flag;
+ pcount++;
+ lastfilter->next = NULL;
+ }
+
+ return pcount;
+}
+
+/* convert list to patterns array */
+local int filterlist_to_patterns()
+{
+ unsigned i;
+ struct filterlist_struct *next = NULL;
+
+ if (pcount == 0) {
+ patterns = NULL;
+ return 0;
+ }
+ if ((patterns = (struct plist *) malloc((pcount + 1) * sizeof(struct plist)))
+ == NULL) {
+ ZIPERR(ZE_MEM, "was creating pattern list");
+ }
+
+ for (i = 0; i < pcount && filterlist != NULL; i++) {
+ switch (filterlist->flag) {
+ case 'i':
+ icount++;
+ break;
+ case 'R':
+ Rcount++;
+ break;
+ }
+ patterns[i].select = filterlist->flag;
+ patterns[i].zname = filterlist->pattern;
+ next = filterlist->next;
+ free(filterlist);
+ filterlist = next;
+ }
+
+ return pcount;
+}
+
+
+/* add a file argument to linked list */
+local long add_name(filearg)
+ char *filearg;
+{
+ char *name = NULL;
+ struct filelist_struct *fileentry = NULL;
+
+ if ((fileentry = (struct filelist_struct *) malloc(sizeof(struct filelist_struct))) == NULL) {
+ ZIPERR(ZE_MEM, "adding file");
+ }
+ if ((name = malloc(strlen(filearg) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "adding file");
+ }
+ strcpy(name, filearg);
+ fileentry->next = NULL;
+ fileentry->name = name;
+ if (filelist == NULL) {
+ /* first file argument */
+ filelist = fileentry; /* start of list */
+ lastfile = fileentry;
+ } else {
+ lastfile->next = fileentry; /* link to last filter in list */
+ lastfile = fileentry;
+ }
+ filearg_count++;
+
+ return filearg_count;
+}
+
+
+/* Running Stats
+ 10/30/04 */
+
+local int DisplayRunningStats()
+{
+ char tempstrg[100];
+
+ if (mesg_line_started) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ }
+ if (logfile_line_started) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ }
+ if (display_volume) {
+ if (noisy) {
+ fprintf(mesg, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+ mesg_line_started = 1;
+ }
+ if (logall) {
+ fprintf(logfile, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+ logfile_line_started = 1;
+ }
+ }
+ if (display_counts) {
+ if (noisy) {
+ fprintf(mesg, "%3ld/%3ld ", files_so_far, files_total - files_so_far);
+ mesg_line_started = 1;
+ }
+ if (logall) {
+ fprintf(logfile, "%3ld/%3ld ", files_so_far, files_total - files_so_far);
+ logfile_line_started = 1;
+ }
+ }
+ if (display_bytes) {
+ /* since file sizes can change as we go, use bytes_so_far from
+ initial scan so all adds up */
+ WriteNumString(bytes_so_far, tempstrg);
+ if (noisy) {
+ fprintf(mesg, "[%4s", tempstrg);
+ mesg_line_started = 1;
+ }
+ if (logall) {
+ fprintf(logfile, "[%4s", tempstrg);
+ logfile_line_started = 1;
+ }
+ if (bytes_total >= bytes_so_far) {
+ WriteNumString(bytes_total - bytes_so_far, tempstrg);
+ if (noisy)
+ fprintf(mesg, "/%4s] ", tempstrg);
+ if (logall)
+ fprintf(logfile, "/%4s] ", tempstrg);
+ } else {
+ WriteNumString(bytes_so_far - bytes_total, tempstrg);
+ if (noisy)
+ fprintf(mesg, "-%4s] ", tempstrg);
+ if (logall)
+ fprintf(logfile, "-%4s] ", tempstrg);
+ }
+ }
+ if (noisy)
+ fflush(mesg);
+ if (logall)
+ fflush(logfile);
+
+ return 0;
+}
+
+local int BlankRunningStats()
+{
+ if (display_volume) {
+ if (noisy) {
+ fprintf(mesg, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+ mesg_line_started = 1;
+ }
+ if (logall) {
+ fprintf(logfile, "%lu>%lu: ", current_in_disk + 1, current_disk + 1);
+ logfile_line_started = 1;
+ }
+ }
+ if (display_counts) {
+ if (noisy) {
+ fprintf(mesg, " / ");
+ mesg_line_started = 1;
+ }
+ if (logall) {
+ fprintf(logfile, " / ");
+ logfile_line_started = 1;
+ }
+ }
+ if (display_bytes) {
+ if (noisy) {
+ fprintf(mesg, " / ");
+ mesg_line_started = 1;
+ }
+ if (logall) {
+ fprintf(logfile, " / ");
+ logfile_line_started = 1;
+ }
+ }
+ if (noisy)
+ fflush(mesg);
+ if (logall)
+ fflush(logfile);
+
+ return 0;
+}
+
+#if CRYPT
+#ifndef WINDLL
+int encr_passwd(modeflag, pwbuf, size, zfn)
+int modeflag;
+char *pwbuf;
+int size;
+ZCONST char *zfn;
+{
+ char *prompt;
+
+ /* Tell picky compilers to shut up about unused variables */
+ zfn = zfn;
+
+ prompt = (modeflag == ZP_PW_VERIFY) ?
+ "Verify password: " : "Enter password: ";
+
+ if (getp(prompt, pwbuf, size) == NULL) {
+ ziperr(ZE_PARMS, "stderr is not a tty");
+ }
+ return IZ_PW_ENTERED;
+}
+#endif /* !WINDLL */
+#else /* !CRYPT */
+int encr_passwd(modeflag, pwbuf, size, zfn)
+int modeflag;
+char *pwbuf;
+int size;
+ZCONST char *zfn;
+{
+ /* Tell picky compilers to shut up about unused variables */
+ modeflag = modeflag; pwbuf = pwbuf; size = size; zfn = zfn;
+
+ return ZE_LOGIC; /* This function should never be called! */
+}
+#endif /* CRYPT */
+
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ */
+int rename_split(temp_name, out_path)
+ char *temp_name;
+ char *out_path;
+{
+ int r;
+ /* Replace old zip file with new zip file, leaving only the new one */
+ if ((r = replace(out_path, temp_name)) != ZE_OK)
+ {
+ zipwarn("new zip file left as: ", temp_name);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ZIPERR(r, "was replacing split file");
+ }
+ if (zip_attributes) {
+ setfileattr(out_path, zip_attributes);
+ }
+ return ZE_OK;
+}
+
+
+int set_filetype(out_path)
+ char *out_path;
+{
+#ifdef __BEOS__
+ /* Set the filetype of the zipfile to "application/zip" */
+ setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+ /* Set the filetype of the zipfile to "application/x-zip" */
+ setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+ /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+ setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+ /* Set the filetype of the zipfile to &DDC */
+ setfiletype(out_path, 0xDDC);
+#endif
+ return ZE_OK;
+}
+
+
+/*
+ -------------------------------------------------------
+ Command Line Options
+ -------------------------------------------------------
+
+ Valid command line options.
+
+ The function get_option() uses this table to check if an
+ option is valid and if it takes a value (also called an
+ option argument). To add an option to zip just add it
+ to this table and add a case in the main switch to handle
+ it. If either shortopt or longopt not used set to "".
+
+ The fields:
+ shortopt - short option name (1 or 2 chars)
+ longopt - long option name
+ value_type - see zip.h for constants
+ negatable - option is negatable with trailing -
+ ID - unsigned long int returned for option
+ name - short description of option which is
+ returned on some errors and when options
+ are listed with -so option, can be NULL
+*/
+
+/* Most option IDs are set to the shortopt char. For
+ multichar short options set to arbitrary unused constant. */
+#define o_AC 0x101
+#define o_AS 0x102
+#define o_C2 0x103
+#define o_C5 0x104
+#define o_db 0x105
+#define o_dc 0x106
+#define o_dd 0x107
+#define o_des 0x108
+#define o_df 0x109
+#define o_DF 0x110
+#define o_dg 0x111
+#define o_ds 0x112
+#define o_du 0x113
+#define o_dv 0x114
+#define o_FF 0x115
+#define o_FI 0x116
+#define o_FS 0x117
+#define o_h2 0x118
+#define o_ic 0x119
+#define o_jj 0x120
+#define o_la 0x121
+#define o_lf 0x122
+#define o_li 0x123
+#define o_ll 0x124
+#define o_mm 0x125
+#define o_MM 0x126
+#define o_nw 0x127
+#define o_RE 0x128
+#define o_sb 0x129
+#define o_sc 0x130
+#define o_sd 0x131
+#define o_sf 0x132
+#define o_so 0x133
+#define o_sp 0x134
+#define o_su 0x135
+#define o_sU 0x136
+#define o_sv 0x137
+#define o_tt 0x138
+#define o_TT 0x139
+#define o_UN 0x140
+#define o_ve 0x141
+#define o_VV 0x142
+#define o_ws 0x143
+#define o_ww 0x144
+#define o_z64 0x145
+#ifdef UNICODE_TEST
+#define o_sC 0x146
+#endif
+
+
+/* the below is mainly from the old main command line
+ switch with a few changes */
+struct option_struct far options[] = {
+ /* short longopt value_type negatable ID name */
+#ifdef EBCDIC
+ {"a", "ascii", o_NO_VALUE, o_NOT_NEGATABLE, 'a', "to ascii"},
+#endif /* EBCDIC */
+#ifdef CMS_MVS
+ {"B", "binary", o_NO_VALUE, o_NOT_NEGATABLE, 'B', "binary"},
+#endif /* CMS_MVS */
+#ifdef TANDEM
+ {"B", "", o_NUMBER_VALUE, o_NOT_NEGATABLE, 'B', "nsk"},
+#endif
+ {"0", "store", o_NO_VALUE, o_NOT_NEGATABLE, '0', "store"},
+ {"1", "compress-1", o_NO_VALUE, o_NOT_NEGATABLE, '1', "compress 1"},
+ {"2", "compress-2", o_NO_VALUE, o_NOT_NEGATABLE, '2', "compress 2"},
+ {"3", "compress-3", o_NO_VALUE, o_NOT_NEGATABLE, '3', "compress 3"},
+ {"4", "compress-4", o_NO_VALUE, o_NOT_NEGATABLE, '4', "compress 4"},
+ {"5", "compress-5", o_NO_VALUE, o_NOT_NEGATABLE, '5', "compress 5"},
+ {"6", "compress-6", o_NO_VALUE, o_NOT_NEGATABLE, '6', "compress 6"},
+ {"7", "compress-7", o_NO_VALUE, o_NOT_NEGATABLE, '7', "compress 7"},
+ {"8", "compress-8", o_NO_VALUE, o_NOT_NEGATABLE, '8', "compress 8"},
+ {"9", "compress-9", o_NO_VALUE, o_NOT_NEGATABLE, '9', "compress 9"},
+ {"A", "adjust-sfx", o_NO_VALUE, o_NOT_NEGATABLE, 'A', "adjust self extractor offsets"},
+#if defined(WIN32)
+ {"AC", "archive-clear", o_NO_VALUE, o_NOT_NEGATABLE, o_AC, "clear DOS archive bit of included files"},
+ {"AS", "archive-set", o_NO_VALUE, o_NOT_NEGATABLE, o_AS, "include only files with archive bit set"},
+#endif
+ {"b", "temp-path", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'b', "dir to use for temp archive"},
+ {"c", "entry-comments", o_NO_VALUE, o_NOT_NEGATABLE, 'c', "add comments for each entry"},
+#ifdef VMS
+ {"C", "preserve-case", o_NO_VALUE, o_NEGATABLE, 'C', "Preserve (C-: down-) case all on VMS"},
+ {"C2", "preserve-case-2", o_NO_VALUE, o_NEGATABLE, o_C2, "Preserve (C2-: down-) case ODS2 on VMS"},
+ {"C5", "preserve-case-5", o_NO_VALUE, o_NEGATABLE, o_C5, "Preserve (C5-: down-) case ODS5 on VMS"},
+#endif /* VMS */
+ {"d", "delete", o_NO_VALUE, o_NOT_NEGATABLE, 'd', "delete entries from archive"},
+ {"db", "display-bytes", o_NO_VALUE, o_NEGATABLE, o_db, "display running bytes"},
+ {"dc", "display-counts", o_NO_VALUE, o_NEGATABLE, o_dc, "display running file count"},
+ {"dd", "display-dots", o_NO_VALUE, o_NEGATABLE, o_dd, "display dots as process each file"},
+ {"dg", "display-globaldots",o_NO_VALUE, o_NEGATABLE, o_dg, "display dots for archive instead of files"},
+ {"ds", "dot-size", o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_ds, "set progress dot size - default 10M bytes"},
+ {"du", "display-usize", o_NO_VALUE, o_NEGATABLE, o_du, "display uncompressed size in bytes"},
+ {"dv", "display-volume", o_NO_VALUE, o_NEGATABLE, o_dv, "display volume (disk) number"},
+#ifdef MACOS
+ {"df", "datafork", o_NO_VALUE, o_NOT_NEGATABLE, o_df, "save datafork"},
+#endif /* MACOS */
+ {"D", "no-dir-entries", o_NO_VALUE, o_NOT_NEGATABLE, 'D', "no entries for dirs themselves (-x */)"},
+ {"DF", "difference-archive",o_NO_VALUE, o_NOT_NEGATABLE, o_DF, "create diff archive with changed/new files"},
+ {"e", "encrypt", o_NO_VALUE, o_NOT_NEGATABLE, 'e', "encrypt entries, ask for password"},
+#ifdef OS2
+ {"E", "longnames", o_NO_VALUE, o_NOT_NEGATABLE, 'E', "use OS2 longnames"},
+#endif
+ {"F", "fix", o_NO_VALUE, o_NOT_NEGATABLE, 'F', "fix mostly intact archive (try first)"},
+ {"FF", "fixfix", o_NO_VALUE, o_NOT_NEGATABLE, o_FF, "try harder to fix archive (not as reliable)"},
+ {"FI", "fifo", o_NO_VALUE, o_NEGATABLE, o_FI, "read Unix FIFO (zip will wait on open pipe)"},
+ {"FS", "filesync", o_NO_VALUE, o_NOT_NEGATABLE, o_FS, "add/delete entries to make archive match OS"},
+ {"f", "freshen", o_NO_VALUE, o_NOT_NEGATABLE, 'f', "freshen existing archive entries"},
+ {"fd", "force-descriptors", o_NO_VALUE, o_NOT_NEGATABLE, o_des,"force data descriptors as if streaming"},
+#ifdef ZIP64_SUPPORT
+ {"fz", "force-zip64", o_NO_VALUE, o_NEGATABLE, o_z64,"force use of Zip64 format, negate prevents"},
+#endif
+ {"g", "grow", o_NO_VALUE, o_NOT_NEGATABLE, 'g', "grow existing archive instead of replace"},
+#ifndef WINDLL
+ {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
+ {"H", "", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
+ {"?", "", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
+ {"h2", "more-help", o_NO_VALUE, o_NOT_NEGATABLE, o_h2, "extended help"},
+#endif /* !WINDLL */
+ {"i", "include", o_VALUE_LIST, o_NOT_NEGATABLE, 'i', "include only files matching patterns"},
+#if defined(VMS) || defined(WIN32)
+ {"ic", "ignore-case", o_NO_VALUE, o_NEGATABLE, o_ic, "ignore case when matching archive entries"},
+#endif
+#ifdef RISCOS
+ {"I", "no-image", o_NO_VALUE, o_NOT_NEGATABLE, 'I', "no image"},
+#endif
+ {"j", "junk-paths", o_NO_VALUE, o_NOT_NEGATABLE, 'j', "strip paths and just store file names"},
+#ifdef MACOS
+ {"jj", "absolute-path", o_NO_VALUE, o_NOT_NEGATABLE, o_jj, "MAC absolute path"},
+#endif /* ?MACOS */
+ {"J", "junk-sfx", o_NO_VALUE, o_NOT_NEGATABLE, 'J', "strip self extractor from archive"},
+ {"k", "DOS-names", o_NO_VALUE, o_NOT_NEGATABLE, 'k', "force use of 8.3 DOS names"},
+ {"l", "to-crlf", o_NO_VALUE, o_NOT_NEGATABLE, 'l', "convert text file line ends - LF->CRLF"},
+ {"ll", "from-crlf", o_NO_VALUE, o_NOT_NEGATABLE, o_ll, "convert text file line ends - CRLF->LF"},
+ {"lf", "logfile-path",o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_lf, "log to log file at path (default overwrite)"},
+ {"la", "log-append", o_NO_VALUE, o_NEGATABLE, o_la, "append to existing log file"},
+ {"li", "log-info", o_NO_VALUE, o_NEGATABLE, o_li, "include informational messages in log"},
+#ifndef WINDLL
+ {"L", "license", o_NO_VALUE, o_NOT_NEGATABLE, 'L', "display license"},
+#endif
+ {"m", "move", o_NO_VALUE, o_NOT_NEGATABLE, 'm', "add files to archive then delete files"},
+ {"mm", "", o_NO_VALUE, o_NOT_NEGATABLE, o_mm, "not used"},
+ {"MM", "must-match", o_NO_VALUE, o_NOT_NEGATABLE, o_MM, "error if in file not matched/not readable"},
+ {"n", "suffixes", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'n', "suffixes to not compress: .gz:.zip"},
+ {"nw", "no-wild", o_NO_VALUE, o_NOT_NEGATABLE, o_nw, "no wildcards during add or update"},
+#if defined(AMIGA) || defined(MACOS)
+ {"N", "notes", o_NO_VALUE, o_NOT_NEGATABLE, 'N', "add notes as entry comments"},
+#endif
+ {"o", "latest-time", o_NO_VALUE, o_NOT_NEGATABLE, 'o', "use latest entry time as archive time"},
+ {"O", "output-file", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'O', "set out zipfile different than in zipfile"},
+ {"p", "paths", o_NO_VALUE, o_NOT_NEGATABLE, 'p', "store paths"},
+ {"P", "password", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'P', "encrypt entries, option value is password"},
+#if defined(QDOS) || defined(QLZIP)
+ {"Q", "Q-flag", o_NUMBER_VALUE, o_NOT_NEGATABLE, 'Q', "Q flag"},
+#endif
+ {"q", "quiet", o_NO_VALUE, o_NOT_NEGATABLE, 'q', "quiet"},
+ {"r", "recurse-paths", o_NO_VALUE, o_NOT_NEGATABLE, 'r', "recurse down listed paths"},
+ {"R", "recurse-patterns", o_NO_VALUE, o_NOT_NEGATABLE, 'R', "recurse current dir and match patterns"},
+ {"RE", "regex", o_NO_VALUE, o_NOT_NEGATABLE, o_RE, "allow [list] matching (regex)"},
+ {"s", "split-size", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 's', "do splits, set split size (-s=0 no splits)"},
+ {"sp", "split-pause", o_NO_VALUE, o_NOT_NEGATABLE, o_sp, "pause while splitting to select destination"},
+ {"sv", "split-verbose", o_NO_VALUE, o_NOT_NEGATABLE, o_sv, "be verbose about creating splits"},
+ {"sb", "split-bell", o_NO_VALUE, o_NOT_NEGATABLE, o_sb, "when pause for next split ring bell"},
+ {"sc", "show-command",o_NO_VALUE, o_NOT_NEGATABLE, o_sc, "show command line"},
+#ifdef UNICODE_TEST
+ {"sC", "create-files",o_NO_VALUE, o_NOT_NEGATABLE, o_sC, "create empty files using archive names"},
+#endif
+ {"sd", "show-debug", o_NO_VALUE, o_NOT_NEGATABLE, o_sd, "show debug"},
+ {"sf", "show-files", o_NO_VALUE, o_NEGATABLE, o_sf, "show files to operate on and exit"},
+ {"so", "show-options",o_NO_VALUE, o_NOT_NEGATABLE, o_so, "show options"},
+#ifdef UNICODE_SUPPORT
+ {"su", "show-unicode", o_NO_VALUE, o_NEGATABLE, o_su, "as -sf but also show escaped Unicode"},
+ {"sU", "show-just-unicode", o_NO_VALUE, o_NEGATABLE, o_sU, "as -sf but only show escaped Unicode"},
+#endif
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(ATARI)
+ {"S", "", o_NO_VALUE, o_NOT_NEGATABLE, 'S', "include system and hidden"},
+#endif /* MSDOS || OS2 || WIN32 || ATARI */
+ {"t", "from-date", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 't', "exclude before date"},
+ {"tt", "before-date", o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_tt, "include before date"},
+ {"T", "test", o_NO_VALUE, o_NOT_NEGATABLE, 'T', "test updates before replacing archive"},
+ {"TT", "unzip-command", o_REQUIRED_VALUE,o_NOT_NEGATABLE,o_TT, "unzip command to use, name is added to end"},
+ {"u", "update", o_NO_VALUE, o_NOT_NEGATABLE, 'u', "update existing entries and add new"},
+ {"U", "copy-entries", o_NO_VALUE, o_NOT_NEGATABLE, 'U', "select from archive instead of file system"},
+#ifdef UNICODE_SUPPORT
+ {"UN", "unicode", o_REQUIRED_VALUE, o_NOT_NEGATABLE, o_UN, "UN=quit, warn, ignore, no, escape"},
+#endif
+ {"v", "verbose", o_NO_VALUE, o_NOT_NEGATABLE, 'v', "display additional information"},
+ {"", "version", o_NO_VALUE, o_NOT_NEGATABLE, o_ve, "(if no other args) show version information"},
+#ifdef VMS
+ {"V", "VMS-portable", o_NO_VALUE, o_NOT_NEGATABLE, 'V', "Store VMS attributes, portable file format"},
+ {"VV", "VMS-specific", o_NO_VALUE, o_NOT_NEGATABLE, o_VV, "Store VMS attributes, VMS specific format"},
+ {"w", "VMS-versions", o_NO_VALUE, o_NOT_NEGATABLE, 'w', "store VMS versions"},
+ {"ww", "VMS-dot-versions", o_NO_VALUE, o_NOT_NEGATABLE, o_ww, "store VMS versions as \".nnn\""},
+#endif /* VMS */
+ {"ws", "wild-stop-dirs", o_NO_VALUE, o_NOT_NEGATABLE, o_ws, "* stops at /, ** includes any /"},
+ {"x", "exclude", o_VALUE_LIST, o_NOT_NEGATABLE, 'x', "exclude files matching patterns"},
+/* {"X", "no-extra", o_NO_VALUE, o_NOT_NEGATABLE, 'X', "no extra"},
+*/
+ {"X", "strip-extra", o_NO_VALUE, o_NEGATABLE, 'X', "-X- keep all ef, -X strip but critical ef"},
+#ifdef S_IFLNK
+ {"y", "symlinks", o_NO_VALUE, o_NOT_NEGATABLE, 'y', "store symbolic links"},
+#endif /* S_IFLNK */
+ {"z", "archive-comment", o_NO_VALUE, o_NOT_NEGATABLE, 'z', "ask for archive comment"},
+ {"Z", "compression-method", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'Z', "compression method"},
+#if defined(MSDOS) || defined(OS2)
+ {"$", "volume-label", o_NO_VALUE, o_NOT_NEGATABLE, '$', "store volume label"},
+#endif
+#ifndef MACOS
+ {"@", "names-stdin", o_NO_VALUE, o_NOT_NEGATABLE, '@', "get file names from stdin, one per line"},
+#endif /* !MACOS */
+#ifdef NTSD_EAS
+ {"!", "use-privileges", o_NO_VALUE, o_NOT_NEGATABLE, '!', "use privileges"},
+#endif
+#ifdef RISCOS
+ {"/", "exts-to-swap", o_REQUIRED_VALUE, o_NOT_NEGATABLE, '/', "override Zip$Exts"},
+#endif
+ /* the end of the list */
+ {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
+ };
+
+
+
+#ifndef USE_ZIPMAIN
+int main(argc, argv)
+#else
+int zipmain(argc, argv)
+#endif
+int argc; /* number of tokens in command line */
+char **argv; /* command line tokens */
+/* Add, update, freshen, or delete zip entries in a zip file. See the
+ command help in help() above. */
+{
+ int d; /* true if just adding to a zip file */
+ char *e; /* malloc'd comment buffer */
+ struct flist far *f; /* steps through found linked list */
+ int i; /* arg counter, root directory flag */
+ int kk; /* next arg type (formerly another re-use of "k") */
+
+ /* zip64 support 09/05/2003 R.Nausedat */
+ uzoff_t c; /* start of central directory */
+ uzoff_t t; /* length of central directory */
+ zoff_t k; /* marked counter, comment size, entry count */
+ uzoff_t n; /* total of entry len's */
+
+ int o; /* true if there were any ZE_OPEN errors */
+ char *p; /* steps through option arguments */
+ char *pp; /* temporary pointer */
+ int r; /* temporary variable */
+ int s; /* flag to read names from stdin */
+ uzoff_t csize; /* compressed file size for stats */
+ uzoff_t usize; /* uncompressed file size for stats */
+ ulg tf; /* file time */
+ int first_listarg = 0;/* index of first arg of "process these files" list */
+ struct zlist far *v; /* temporary variable */
+ struct zlist far * far *w; /* pointer to last link in zfiles list */
+ FILE *x /*, *y */; /* input and output zip files (y global) */
+ struct zlist far *z; /* steps through zfiles linked list */
+ int bad_open_is_error = 0; /* if read fails, 0=warning, 1=error */
+#if 0
+ /* does not seem used */
+#ifdef WINDLL
+ int retcode; /* return code for dll */
+#endif /* WINDLL */
+#endif
+#if (!defined(VMS) && !defined(CMS_MVS))
+ char *zipbuf; /* stdio buffer for the zip file */
+#endif /* !VMS && !CMS_MVS */
+ FILE *comment_stream; /* set to stderr if anything is read from stdin */
+ int all_current; /* used by File Sync to determine if all entries are current */
+
+ struct filelist_struct *filearg;
+
+/* used by get_option */
+ unsigned long option; /* option ID returned by get_option */
+ int argcnt = 0; /* current argcnt in args */
+ int argnum = 0; /* arg number */
+ int optchar = 0; /* option state */
+ char *value = NULL; /* non-option arg, option value or NULL */
+ int negated = 0; /* 1 = option negated */
+ int fna = 0; /* current first non-opt arg */
+ int optnum = 0; /* index in table */
+
+ int show_options = 0; /* show options */
+ int show_what_doing = 0; /* show what doing */
+ int show_args = 0; /* show command line */
+ int seen_doubledash = 0; /* seen -- argument */
+ int key_needed = 0; /* prompt for encryption key */
+ int have_out = 0; /* if set in_path and out_path different archive */
+#ifdef UNICODE_TEST
+ int create_files = 0;
+#endif
+
+ char **args = NULL; /* could be wide argv */
+
+
+#ifdef THEOS
+ /* the argument expansion from the standard library is full of bugs */
+ /* use mine instead */
+ _setargv(&argc, &argv);
+ setlocale(LC_CTYPE, "I");
+#else
+ SETLOCALE(LC_CTYPE, "");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+ /* For Unix, set the locale to UTF-8. Any UTF-8 locale is
+ OK and they should all be the same. This allows seeing,
+ writing, and displaying (if the fonts are loaded) all
+ characters in UTF-8. */
+ {
+ char *loc;
+
+ /*
+ loc = setlocale(LC_CTYPE, NULL);
+ printf(" Initial language locale = '%s'\n", loc);
+ */
+
+ loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+ /*
+ printf("langinfo %s\n", nl_langinfo(CODESET));
+ */
+
+ if (loc != NULL) {
+ /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+ using_utf8 = 1;
+ /*
+ printf(" Locale set to %s\n", loc);
+ */
+ } else {
+ /*
+ printf(" Could not set Unicode UTF-8 locale\n");
+ */
+ }
+ }
+# endif
+#endif
+
+#if defined(__IBMC__) && defined(__DEBUG_ALLOC__)
+ {
+ extern void DebugMalloc(void);
+ atexit(DebugMalloc);
+ }
+#endif
+
+#ifdef QDOS
+ {
+ extern void QDOSexit(void);
+ atexit(QDOSexit);
+ }
+#endif
+
+#ifdef NLM
+ {
+ extern void NLMexit(void);
+ atexit(NLMexit);
+ }
+#endif
+
+#ifdef RISCOS
+ set_prefix();
+#endif
+
+#ifdef __human68k__
+ fflush(stderr);
+ setbuf(stderr, NULL);
+#endif
+
+/* Re-initialize global variables to make the zip dll re-entrant. It is
+ * possible that we could get away with not re-initializing all of these
+ * but better safe than sorry.
+ */
+#if defined(MACOS) || defined(WINDLL) || defined(USE_ZIPMAIN)
+ action = ADD; /* one of ADD, UPDATE, FRESHEN, DELETE, or ARCHIVE */
+ comadd = 0; /* 1=add comments for new files */
+ zipedit = 0; /* 1=edit zip comment and all file comments */
+ latest = 0; /* 1=set zip file time to time of latest file */
+ before = 0; /* 0=ignore, else exclude files before this time */
+ after = 0; /* 0=ignore, else exclude files newer than this time */
+ test = 0; /* 1=test zip file with unzip -t */
+ unzip_path = NULL; /* where to look for unzip command path */
+ tempdir = 0; /* 1=use temp directory (-b) */
+ junk_sfx = 0; /* 1=junk the sfx prefix */
+#if defined(AMIGA) || defined(MACOS)
+ filenotes = 0;/* 1=take comments from AmigaDOS/MACOS filenotes */
+#endif
+#ifndef USE_ZIPMAIN
+ zipstate = -1;
+#endif
+ tempzip = NULL;
+ fcount = 0;
+ recurse = 0; /* 1=recurse into directories; 2=match filenames */
+ dispose = 0; /* 1=remove files after put in zip file */
+ pathput = 1; /* 1=store path with name */
+ method = BEST; /* one of BEST, DEFLATE (only), or STORE (only) */
+ dosify = 0; /* 1=make new entries look like MSDOS */
+ verbose = 0; /* 1=report oddities in zip file structure */
+ fix = 0; /* 1=fix the zip file */
+ adjust = 0; /* 1=adjust offsets for sfx'd file (keep preamble) */
+ level = 6; /* 0=fastest compression, 9=best compression */
+ translate_eol = 0; /* Translate end-of-line LF -> CR LF */
+#if defined(OS2) || defined(WIN32)
+ use_longname_ea = 0; /* 1=use the .LONGNAME EA as the file's name */
+#endif
+#ifdef NTSD_EAS
+ use_privileges = 0; /* 1=use security privileges overrides */
+#endif
+ no_wild = 0; /* 1 = wildcards are disabled */
+#ifdef WILD_STOP_AT_DIR
+ wild_stop_at_dir = 1; /* default wildcards do not include / in matches */
+#else
+ wild_stop_at_dir = 0; /* default wildcards do include / in matches */
+#endif
+
+ skip_this_disk = 0;
+ des_good = 0; /* Good data descriptor found */
+ des_crc = 0; /* Data descriptor CRC */
+ des_csize = 0; /* Data descriptor csize */
+ des_usize = 0; /* Data descriptor usize */
+
+ dot_size = 0; /* buffers processed in deflate per dot, 0 = no dots */
+ dot_count = 0; /* buffers seen, recyles at dot_size */
+
+ display_counts = 0; /* display running file count */
+ display_bytes = 0; /* display running bytes remaining */
+ display_globaldots = 0; /* display dots for archive instead of each file */
+ display_volume = 0; /* display current input and output volume (disk) numbers */
+ display_usize = 0; /* display uncompressed bytes */
+
+ files_so_far = 0; /* files processed so far */
+ bad_files_so_far = 0; /* bad files skipped so far */
+ files_total = 0; /* files total to process */
+ bytes_so_far = 0; /* bytes processed so far (from initial scan) */
+ good_bytes_so_far = 0; /* good bytes read so far */
+ bad_bytes_so_far = 0; /* bad bytes skipped so far */
+ bytes_total = 0; /* total bytes to process (from initial scan) */
+
+ logall = 0; /* 0 = warnings/errors, 1 = all */
+ logfile = NULL; /* pointer to open logfile or NULL */
+ logfile_append = 0; /* append to existing logfile */
+ logfile_path = NULL; /* pointer to path of logfile */
+
+ hidden_files = 0; /* process hidden and system files */
+ volume_label = 0; /* add volume label */
+ dirnames = 1; /* include directory entries by default */
+#if defined(WIN32)
+ only_archive_set = 0; /* only include if DOS archive bit set */
+ clear_archive_bits = 0; /* clear DOS archive bit of included files */
+#endif
+ linkput = 0; /* 1=store symbolic links as such */
+ noisy = 1; /* 0=quiet operation */
+ extra_fields = 1; /* 0=create minimum, 1=don't copy old, 2=keep old */
+
+ use_descriptors = 0; /* 1=use data descriptors 12/29/04 */
+ zip_to_stdout = 0; /* output zipfile to stdout 12/30/04 */
+ allow_empty_archive = 0;/* if no files, create empty archive anyway 12/28/05 */
+ copy_only = 0; /* 1=copying archive entries only */
+
+ output_seekable = 1; /* 1 = output seekable 3/13/05 EG */
+
+#ifdef ZIP64_SUPPORT /* zip64 support 10/4/03 */
+ force_zip64 = -1; /* if 1 force entries to be zip64 */
+ /* mainly for streaming from stdin */
+ zip64_entry = 0; /* current entry needs Zip64 */
+ zip64_archive = 0; /* if 1 then at least 1 entry needs zip64 */
+#endif
+
+#ifdef UNICODE_SUPPORT
+ utf8_force = 0; /* 1=force storing UTF-8 as standard per AppNote bit 11 */
+#endif
+
+ unicode_escape_all = 0; /* 1=escape all non-ASCII characters in paths */
+ unicode_mismatch = 1; /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+
+ scan_delay = 5; /* seconds before display Scanning files message */
+ scan_dot_time = 2; /* time in seconds between Scanning files dots */
+ scan_start = 0; /* start of scan */
+ scan_last = 0; /* time of last message */
+ scan_started = 0; /* scan has started */
+ scan_count = 0; /* Used for Scanning files ... message */
+
+ before = 0; /* 0=ignore, else exclude files before this time */
+ after = 0; /* 0=ignore, else exclude files newer than this time */
+
+ special = ".Z:.zip:.zoo:.arc:.lzh:.arj"; /* List of special suffixes */
+ key = NULL; /* Scramble password if scrambling */
+ key_needed = 0; /* Need scramble password */
+ tempath = NULL; /* Path for temporary files */
+ patterns = NULL; /* List of patterns to be matched */
+ pcount = 0; /* number of patterns */
+ icount = 0; /* number of include only patterns */
+ Rcount = 0; /* number of -R include patterns */
+
+ found = NULL; /* List of names found, or new found entry */
+ fnxt = &found;
+
+ /* used by get_option */
+ argcnt = 0; /* size of args */
+ argnum = 0; /* current arg number */
+ optchar = 0; /* option state */
+ value = NULL; /* non-option arg, option value or NULL */
+ negated = 0; /* 1 = option negated */
+ fna = 0; /* current first nonopt arg */
+ optnum = 0; /* option index */
+
+ show_options = 0; /* 1 = show options */
+ show_what_doing = 0; /* 1 = show what zip doing */
+ show_args = 0; /* 1 = show command line */
+ seen_doubledash = 0; /* seen -- argument */
+
+ zipfile = NULL; /* path of usual in and out zipfile */
+ tempzip = NULL; /* name of temp file */
+ y = NULL; /* output file now global so can change in splits */
+ in_file = NULL; /* current input file for splits */
+ in_split_path = NULL; /* current in split path */
+ in_path = NULL; /* used by splits to track changing split locations */
+ out_path = NULL; /* if set, use -O out_path as output */
+ have_out = 0; /* if set, in_path and out_path not the same archive */
+
+ total_disks = 0; /* total disks in archive */
+ current_in_disk = 0; /* current read split disk */
+ current_in_offset = 0; /* current offset in current read disk */
+ skip_current_disk = 0; /* if != 0 and fix then skip entries on this disk */
+
+ zip64_eocd_disk = 0; /* disk with Zip64 End Of Central Directory Record */
+ zip64_eocd_offset = 0; /* offset for Zip64 EOCD Record */
+
+ current_local_disk = 0; /* disk with current local header */
+
+ current_disk = 0; /* current disk number */
+ cd_start_disk = (ulg)-1; /* central directory start disk */
+ cd_start_offset = 0; /* offset of start of cd on cd start disk */
+ cd_entries_this_disk = 0; /* cd entries this disk */
+ total_cd_entries = 0; /* total cd entries in new/updated archive */
+
+ /* for split method 1 (keep split with local header open and update) */
+ current_local_tempname = NULL; /* name of temp file */
+ current_local_file = NULL; /* file pointer for current local header */
+ current_local_offset = 0; /* offset to start of current local header */
+
+ /* global */
+ bytes_this_split = 0; /* bytes written to the current split */
+ read_split_archive = 0; /* 1=scanzipf_reg detected spanning signature */
+ split_method = 0; /* 0=no splits, 1=update LHs, 2=data descriptors */
+ split_size = 0; /* how big each split should be */
+ split_bell = 0; /* when pause for next split ring bell */
+ bytes_prev_splits = 0; /* total bytes written to all splits before this */
+ bytes_this_entry = 0; /* bytes written for this entry across all splits */
+ noisy_splits = 0; /* be verbose about creating splits */
+ mesg_line_started = 0; /* 1=started writing a line to mesg */
+ logfile_line_started = 0; /* 1=started writing a line to logfile */
+
+ filelist = NULL;
+ filearg_count = 0;
+ allow_empty_archive = 0; /* if no files, allow creation of empty archive anyway */
+ bad_open_is_error = 0; /* if read fails, 0=warning, 1=error */
+ unicode_mismatch = 0; /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+ show_files = 0; /* show files to operate on and exit */
+ scan_delay = 5; /* seconds before display Scanning files message */
+ scan_dot_time = 2; /* time in seconds between Scanning files dots */
+ scan_started = 0; /* space at start of scan has been displayed */
+ scan_last = 0; /* Time last dot displayed for Scanning files message */
+ scan_start = 0; /* Time scanning started for Scanning files message */
+#ifdef UNICODE_SUPPORT
+ use_wide_to_mb_default = 0;
+#endif
+ filter_match_case = 1; /* default is to match case when matching archive entries */
+ allow_fifo = 0; /* 1=allow reading Unix FIFOs, waiting if pipe open */
+
+#if !defined(MACOS) && !defined(USE_ZIPMAIN)
+ retcode = setjmp(zipdll_error_return);
+ if (retcode) {
+ return retcode;
+ }
+#endif /* !MACOS */
+#endif /* MACOS || WINDLL */
+
+#if !defined(ALLOW_REGEX) && (defined(MSDOS) || defined(WIN32))
+ allow_regex = 0; /* 1 = allow [list] matching (regex) */
+#else
+ allow_regex = 1;
+#endif
+
+ mesg = (FILE *) stdout; /* cannot be made at link time for VMS */
+ comment_stream = (FILE *)stdin;
+
+ init_upper(); /* build case map table */
+
+#ifdef LARGE_FILE_SUPPORT
+ /* test if we can support large files - 9/29/04 */
+ if (sizeof(zoff_t) < 8) {
+ ZIPERR(ZE_COMPERR, "LARGE_FILE_SUPPORT enabled but OS not supporting it");
+ }
+#endif
+ /* test if sizes are the same - 12/30/04 */
+ if (sizeof(uzoff_t) != sizeof(zoff_t)){
+ ZIPERR(ZE_COMPERR, "uzoff_t not same size as zoff_t");
+ }
+
+#if (defined(WIN32) && defined(USE_EF_UT_TIME))
+ /* For the Win32 environment, we may have to "prepare" the environment
+ prior to the tzset() call, to work around tzset() implementation bugs.
+ */
+ iz_w32_prepareTZenv();
+#endif
+
+#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
+# ifndef VALID_TIMEZONE
+# define VALID_TIMEZONE(tmp) \
+ (((tmp = getenv("TZ")) != NULL) && (*tmp != '\0'))
+# endif
+ zp_tz_is_valid = VALID_TIMEZONE(p);
+#if (defined(AMIGA) || defined(DOS))
+ if (!zp_tz_is_valid)
+ extra_fields = 0; /* disable storing "UT" time stamps */
+#endif /* AMIGA || DOS */
+#endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
+
+/* For systems that do not have tzset() but supply this function using another
+ name (_tzset() or something similar), an appropiate "#define tzset ..."
+ should be added to the system specifc configuration section. */
+#if (!defined(TOPS20) && !defined(VMS))
+#if (!defined(RISCOS) && !defined(MACOS) && !defined(QDOS))
+#if (!defined(BSD) && !defined(MTS) && !defined(CMS_MVS) && !defined(TANDEM))
+ tzset();
+#endif
+#endif
+#endif
+
+#ifdef VMSCLI
+ {
+ ulg status = vms_zip_cmdline(&argc, &argv);
+ if (!(status & 1))
+ return status;
+ }
+#endif /* VMSCLI */
+
+ /* Substitutes the extended command line argument list produced by
+ * the MKS Korn Shell in place of the command line info from DOS.
+ */
+
+ /* extract extended argument list from environment */
+ expand_args(&argc, &argv);
+
+#ifndef WINDLL
+ /* Process arguments */
+ diag("processing arguments");
+ /* First, check if just the help or version screen should be displayed */
+ if (argc == 1 && isatty(1)) /* no arguments, and output screen available */
+ { /* show help screen */
+# ifdef VMSCLI
+ VMSCLI_help();
+# else
+ help();
+# endif
+ EXIT(ZE_OK);
+ }
+ /* Check -v here as env arg can change argc. Handle --version in main switch. */
+ else if (argc == 2 && strcmp(argv[1], "-v") == 0 &&
+ /* only "-v" as argument, and */
+ (isatty(1) || isatty(0)))
+ /* stdout or stdin is connected to console device */
+ { /* show diagnostic version info */
+ version_info();
+ EXIT(ZE_OK);
+ }
+# ifndef VMS
+# ifndef RISCOS
+ envargs(&argc, &argv, "ZIPOPT", "ZIP"); /* get options from environment */
+# else /* RISCOS */
+ envargs(&argc, &argv, "ZIPOPT", "Zip$Options"); /* get options from environment */
+ getRISCOSexts("Zip$Exts"); /* get the extensions to swap from environment */
+# endif /* ? RISCOS */
+# else /* VMS */
+ envargs(&argc, &argv, "ZIPOPT", "ZIP_OPTS"); /* 4th arg for unzip compat. */
+# endif /* ?VMS */
+#endif /* !WINDLL */
+
+ zipfile = tempzip = NULL;
+ y = NULL;
+ d = 0; /* disallow adding to a zip file */
+#if (!defined(MACOS) && !defined(WINDLL) && !defined(NLM))
+ signal(SIGINT, handler);
+#ifdef SIGTERM /* AMIGADOS and others have no SIGTERM */
+ signal(SIGTERM, handler);
+#endif
+# if defined(SIGABRT) && !(defined(AMIGA) && defined(__SASC))
+ signal(SIGABRT, handler);
+# endif
+# ifdef SIGBREAK
+ signal(SIGBREAK, handler);
+# endif
+# ifdef SIGBUS
+ signal(SIGBUS, handler);
+# endif
+# ifdef SIGILL
+ signal(SIGILL, handler);
+# endif
+# ifdef SIGSEGV
+ signal(SIGSEGV, handler);
+# endif
+#endif /* !MACOS && !WINDLL && !NLM */
+#ifdef NLM
+ NLMsignals();
+#endif
+
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ /* check if this Win32 OS has support for wide character calls */
+ has_win32_wide();
+#endif
+
+ /* make copy of args that can use with insert_arg() used by get_option() */
+ args = copy_args(argv, 0);
+
+ kk = 0; /* Next non-option argument type */
+ s = 0; /* set by -@ */
+
+ /*
+ -------------------------------------------
+ Process command line using get_option
+ -------------------------------------------
+
+ Each call to get_option() returns either a command
+ line option and possible value or a non-option argument.
+ Arguments are permuted so that all options (-r, -b temp)
+ are returned before non-option arguments (zipfile).
+ Returns 0 when nothing left to read.
+ */
+
+ /* set argnum = 0 on first call to init get_option */
+ argnum = 0;
+
+ /* get_option returns the option ID and updates parameters:
+ args - usually same as argv if no argument file support
+ argcnt - current argc for args
+ value - char* to value (free() when done with it) or NULL if no value
+ negated - option was negated with trailing -
+ */
+
+ while ((option = get_option(&args, &argcnt, &argnum,
+ &optchar, &value, &negated,
+ &fna, &optnum, 0)))
+ {
+ switch (option)
+ {
+#ifdef EBCDIC
+ case 'a':
+ aflag = ASCII;
+ printf("Translating to ASCII...\n");
+ break;
+#endif /* EBCDIC */
+#ifdef CMS_MVS
+ case 'B':
+ bflag = 1;
+ printf("Using binary mode...\n");
+ break;
+#endif /* CMS_MVS */
+#ifdef TANDEM
+ case 'B':
+ nskformatopt(value);
+ free(value);
+ break;
+#endif
+
+ case '0':
+ method = STORE; level = 0; break;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ /* Set the compression efficacy */
+ level = (int)option - '0'; break;
+ case 'A': /* Adjust unzipsfx'd zipfile: adjust offsets only */
+ adjust = 1; break;
+#if defined(WIN32)
+ case o_AC:
+ clear_archive_bits = 1; break;
+ case o_AS:
+ /* Since some directories could be empty if no archive bits are
+ set for files in a directory, don't add directory entries (-D).
+ Just files with the archive bit set are added, including paths
+ (unless paths are excluded). All major unzips should create
+ directories for the paths as needed. */
+ dirnames = 0;
+ only_archive_set = 1; break;
+#endif /* MSDOS || OS2 || WIN32 */
+ case 'b': /* Specify path for temporary file */
+ tempdir = 1;
+ tempath = value;
+ break;
+ case 'c': /* Add comments for new files in zip file */
+ comadd = 1; break;
+
+ /* -C, -C2, and -C5 are with -V */
+
+ case 'd': /* Delete files from zip file */
+ if (action != ADD) {
+ ZIPERR(ZE_PARMS, "specify just one action");
+ }
+ action = DELETE;
+ break;
+#ifdef MACOS
+ case o_df:
+ MacZip.DataForkOnly = true;
+ break;
+#endif /* MACOS */
+ case o_db:
+ if (negated)
+ display_bytes = 0;
+ else
+ display_bytes = 1;
+ break;
+ case o_dc:
+ if (negated)
+ display_counts = 0;
+ else
+ display_counts = 1;
+ break;
+ case o_dd:
+ /* display dots */
+ display_globaldots = 0;
+ if (negated) {
+ dot_count = 0;
+ } else {
+ /* set default dot size if dot_size not set (dot_count = 0) */
+ if (dot_count == 0)
+ /* default to 10 MB */
+ dot_size = 10 * 0x100000;
+ dot_count = -1;
+ }
+ break;
+ case o_dg:
+ /* display dots globally for archive instead of for each file */
+ if (negated) {
+ display_globaldots = 0;
+ } else {
+ display_globaldots = 1;
+ /* set default dot size if dot_size not set (dot_count = 0) */
+ if (dot_count == 0)
+ dot_size = 10 * 0x100000;
+ dot_count = -1;
+ }
+ break;
+ case o_ds:
+ /* input dot_size is now actual dot size to account for
+ different buffer sizes */
+ if (value == NULL)
+ dot_size = 10 * 0x100000;
+ else if (value[0] == '\0') {
+ /* default to 10 MB */
+ dot_size = 10 * 0x100000;
+ free(value);
+ } else {
+ dot_size = ReadNumString(value);
+ if (dot_size == (zoff_t)-1) {
+ sprintf(errbuf, "option -ds (--dot-size) has bad size: '%s'",
+ value);
+ free(value);
+ ZIPERR(ZE_PARMS, errbuf);
+ }
+ if (dot_size < 0x400) {
+ /* < 1 KB so there is no multiplier, assume MB */
+ dot_size *= 0x100000;
+
+ } else if (dot_size < 0x400L * 32) {
+ /* 1K <= dot_size < 32K */
+ sprintf(errbuf, "dot size must be at least 32 KB: '%s'", value);
+ free(value);
+ ZIPERR(ZE_PARMS, errbuf);
+
+ } else {
+ /* 32K <= dot_size */
+ }
+ free(value);
+ }
+ dot_count = -1;
+ break;
+ case o_du:
+ if (negated)
+ display_usize = 0;
+ else
+ display_usize = 1;
+ break;
+ case o_dv:
+ if (negated)
+ display_volume = 0;
+ else
+ display_volume = 1;
+ break;
+ case 'D': /* Do not add directory entries */
+ dirnames = 0; break;
+ case o_DF: /* Create a difference archive */
+ diff_mode = 1;
+ allow_empty_archive = 1;
+ break;
+ case 'e': /* Encrypt */
+#if !CRYPT
+ ZIPERR(ZE_PARMS, "encryption not supported");
+#else /* CRYPT */
+ if (key)
+ free(key);
+ key_needed = 1;
+#endif /* !CRYPT */
+ break;
+ case 'F': /* fix the zip file */
+ fix = 1; break;
+ case o_FF: /* try harder to fix file */
+ fix = 2; break;
+ case o_FI:
+ if (negated)
+ allow_fifo = 0;
+ else
+ allow_fifo = 1;
+ break;
+ case o_FS: /* delete exiting entries in archive where there is
+ no matching file on file system */
+ filesync = 1; break;
+ case 'f': /* Freshen zip file--overwrite only */
+ if (action != ADD) {
+ ZIPERR(ZE_PARMS, "specify just one action");
+ }
+ action = FRESHEN;
+ break;
+ case 'g': /* Allow appending to a zip file */
+ d = 1; break;
+#ifndef WINDLL
+ case 'h': case 'H': case '?': /* Help */
+#ifdef VMSCLI
+ VMSCLI_help();
+#else
+ help();
+#endif
+ RETURN(finish(ZE_OK));
+#endif /* !WINDLL */
+
+#ifndef WINDLL
+ case o_h2: /* Extended Help */
+ help_extended();
+ RETURN(finish(ZE_OK));
+#endif /* !WINDLL */
+
+ /* -i is with -x */
+#if defined(VMS) || defined(WIN32)
+ case o_ic: /* Ignore case (case-insensitive matching of archive entries) */
+ if (negated)
+ filter_match_case = 1;
+ else
+ filter_match_case = 0;
+ break;
+#endif
+#ifdef RISCOS
+ case 'I': /* Don't scan through Image files */
+ scanimage = 0;
+ break;
+#endif
+#ifdef MACOS
+ case o_jj: /* store absolute path including volname */
+ MacZip.StoreFullPath = true;
+ break;
+#endif /* ?MACOS */
+ case 'j': /* Junk directory names */
+ pathput = 0; break;
+ case 'J': /* Junk sfx prefix */
+ junk_sfx = 1; break;
+ case 'k': /* Make entries using DOS names (k for Katz) */
+ dosify = 1; break;
+ case 'l': /* Translate end-of-line */
+ translate_eol = 1; break;
+ case o_ll:
+ translate_eol = 2; break;
+ case o_lf:
+ /* open a logfile */
+ /* allow multiple use of option but only last used */
+ if (logfile_path) {
+ free(logfile_path);
+ }
+ logfile_path = value;
+ break;
+ case o_la:
+ /* append to existing logfile */
+ if (negated)
+ logfile_append = 0;
+ else
+ logfile_append = 1;
+ break;
+ case o_li:
+ /* log all including informational messages */
+ if (negated)
+ logall = 0;
+ else
+ logall = 1;
+ break;
+#ifndef WINDLL
+ case 'L': /* Show license */
+ license();
+ RETURN(finish(ZE_OK));
+#endif
+ case 'm': /* Delete files added or updated in zip file */
+ dispose = 1; break;
+ case o_mm: /* To prevent use of -mm for -MM */
+ ZIPERR(ZE_PARMS, "-mm not supported, Must_Match is -MM");
+ dispose = 1; break;
+ case o_MM: /* Exit with error if input file can't be read */
+ bad_open_is_error = 1; break;
+ case 'n': /* Don't compress files with a special suffix */
+ special = value;
+ /* special = NULL; */ /* will be set at next argument */
+ break;
+ case o_nw: /* no wildcards - wildcards are handled like other characters */
+ no_wild = 1;
+ break;
+#if defined(AMIGA) || defined(MACOS)
+ case 'N': /* Get zipfile comments from AmigaDOS/MACOS filenotes */
+ filenotes = 1; break;
+#endif
+ case 'o': /* Set zip file time to time of latest file in it */
+ latest = 1; break;
+ case 'O': /* Set output file different than input archive */
+ out_path = ziptyp(value);
+ free(value);
+ have_out = 1;
+ break;
+ case 'p': /* Store path with name */
+ break; /* (do nothing as annoyance avoidance) */
+ case 'P': /* password for encryption */
+ if (key != NULL) {
+ free(key);
+ }
+#if CRYPT
+ key = value;
+ key_needed = 0;
+#else
+ ZIPERR(ZE_PARMS, "encryption not supported");
+#endif /* CRYPT */
+ break;
+#if defined(QDOS) || defined(QLZIP)
+ case 'Q':
+ qlflag = strtol(value, NULL, 10);
+ /* qlflag = strtol((p+1), &p, 10); */
+ /* p--; */
+ if (qlflag == 0) qlflag = 4;
+ free(value);
+ break;
+#endif
+ case 'q': /* Quiet operation */
+ noisy = 0;
+#ifdef MACOS
+ MacZip.MacZip_Noisy = false;
+#endif /* MACOS */
+ if (verbose) verbose--;
+ break;
+ case 'r': /* Recurse into subdirectories, match full path */
+ if (recurse == 2) {
+ ZIPERR(ZE_PARMS, "do not specify both -r and -R");
+ }
+ recurse = 1; break;
+ case 'R': /* Recurse into subdirectories, match filename */
+ if (recurse == 1) {
+ ZIPERR(ZE_PARMS, "do not specify both -r and -R");
+ }
+ recurse = 2; break;
+
+ case o_RE: /* Allow [list] matching (regex) */
+ allow_regex = 1; break;
+
+ case o_sc: /* show command line args */
+ show_args = 1; break;
+#ifdef UNICODE_TEST
+ case o_sC: /* create empty files from archive names */
+ create_files = 1;
+ show_files = 1; break;
+#endif
+ case o_sd: /* show debugging */
+ show_what_doing = 1; break;
+ case o_sf: /* show files to operate on */
+ if (!negated)
+ show_files = 1;
+ else
+ show_files = 2;
+ break;
+ case o_so: /* show all options */
+ show_options = 1; break;
+#ifdef UNICODE_SUPPORT
+ case o_su: /* -sf but also show Unicode if exists */
+ if (!negated)
+ show_files = 3;
+ else
+ show_files = 4;
+ break;
+ case o_sU: /* -sf but only show Unicode if exists or normal if not */
+ if (!negated)
+ show_files = 5;
+ else
+ show_files = 6;
+ break;
+#endif
+
+ case 's': /* enable split archives */
+ /* get the split size from value */
+ if (strcmp(value, "-") == 0) {
+ /* -s- do not allow splits */
+ split_method = -1;
+ } else {
+ split_size = ReadNumString(value);
+ if (split_size == (uzoff_t)-1) {
+ sprintf(errbuf, "bad split size: '%s'", value);
+ ZIPERR(ZE_PARMS, errbuf);
+ }
+ if (split_size == 0) {
+ /* do not allow splits */
+ split_method = -1;
+ } else {
+ if (split_method == 0) {
+ split_method = 1;
+ }
+ if (split_size < 0x400) {
+ /* < 1 KB there is no multiplier, assume MB */
+ split_size *= 0x100000;
+ }
+ /* By setting the minimum split size to 64 KB we avoid
+ not having enough room to write a header unsplit
+ which is required */
+ if (split_size < 0x400L * 64) {
+ /* split_size < 64K */
+ sprintf(errbuf, "minimum split size is 64 KB: '%s'", value);
+ free(value);
+ ZIPERR(ZE_PARMS, errbuf);
+ }
+ }
+ }
+ free(value);
+ break;
+ case o_sb: /* when pause for next split ring bell */
+ split_bell = 1;
+ break;
+ case o_sp: /* enable split select - pause splitting between splits */
+ use_descriptors = 1;
+ split_method = 2;
+ break;
+ case o_sv: /* be verbose about creating splits */
+ noisy_splits = 1;
+ break;
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(ATARI)
+ case 'S':
+ hidden_files = 1; break;
+#endif /* MSDOS || OS2 || WIN32 || ATARI */
+#ifdef MACOS
+ case 'S':
+ MacZip.IncludeInvisible = true; break;
+#endif /* MACOS */
+ case 't': /* Exclude files earlier than specified date */
+ {
+ int yyyy, mm, dd; /* results of sscanf() */
+
+ /* Support ISO 8601 & American dates */
+ if ((sscanf(value, "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3 &&
+ sscanf(value, "%2d%2d%4d", &mm, &dd, &yyyy) != 3) ||
+ mm < 1 || mm > 12 || dd < 1 || dd > 31) {
+ ZIPERR(ZE_PARMS,
+ "invalid date entered for -t option - use mmddyyyy or yyyy-mm-dd");
+ }
+ before = dostime(yyyy, mm, dd, 0, 0, 0);
+ }
+ free(value);
+ break;
+ case o_tt: /* Exclude files at or after specified date */
+ {
+ int yyyy, mm, dd; /* results of sscanf() */
+
+ /* Support ISO 8601 & American dates */
+ if ((sscanf(value, "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3 &&
+ sscanf(value, "%2d%2d%4d", &mm, &dd, &yyyy) != 3) ||
+ mm < 1 || mm > 12 || dd < 1 || dd > 31) {
+ ZIPERR(ZE_PARMS,
+ "invalid date entered for -tt option - use mmddyyyy or yyyy-mm-dd");
+ }
+ after = dostime(yyyy, mm, dd, 0, 0, 0);
+ }
+ free(value);
+ break;
+ case 'T': /* test zip file */
+ test = 1; break;
+ case o_TT: /* command path to use instead of 'unzip -t ' */
+ if (unzip_path)
+ free(unzip_path);
+ unzip_path = value;
+ break;
+ case 'U': /* Select archive entries to keep or operate on */
+ if (action != ADD) {
+ ZIPERR(ZE_PARMS, "specify just one action");
+ }
+ action = ARCHIVE;
+ break;
+#ifdef UNICODE_SUPPORT
+ case o_UN: /* Unicode */
+ if (abbrevmatch("quit", value, 0, 1)) {
+ /* Unicode path mismatch is error */
+ unicode_mismatch = 0;
+ } else if (abbrevmatch("warn", value, 0, 1)) {
+ /* warn of mismatches and continue */
+ unicode_mismatch = 1;
+ } else if (abbrevmatch("ignore", value, 0, 1)) {
+ /* ignore mismatches and continue */
+ unicode_mismatch = 2;
+ } else if (abbrevmatch("no", value, 0, 1)) {
+ /* no use Unicode path */
+ unicode_mismatch = 3;
+ } else if (abbrevmatch("escape", value, 0, 1)) {
+ /* escape all non-ASCII characters */
+ unicode_escape_all = 1;
+
+ } else if (abbrevmatch("UTF8", value, 0, 1)) {
+ /* force storing UTF-8 as standard per AppNote bit 11 */
+ utf8_force = 1;
+
+ } else {
+ zipwarn("-UN must be Quit, Warn, Ignore, No, Escape, or UTF8: ", value);
+
+ free(value);
+ ZIPERR(ZE_PARMS, "-UN (unicode) bad value");
+ }
+ free(value);
+ break;
+#endif
+ case 'u': /* Update zip file--overwrite only if newer */
+ if (action != ADD) {
+ ZIPERR(ZE_PARMS, "specify just one action");
+ }
+ action = UPDATE;
+ break;
+ case 'v': /* Either display version information or */
+ case o_ve: /* Mention oddities in zip file structure */
+ if (option == o_ve || /* --version */
+ (argcnt == 2 && strlen(args[1]) == 2)) { /* -v only */
+ /* display version */
+#ifndef WINDLL
+ version_info();
+#else
+ zipwarn("version information not supported for dll", "");
+#endif
+ RETURN(finish(ZE_OK));
+ } else {
+ noisy = 1;
+ verbose++;
+ }
+ break;
+#ifdef VMS
+ case 'C': /* Preserve case (- = down-case) all. */
+ if (negated)
+ { /* Down-case all. */
+ if ((vms_case_2 > 0) || (vms_case_5 > 0))
+ {
+ ZIPERR( ZE_PARMS, "Conflicting case directives (-C-)");
+ }
+ vms_case_2 = -1;
+ vms_case_5 = -1;
+ }
+ else
+ { /* Not negated. Preserve all. */
+ if ((vms_case_2 < 0) || (vms_case_5 < 0))
+ {
+ ZIPERR( ZE_PARMS, "Conflicting case directives (-C)");
+ }
+ vms_case_2 = 1;
+ vms_case_5 = 1;
+ }
+ break;
+ case o_C2: /* Preserve case (- = down-case) ODS2. */
+ if (negated)
+ { /* Down-case ODS2. */
+ if (vms_case_2 > 0)
+ {
+ ZIPERR( ZE_PARMS, "Conflicting case directives (-C2-)");
+ }
+ vms_case_2 = -1;
+ }
+ else
+ { /* Not negated. Preserve ODS2. */
+ if (vms_case_2 < 0)
+ {
+ ZIPERR( ZE_PARMS, "Conflicting case directives (-C2)");
+ }
+ vms_case_2 = 1;
+ }
+ break;
+ case o_C5: /* Preserve case (- = down-case) ODS5. */
+ if (negated)
+ { /* Down-case ODS5. */
+ if (vms_case_5 > 0)
+ {
+ ZIPERR( ZE_PARMS, "Conflicting case directives (-C5-)");
+ }
+ vms_case_5 = -1;
+ }
+ else
+ { /* Not negated. Preserve ODS5. */
+ if (vms_case_5 < 0)
+ {
+ ZIPERR( ZE_PARMS, "Conflicting case directives (-C5)");
+ }
+ vms_case_5 = 1;
+ }
+ break;
+ case 'V': /* Store in VMS format. (Record multiples.) */
+ vms_native = 1; break;
+ /* below does work with new parser but doesn't allow tracking
+ -VV separately, like adding a separate description */
+ /* vms_native++; break; */
+ case o_VV: /* Store in VMS specific format */
+ vms_native = 2; break;
+ case 'w': /* Append the VMS version number */
+ vmsver |= 1; break;
+ case o_ww: /* Append the VMS version number as ".nnn". */
+ vmsver |= 3; break;
+#endif /* VMS */
+ case o_ws: /* Wildcards do not include directory boundaries in matches */
+ wild_stop_at_dir = 1;
+ break;
+
+ case 'i': /* Include only the following files */
+ /* if nothing matches include list then still create an empty archive */
+ allow_empty_archive = 1;
+ case 'x': /* Exclude following files */
+ add_filter((int) option, value);
+ free(value);
+ break;
+#ifdef S_IFLNK
+ case 'y': /* Store symbolic links as such */
+ linkput = 1; break;
+#endif /* S_IFLNK */
+ case 'z': /* Edit zip file comment */
+ zipedit = 1; break;
+ case 'Z': /* Compression method */
+ if (abbrevmatch("deflate", value, 0, 1)) {
+ /* deflate */
+ method = DEFLATE;
+ } else if (abbrevmatch("store", value, 0, 1)) {
+ /* store */
+ method = STORE;
+ } else if (abbrevmatch("bzip2", value, 0, 1)) {
+ /* bzip2 */
+#ifdef BZIP2_SUPPORT
+ method = BZIP2;
+#else
+ ZIPERR(ZE_COMPERR, "Compression method bzip2 not enabled");
+#endif
+ } else {
+#ifdef BZIP2_SUPPORT
+ zipwarn("valid compression methods are: store, deflate, bzip2", "");
+#else
+ zipwarn("valid compression methods are: store, deflate)", "");
+#endif
+ zipwarn("unknown compression method found: ", value);
+ free(value);
+ ZIPERR(ZE_PARMS, "Option -Z (--compression-method): unknown method");
+ }
+ free(value);
+ break;
+#if defined(MSDOS) || defined(OS2)
+ case '$': /* Include volume label */
+ volume_label = 1; break;
+#endif
+#ifndef MACOS
+ case '@': /* read file names from stdin */
+ comment_stream = NULL;
+ s = 1; /* defer -@ until have zipfile name */
+ break;
+#endif /* !MACOS */
+ case 'X':
+ if (negated)
+ extra_fields = 2;
+ else
+ extra_fields = 0;
+ break;
+#ifdef OS2
+ case 'E':
+ /* use the .LONGNAME EA (if any) as the file's name. */
+ use_longname_ea = 1;
+ break;
+#endif
+#ifdef NTSD_EAS
+ case '!':
+ /* use security privilege overrides */
+ use_privileges = 1;
+ break;
+#endif
+#ifdef RISCOS
+ case '/':
+ exts2swap = value; /* override Zip$Exts */
+ break;
+#endif
+ case o_des:
+ use_descriptors = 1;
+ break;
+
+#ifdef ZIP64_SUPPORT
+ case o_z64: /* Force creation of Zip64 entries */
+ if (negated) {
+ force_zip64 = 0;
+ } else {
+ force_zip64 = 1;
+ }
+ break;
+#endif
+
+ case o_NON_OPTION_ARG:
+ /* not an option */
+ /* no more options as permuting */
+ /* just dash also ends up here */
+
+ if (recurse != 2 && kk == 0 && patterns == NULL) {
+ /* have all filters so convert filterlist to patterns array
+ as PROCNAME needs patterns array */
+ filterlist_to_patterns();
+ }
+
+ /* "--" stops arg processing for remaining args */
+ /* ignore only first -- */
+ if (strcmp(value, "--") == 0 && seen_doubledash == 0) {
+ /* -- */
+ seen_doubledash = 1;
+ if (kk == 0) {
+ ZIPERR(ZE_PARMS, "can't use -- before archive name");
+ }
+
+ /* just ignore as just marks what follows as non-option arguments */
+
+ } else if (kk == 6) {
+ /* value is R pattern */
+ add_filter((int)'R', value);
+ free(value);
+ if (first_listarg == 0) {
+ first_listarg = argnum;
+ }
+ } else switch (kk)
+ {
+ case 0:
+ /* first non-option arg is zipfile name */
+#if (!defined(MACOS) && !defined(WINDLL))
+ if (strcmp(value, "-") == 0) { /* output zipfile is dash */
+ /* just a dash */
+ zipstdout();
+ } else
+#endif /* !MACOS && !WINDLL */
+ {
+ /* name of zipfile */
+ if ((zipfile = ziptyp(value)) == NULL) {
+ ZIPERR(ZE_MEM, "was processing arguments");
+ }
+ /* read zipfile if exists */
+ /*
+ if ((r = readzipfile()) != ZE_OK) {
+ ZIPERR(r, zipfile);
+ }
+ */
+ free(value);
+ }
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Zipfile name '%s'\n", zipfile);
+ fflush(mesg);
+ }
+ /* if in_path not set, use zipfile path as usual for input */
+ /* in_path is used as the base path to find splits */
+ if (in_path == NULL) {
+ if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "was processing arguments");
+ }
+ strcpy(in_path, zipfile);
+ }
+ /* if out_path not set, use zipfile path as usual for output */
+ /* out_path is where the output archive is written */
+ if (out_path == NULL) {
+ if ((out_path = malloc(strlen(zipfile) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "was processing arguments");
+ }
+ strcpy(out_path, zipfile);
+ }
+ kk = 3;
+ if (s)
+ {
+ /* do -@ and get names from stdin */
+ /* should be able to read names from
+ stdin and output to stdout, but
+ this was not allowed in old code.
+ This check moved to kk = 3 case to fix. */
+ /* if (strcmp(zipfile, "-") == 0) {
+ ZIPERR(ZE_PARMS, "can't use - and -@ together");
+ }
+ */
+ while ((pp = getnam(stdin)) != NULL)
+ {
+ kk = 4;
+ if (recurse == 2) {
+ /* reading patterns from stdin */
+ add_filter((int)'R', pp);
+ } else {
+ /* file argument now processed later */
+ add_name(pp);
+ }
+ /*
+ if ((r = PROCNAME(pp)) != ZE_OK) {
+ if (r == ZE_MISS)
+ zipwarn("name not matched: ", pp);
+ else {
+ ZIPERR(r, pp);
+ }
+ }
+ */
+ free(pp);
+ }
+ s = 0;
+ }
+ if (recurse == 2) {
+ /* rest are -R patterns */
+ kk = 6;
+ }
+ break;
+
+ case 3: case 4:
+ /* no recurse and -r file names */
+ /* can't read filenames -@ and input - from stdin at
+ same time */
+ if (s == 1 && strcmp(value, "-") == 0) {
+ ZIPERR(ZE_PARMS, "can't read input (-) and filenames (-@) both from stdin");
+ }
+ /* add name to list for later processing */
+ add_name(value);
+ /*
+ if ((r = PROCNAME(value)) != ZE_OK) {
+ if (r == ZE_MISS)
+ zipwarn("name not matched: ", value);
+ else {
+ ZIPERR(r, value);
+ }
+ }
+ */
+ if (kk == 3) {
+ first_listarg = argnum;
+ kk = 4;
+ }
+ break;
+
+ } /* switch kk */
+ break;
+
+ default:
+ /* should never get here as get_option will exit if not in table */
+ sprintf(errbuf, "no such option ID: %ld", option);
+ ZIPERR(ZE_PARMS, errbuf);
+
+ } /* switch */
+ }
+
+
+ /* do processing of command line and one-time tasks */
+
+ /* Key not yet specified. If needed, get/verify it now. */
+ if (key_needed) {
+ if ((key = malloc(IZ_PWLEN+1)) == NULL) {
+ ZIPERR(ZE_MEM, "was getting encryption password");
+ }
+ r = encr_passwd(ZP_PW_ENTER, key, IZ_PWLEN+1, zipfile);
+ if (r != IZ_PW_ENTERED) {
+ if (r < IZ_PW_ENTERED)
+ r = ZE_PARMS;
+ ZIPERR(r, "was getting encryption password");
+ }
+ if (*key == '\0') {
+ ZIPERR(ZE_PARMS, "zero length password not allowed");
+ }
+ if ((e = malloc(IZ_PWLEN+1)) == NULL) {
+ ZIPERR(ZE_MEM, "was verifying encryption password");
+ }
+ r = encr_passwd(ZP_PW_VERIFY, e, IZ_PWLEN+1, zipfile);
+ if (r != IZ_PW_ENTERED && r != IZ_PW_SKIPVERIFY) {
+ free((zvoid *)e);
+ if (r < ZE_OK) r = ZE_PARMS;
+ ZIPERR(r, "was verifying encryption password");
+ }
+ r = ((r == IZ_PW_SKIPVERIFY) ? 0 : strcmp(key, e));
+ free((zvoid *)e);
+ if (r) {
+ ZIPERR(ZE_PARMS, "password verification failed");
+ }
+ }
+ if (key) {
+ /* if -P "" could get here */
+ if (*key == '\0') {
+ ZIPERR(ZE_PARMS, "zero length password not allowed");
+ }
+ }
+
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Command line read\n");
+ fflush(mesg);
+ }
+
+ /* show command line args */
+ if (show_args) {
+ fprintf(mesg, "command line:\n");
+ for (i = 0; args[i]; i++) {
+ fprintf(mesg, "'%s' ", args[i]);
+ }
+ fprintf(mesg, "\n");
+ ZIPERR(ZE_ABORT, "show command line");
+ }
+
+ /* show all options */
+ if (show_options) {
+ printf("available options:\n");
+ printf(" %-2s %-18s %-4s %-3s %-30s\n", "sh", "long", "val", "neg", "description");
+ printf(" %-2s %-18s %-4s %-3s %-30s\n", "--", "----", "---", "---", "-----------");
+ for (i = 0; options[i].option_ID; i++) {
+ printf(" %-2s %-18s ", options[i].shortopt, options[i].longopt);
+ switch (options[i].value_type) {
+ case o_NO_VALUE:
+ printf("%-4s ", "");
+ break;
+ case o_REQUIRED_VALUE:
+ printf("%-4s ", "req");
+ break;
+ case o_OPTIONAL_VALUE:
+ printf("%-4s ", "opt");
+ break;
+ case o_VALUE_LIST:
+ printf("%-4s ", "list");
+ break;
+ case o_ONE_CHAR_VALUE:
+ printf("%-4s ", "char");
+ break;
+ case o_NUMBER_VALUE:
+ printf("%-4s ", "num");
+ break;
+ default:
+ printf("%-4s ", "unk");
+ }
+ switch (options[i].negatable) {
+ case o_NEGATABLE:
+ printf("%-3s ", "neg");
+ break;
+ case o_NOT_NEGATABLE:
+ printf("%-3s ", "");
+ break;
+ default:
+ printf("%-3s ", "unk");
+ }
+ if (options[i].name)
+ printf("%-30s\n", options[i].name);
+ else
+ printf("\n");
+ }
+ RETURN(finish(ZE_OK));
+ }
+
+
+ /* open log file */
+ if (logfile_path) {
+ char mode[10];
+ char *p;
+ char *lastp;
+
+ /* if no extension add .log */
+ p = logfile_path;
+ /* find last / */
+ lastp = NULL;
+ for (p = logfile_path; (p = MBSRCHR(p, '/')) != NULL; p++) {
+ lastp = p;
+ }
+ if (lastp == NULL)
+ lastp = logfile_path;
+ if (MBSRCHR(lastp, '.') == NULL) {
+ /* add .log */
+ if ((p = malloc(strlen(logfile_path) + 5)) == NULL) {
+ ZIPERR(ZE_MEM, "logpath");
+ }
+ strcpy(p, logfile_path);
+ strcat(p, ".log");
+ free(logfile_path);
+ logfile_path = p;
+ }
+
+ if (logfile_append) {
+ sprintf(mode, "a");
+ } else {
+ sprintf(mode, "w");
+ }
+ if ((logfile = zfopen(logfile_path, mode)) == NULL) {
+ sprintf(errbuf, "could not open logfile '%s'", logfile_path);
+ ZIPERR(ZE_PARMS, errbuf);
+ }
+ {
+ /* At top put start time and command line */
+
+ /* get current time */
+ struct tm *now;
+ time_t clocktime;
+
+ time(&clocktime);
+ now = localtime(&clocktime);
+
+ fprintf(logfile, "---------\n");
+ fprintf(logfile, "Zip log opened %s", asctime(now));
+ fprintf(logfile, "command line arguments:\n ");
+ for (i = 1; args[i]; i++) {
+ size_t j;
+ int has_space = 0;
+
+ for (j = 0; j < strlen(args[i]); j++) {
+ if (isspace(args[i][j])) {
+ has_space = 1;
+ break;
+ }
+ }
+ if (has_space)
+ fprintf(logfile, "\"%s\" ", args[i]);
+ else
+ fprintf(logfile, "%s ", args[i]);
+ }
+ fprintf(logfile, "\n\n");
+ fflush(logfile);
+ }
+ } else {
+ /* only set logall if logfile open */
+ logall = 0;
+ }
+
+
+ if (split_method && out_path) {
+ /* if splitting, the archive name must have .zip extension */
+ int plen = strlen(out_path);
+ char *out_path_ext;
+
+#ifdef VMS
+ /* On VMS, adjust plen (and out_path_ext) to avoid the file version. */
+ plen -= strlen( vms_file_version( out_path));
+#endif /* def VMS */
+ out_path_ext = out_path+ plen- 4;
+
+ if (plen < 4 ||
+ out_path_ext[0] != '.' ||
+ toupper(out_path_ext[1]) != 'Z' ||
+ toupper(out_path_ext[2]) != 'I' ||
+ toupper(out_path_ext[3]) != 'P') {
+ ZIPERR(ZE_PARMS, "archive name must end in .zip for splits");
+ }
+ }
+
+
+ if (verbose && (dot_size == 0) && (dot_count == 0)) {
+ /* now default to default 10 MB dot size */
+ dot_size = 10 * 0x100000;
+ /* show all dots as before if verbose set and dot_size not set (dot_count = 0) */
+ /* maybe should turn off dots in default verbose mode */
+ /* dot_size = -1; */
+ }
+
+ /* done getting -R filters so convert filterlist if not done */
+ if (pcount && patterns == NULL) {
+ filterlist_to_patterns();
+ }
+
+#if (defined(MSDOS) || defined(OS2)) && !defined(WIN32)
+ if ((kk == 3 || kk == 4) && volume_label == 1) {
+ /* read volume label */
+ PROCNAME(NULL);
+ kk = 4;
+ }
+#endif
+
+ if (have_out && kk == 3) {
+ copy_only = 1;
+ action = ARCHIVE;
+ }
+
+ if (have_out && namecmp(in_path, out_path) == 0) {
+ sprintf(errbuf, "--out path must be different than in path: %s", out_path);
+ ZIPERR(ZE_PARMS, errbuf);
+ }
+
+ if (fix && diff_mode) {
+ ZIPERR(ZE_PARMS, "can't use --diff (-DF) with fix (-F or -FF)");
+ }
+
+ if (action == ARCHIVE && !have_out && !show_files) {
+ ZIPERR(ZE_PARMS, "-U (--copy) requires -O (--out)");
+ }
+
+ if (fix && !have_out) {
+ zipwarn("fix options -F and -FF require --out:\n",
+ " zip -F indamagedarchive --out outfixedarchive");
+ ZIPERR(ZE_PARMS, "fix options require --out");
+ }
+
+ if (fix && !copy_only) {
+ ZIPERR(ZE_PARMS, "no other actions allowed when fixing archive (-F or -FF)");
+ }
+
+ if (!have_out && diff_mode) {
+ ZIPERR(ZE_PARMS, "-DF (--diff) requires -O (--out)");
+ }
+
+ if (diff_mode && (action == ARCHIVE || action == DELETE)) {
+ ZIPERR(ZE_PARMS, "can't use --diff (-DF) with -d or -U");
+ }
+
+ if (action != ARCHIVE && (recurse == 2 || pcount) && first_listarg == 0 &&
+ !filelist && (kk < 3 || (action != UPDATE && action != FRESHEN))) {
+ ZIPERR(ZE_PARMS, "nothing to select from");
+ }
+
+/*
+ -------------------------------------
+ end of new command line code
+ -------------------------------------
+*/
+
+#if (!defined(MACOS) && !defined(WINDLL))
+ if (kk < 3) { /* zip used as filter */
+ zipstdout();
+ comment_stream = NULL;
+ if ((r = procname("-", 0)) != ZE_OK) {
+ if (r == ZE_MISS) {
+ if (bad_open_is_error) {
+ zipwarn("name not matched: ", "-");
+ ZIPERR(ZE_OPEN, "-");
+ } else {
+ zipwarn("name not matched: ", "-");
+ }
+ } else {
+ ZIPERR(r, "-");
+ }
+ }
+ kk = 4;
+ if (s) {
+ ZIPERR(ZE_PARMS, "can't use - and -@ together");
+ }
+ }
+#endif /* !MACOS && !WINDLL */
+
+ if (zipfile && !strcmp(zipfile, "-")) {
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Zipping to stdout\n");
+ fflush(mesg);
+ }
+ zip_to_stdout = 1;
+ }
+
+ /* Check option combinations */
+ if (special == NULL) {
+ ZIPERR(ZE_PARMS, "missing suffix list");
+ }
+ if (level == 9 || !strcmp(special, ";") || !strcmp(special, ":"))
+ special = NULL; /* compress everything */
+
+ if (action == DELETE && (method != BEST || dispose || recurse ||
+ key != NULL || comadd || zipedit)) {
+ zipwarn("invalid option(s) used with -d; ignored.","");
+ /* reset flags - needed? */
+ method = BEST;
+ dispose = 0;
+ recurse = 0;
+ if (key != NULL) {
+ free((zvoid *)key);
+ key = NULL;
+ }
+ comadd = 0;
+ zipedit = 0;
+ }
+ if (action == ARCHIVE && (method != BEST || dispose || recurse ||
+ comadd || zipedit)) {
+ zipwarn("can't set method, move, recurse, or comments with copy mode.","");
+ /* reset flags - needed? */
+ method = BEST;
+ dispose = 0;
+ recurse = 0;
+ comadd = 0;
+ zipedit = 0;
+ }
+ if (linkput && dosify)
+ {
+ zipwarn("can't use -y with -k, -y ignored", "");
+ linkput = 0;
+ }
+ if (fix == 1 && adjust)
+ {
+ zipwarn("can't use -F with -A, -F ignored", "");
+ fix = 0;
+ }
+ if (fix == 2 && adjust)
+ {
+ zipwarn("can't use -FF with -A, -FF ignored", "");
+ fix = 0;
+ }
+ if (test && zip_to_stdout) {
+ test = 0;
+ zipwarn("can't use -T on stdout, -T ignored", "");
+ }
+ if (split_method && (fix || adjust)) {
+ ZIPERR(ZE_PARMS, "can't create split archive while fixing or adjusting\n");
+ }
+ if (split_method && (d || zip_to_stdout)) {
+ ZIPERR(ZE_PARMS, "can't create split archive with -d or -g or on stdout\n");
+ }
+ if ((action != ADD || d) && filesync) {
+ ZIPERR(ZE_PARMS, "can't use -d, -f, -u, -U, or -g with filesync -FS\n");
+ }
+ if ((action != ADD || d) && zip_to_stdout) {
+ ZIPERR(ZE_PARMS, "can't use -d, -f, -u, -U, or -g on stdout\n");
+ }
+#if defined(EBCDIC) && !defined(OS390)
+ if (aflag==ASCII && !translate_eol) {
+ /* Translation to ASCII implies EOL translation!
+ * (on OS390, consistent EOL translation is controlled separately)
+ * The default translation mode is "UNIX" mode (single LF terminators).
+ */
+ translate_eol = 2;
+ }
+#endif
+#ifdef CMS_MVS
+ if (aflag==ASCII && bflag)
+ ZIPERR(ZE_PARMS, "can't use -a with -B");
+#endif
+#ifdef VMS
+ if (!extra_fields && vms_native)
+ {
+ zipwarn("can't use -V with -X, -V ignored", "");
+ vms_native = 0;
+ }
+ if (vms_native && translate_eol)
+ ZIPERR(ZE_PARMS, "can't use -V with -l or -ll");
+#endif
+
+ if (noisy) {
+ if (fix == 1)
+ zipmessage("Fix archive (-F) - assume mostly intact archive", "");
+ else if (fix == 2)
+ zipmessage("Fix archive (-FF) - salvage what can", "");
+ }
+
+ /* Read old archive */
+
+ /* Now read the zip file here instead of when doing args above */
+ /* Only read the central directory and build zlist */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Reading archive\n");
+ fflush(mesg);
+ }
+
+
+
+
+ /* If -FF we do it all here */
+ if (fix == 2) {
+
+ /* Open zip file and temporary output file */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Open zip file and create temp file (-FF)\n");
+ fflush(mesg);
+ }
+ diag("opening zip file and creating temporary zip file");
+ x = NULL;
+ tempzn = 0;
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Creating new zip file (-FF)\n");
+ fflush(mesg);
+ }
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+ {
+ int yd;
+ int i;
+
+ /* use mkstemp to avoid race condition and compiler warning */
+
+ if (tempath != NULL)
+ {
+ /* if -b used to set temp file dir use that for split temp */
+ if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, tempath);
+ if (lastchar(tempzip) != '/')
+ strcat(tempzip, "/");
+ }
+ else
+ {
+ /* create path by stripping name and appending template */
+ if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, zipfile);
+ for(i = strlen(tempzip); i > 0; i--) {
+ if (tempzip[i - 1] == '/')
+ break;
+ }
+ tempzip[i] = '\0';
+ }
+ strcat(tempzip, "ziXXXXXX");
+
+ if ((yd = mkstemp(tempzip)) == EOF) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ }
+#else
+ if ((tempzip = tempname(zipfile)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+#endif
+
+#if (!defined(VMS) && !defined(CMS_MVS))
+ /* Use large buffer to speed up stdio: */
+#if (defined(_IOFBF) || !defined(BUFSIZ))
+ zipbuf = (char *)malloc(ZBSZ);
+#else
+ zipbuf = (char *)malloc(BUFSIZ);
+#endif
+ if (zipbuf == NULL) {
+ ZIPERR(ZE_MEM, tempzip);
+ }
+# ifdef _IOFBF
+ setvbuf(y, zipbuf, _IOFBF, ZBSZ);
+# else
+ setbuf(y, zipbuf);
+# endif /* _IOBUF */
+#endif /* !VMS && !CMS_MVS */
+
+
+ if ((r = readzipfile()) != ZE_OK) {
+ ZIPERR(r, zipfile);
+ }
+
+ /* Write central directory and end header to temporary zip */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Writing central directory (-FF)\n");
+ fflush(mesg);
+ }
+ diag("writing central directory");
+ k = 0; /* keep count for end header */
+ c = tempzn; /* get start of central */
+ n = t = 0;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ {
+ if ((r = putcentral(z)) != ZE_OK) {
+ ZIPERR(r, tempzip);
+ }
+ tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
+ n += z->len;
+ t += z->siz;
+ k++;
+ }
+ if (zcount == 0)
+ zipwarn("zip file empty", "");
+ t = tempzn - c; /* compute length of central */
+ diag("writing end of central directory");
+ if ((r = putend(k, t, c, zcomlen, zcomment)) != ZE_OK) {
+ ZIPERR(r, tempzip);
+ }
+ if (fclose(y)) {
+ ZIPERR(d ? ZE_WRITE : ZE_TEMP, tempzip);
+ }
+ if (in_file != NULL) {
+ fclose(in_file);
+ in_file = NULL;
+ }
+
+ /* Replace old zip file with new zip file, leaving only the new one */
+ if (strcmp(zipfile, "-") && !d)
+ {
+ diag("replacing old zip file with new zip file");
+ if ((r = replace(out_path, tempzip)) != ZE_OK)
+ {
+ zipwarn("new zip file left as: ", tempzip);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ZIPERR(r, "was replacing the original zip file");
+ }
+ free((zvoid *)tempzip);
+ }
+ tempzip = NULL;
+ if (zip_attributes && strcmp(zipfile, "-")) {
+ setfileattr(out_path, zip_attributes);
+#ifdef VMS
+ /* If the zip file existed previously, restore its record format: */
+ if (x != NULL)
+ (void)VMSmunch(out_path, RESTORE_RTYPE, NULL);
+#endif
+ }
+
+ set_filetype(out_path);
+
+ /* finish logfile (it gets closed in freeup() called by finish()) */
+ if (logfile) {
+ struct tm *now;
+ time_t clocktime;
+
+ fprintf(logfile, "\nTotal %ld entries (", files_total);
+ DisplayNumString(logfile, bytes_total);
+ fprintf(logfile, " bytes)");
+
+ /* get current time */
+ time(&clocktime);
+ now = localtime(&clocktime);
+ fprintf(logfile, "\nDone %s", asctime(now));
+ fflush(logfile);
+ }
+
+ RETURN(finish(ZE_OK));
+ }
+
+
+
+ /* read zipfile if exists */
+ if ((r = readzipfile()) != ZE_OK) {
+ ZIPERR(r, zipfile);
+ }
+
+#ifndef UTIL
+ if (split_method == -1) {
+ split_method = 0;
+ } else if (!fix && split_method == 0 && total_disks > 1) {
+ /* if input archive is multi-disk and splitting has not been
+ enabled or disabled (split_method == -1), then automatically
+ set split size to same as first input split */
+ zoff_t size = 0;
+
+ in_split_path = get_in_split_path(in_path, 0);
+
+ if (filetime(in_split_path, NULL, &size, NULL) == 0) {
+ zipwarn("Could not get info for input split: ", in_split_path);
+ return ZE_OPEN;
+ }
+ split_method = 1;
+ split_size = (uzoff_t) size;
+
+ free(in_split_path);
+ in_split_path = NULL;
+ }
+
+ if (noisy_splits && split_size > 0)
+ zipmessage("splitsize = ", zip_fuzofft(split_size, NULL, NULL));
+#endif
+
+ /* so disk display starts at 1, will be updated when entries are read */
+ current_in_disk = 0;
+
+ /* no input zipfile and showing contents */
+ if (!zipfile_exists && show_files && (kk == 3 || action == ARCHIVE)) {
+ ZIPERR(ZE_OPEN, zipfile);
+ }
+
+ if (zcount == 0 && (action != ADD || d)) {
+ zipwarn(zipfile, " not found or empty");
+ }
+
+ if (have_out && kk == 3) {
+ /* no input paths so assume copy mode and match everything if --out */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ z->mark = pcount ? filter(z->zname, filter_match_case) : 1;
+ }
+ }
+
+ /* Scan for new files */
+
+ /* Process file arguments from command line */
+ if (filelist) {
+ if (action == ARCHIVE) {
+ /* find in archive */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Scanning archive entries\n");
+ fflush(mesg);
+ }
+ for (; filelist; ) {
+ if ((r = proc_archive_name(filelist->name, filter_match_case)) != ZE_OK) {
+ if (r == ZE_MISS) {
+ char *n = NULL;
+#ifdef WIN32
+ /* Win9x console always uses OEM character coding, and
+ WinNT console is set to OEM charset by default, too */
+ if ((n = malloc(strlen(filelist->name) + 1)) == NULL)
+ ZIPERR(ZE_MEM, "name not matched error");
+ INTERN_TO_OEM(filelist->name, n);
+#else
+ n = filelist->name;
+#endif
+ zipwarn("not in archive: ", n);
+#ifdef WIN32
+ free(n);
+#endif
+ }
+ else {
+ ZIPERR(r, filelist->name);
+ }
+ }
+ free(filelist->name);
+ filearg = filelist;
+ filelist = filelist->next;
+ free(filearg);
+ }
+ } else {
+ /* try find matching files on OS first then try find entries in archive */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Scanning files\n");
+ fflush(mesg);
+ }
+ for (; filelist; ) {
+ if ((r = PROCNAME(filelist->name)) != ZE_OK) {
+ if (r == ZE_MISS) {
+ if (bad_open_is_error) {
+ zipwarn("name not matched: ", filelist->name);
+ ZIPERR(ZE_OPEN, filelist->name);
+ } else {
+ zipwarn("name not matched: ", filelist->name);
+ }
+ } else {
+ ZIPERR(r, filelist->name);
+ }
+ }
+ free(filelist->name);
+ filearg = filelist;
+ filelist = filelist->next;
+ free(filearg);
+ }
+ }
+ }
+
+ /* recurse from current directory for -R */
+ if (recurse == 2) {
+#ifdef AMIGA
+ if ((r = PROCNAME("")) != ZE_OK)
+#else
+ if ((r = PROCNAME(".")) != ZE_OK)
+#endif
+ {
+ if (r == ZE_MISS) {
+ if (bad_open_is_error) {
+ zipwarn("name not matched: ", "current directory for -R");
+ ZIPERR(ZE_OPEN, "-R");
+ } else {
+ zipwarn("name not matched: ", "current directory for -R");
+ }
+ } else {
+ ZIPERR(r, "-R");
+ }
+ }
+ }
+
+
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Applying filters\n");
+ fflush(mesg);
+ }
+ /* Clean up selections ("3 <= kk <= 5" now) */
+ if (kk != 4 && first_listarg == 0 &&
+ (action == UPDATE || action == FRESHEN)) {
+ /* if -u or -f with no args, do all, but, when present, apply filters */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ z->mark = pcount ? filter(z->zname, filter_match_case) : 1;
+#ifdef DOS
+ if (z->mark) z->dosflag = 1; /* force DOS attribs for incl. names */
+#endif
+ }
+ }
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Checking dups\n");
+ fflush(mesg);
+ }
+ if ((r = check_dup()) != ZE_OK) { /* remove duplicates in found list */
+ if (r == ZE_PARMS) {
+ ZIPERR(r, "cannot repeat names in zip file");
+ }
+ else {
+ ZIPERR(r, "was processing list of files");
+ }
+ }
+
+ if (zcount)
+ free((zvoid *)zsort);
+
+
+/*
+ * XXX make some kind of mktemppath() function for each OS.
+ */
+
+#ifndef VM_CMS
+/* For CMS, leave tempath NULL. A-disk will be used as default. */
+ /* If -b not specified, make temporary path the same as the zip file */
+#if defined(MSDOS) || defined(__human68k__) || defined(AMIGA)
+ if (tempath == NULL && ((p = MBSRCHR(zipfile, '/')) != NULL ||
+# ifdef MSDOS
+ (p = MBSRCHR(zipfile, '\\')) != NULL ||
+# endif /* MSDOS */
+ (p = MBSRCHR(zipfile, ':')) != NULL))
+ {
+ if (*p == ':')
+ p++;
+#else
+#ifdef RISCOS
+ if (tempath == NULL && (p = MBSRCHR(zipfile, '.')) != NULL)
+ {
+#else
+#ifdef QDOS
+ if (tempath == NULL && (p = LastDir(zipfile)) != NULL)
+ {
+#else
+ if (tempath == NULL && (p = MBSRCHR(zipfile, '/')) != NULL)
+ {
+#endif /* QDOS */
+#endif /* RISCOS */
+#endif /* MSDOS || __human68k__ || AMIGA */
+ if ((tempath = (char *)malloc((int)(p - zipfile) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "was processing arguments");
+ }
+ r = *p; *p = 0;
+ strcpy(tempath, zipfile);
+ *p = (char)r;
+ }
+#endif /* VM_CMS */
+
+#if (defined(IZ_CHECK_TZ) && defined(USE_EF_UT_TIME))
+ if (!zp_tz_is_valid) {
+ zipwarn("TZ environment variable not found, cannot use UTC times!!","");
+ }
+#endif /* IZ_CHECK_TZ && USE_EF_UT_TIME */
+
+ /* For each marked entry, if not deleting, check if it exists, and if
+ updating or freshening, compare date with entry in old zip file.
+ Unmark if it doesn't exist or is too old, else update marked count. */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Scanning files to update\n");
+ fflush(mesg);
+ }
+#ifdef MACOS
+ PrintStatProgress("Getting file information ...");
+#endif
+ diag("stating marked entries");
+ k = 0; /* Initialize marked count */
+ scan_started = 0;
+ scan_count = 0;
+ all_current = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ /* if already displayed Scanning files in newname() then continue dots */
+ if (noisy && scan_last) {
+ scan_count++;
+ if (scan_count % 100 == 0) {
+ time_t current = time(NULL);
+
+ if (current - scan_last > scan_dot_time) {
+ if (scan_started == 0) {
+ scan_started = 1;
+ fprintf(mesg, " ");
+ fflush(mesg);
+ }
+ scan_last = current;
+ fprintf(mesg, ".");
+ fflush(mesg);
+ }
+ }
+ }
+ z->current = 0;
+ if (!(z->mark)) {
+ /* if something excluded run through the list to catch deletions */
+ all_current = 0;
+ }
+ if (z->mark) {
+#ifdef USE_EF_UT_TIME
+ iztimes f_utim, z_utim;
+ ulg z_tim;
+#endif /* USE_EF_UT_TIME */
+ Trace((stderr, "zip diagnostics: marked file=%s\n", z->oname));
+
+ csize = z->siz;
+ usize = z->len;
+ if (action == DELETE) {
+ /* only delete files in date range */
+#ifdef USE_EF_UT_TIME
+ z_tim = (get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+ unix2dostime(&z_utim.mtime) : z->tim;
+#else /* !USE_EF_UT_TIME */
+# define z_tim z->tim
+#endif /* ?USE_EF_UT_TIME */
+ if (z_tim < before || (after && z_tim >= after)) {
+ /* include in archive */
+ z->mark = 0;
+ } else {
+ /* delete file */
+ files_total++;
+ /* ignore len in old archive and update to current size */
+ z->len = usize;
+ if (csize != (uzoff_t) -1 && csize != (uzoff_t) -2)
+ bytes_total += csize;
+ k++;
+ }
+ } else if (action == ARCHIVE) {
+ /* only keep files in date range */
+#ifdef USE_EF_UT_TIME
+ z_tim = (get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+ unix2dostime(&z_utim.mtime) : z->tim;
+#else /* !USE_EF_UT_TIME */
+# define z_tim z->tim
+#endif /* ?USE_EF_UT_TIME */
+ if (z_tim < before || (after && z_tim >= after)) {
+ /* exclude from archive */
+ z->mark = 0;
+ } else {
+ /* keep file */
+ files_total++;
+ /* ignore len in old archive and update to current size */
+ z->len = usize;
+ if (csize != (uzoff_t) -1 && csize != (uzoff_t) -2)
+ bytes_total += csize;
+ k++;
+ }
+ } else {
+ int isdirname = 0;
+
+ if (z->name && (z->name)[strlen(z->name) - 1] == '/') {
+ isdirname = 1;
+ }
+
+# if defined(UNICODE_SUPPORT) && defined(WIN32)
+ if (!no_win32_wide) {
+ if (z->namew == NULL) {
+ if (z->uname != NULL)
+ z->namew = utf8_to_wchar_string(z->uname);
+ else
+ z->namew = local_to_wchar_string(z->name);
+ }
+ }
+# endif
+
+#ifdef USE_EF_UT_TIME
+# if defined(UNICODE_SUPPORT) && defined(WIN32)
+ if (!no_win32_wide)
+ tf = filetimew(z->namew, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
+ else
+ tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
+# else
+ tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, &f_utim);
+# endif
+#else /* !USE_EF_UT_TIME */
+# if defined(UNICODE_SUPPORT) && defined(WIN32)
+ if (!no_win32_wide)
+ tf = filetimew(z->namew, (ulg *)NULL, (zoff_t *)&usize, NULL);
+ else
+ tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+# else
+ tf = filetime(z->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+# endif
+#endif /* ?USE_EF_UT_TIME */
+ if (tf == 0)
+ /* entry that is not on OS */
+ all_current = 0;
+ if (tf == 0 ||
+ tf < before || (after && tf >= after) ||
+ ((action == UPDATE || action == FRESHEN) &&
+#ifdef USE_EF_UT_TIME
+ ((get_ef_ut_ztime(z, &z_utim) & EB_UT_FL_MTIME) ?
+ f_utim.mtime <= ROUNDED_TIME(z_utim.mtime) : tf <= z->tim)
+#else /* !USE_EF_UT_TIME */
+ tf <= z->tim
+#endif /* ?USE_EF_UT_TIME */
+ ))
+ {
+ z->mark = comadd ? 2 : 0;
+ z->trash = tf && tf >= before &&
+ (after ==0 || tf < after); /* delete if -um or -fm */
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %s %s\n", z->oname,
+ z->trash ? "up to date" : "missing or early");
+ if (logfile)
+ fprintf(logfile, "zip diagnostic: %s %s\n", z->oname,
+ z->trash ? "up to date" : "missing or early");
+ }
+ else if (diff_mode && tf == z->tim &&
+ ((isdirname && (zoff_t)usize == -1) || (usize == z->len))) {
+ /* if in diff mode only include if file time or size changed */
+ /* usize is -1 for directories */
+ z->mark = 0;
+ }
+ else {
+ /* usize is -1 for directories and -2 for devices */
+ if (tf == z->tim &&
+ ((z->len == 0 && (zoff_t)usize == -1)
+ || usize == z->len)) {
+ /* FileSync uses the current flag */
+ /* Consider an entry current if file time is the same
+ and entry size is 0 and a directory on the OS
+ or the entry size matches the OS size */
+ z->current = 1;
+ } else {
+ all_current = 0;
+ }
+ files_total++;
+ if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2)
+ /* ignore len in old archive and update to current size */
+ z->len = usize;
+ else
+ z->len = 0;
+ if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2)
+ bytes_total += usize;
+ k++;
+ }
+ }
+ }
+ }
+
+ /* Remove entries from found list that do not exist or are too old */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: fcount = %u\n", (unsigned)fcount);
+ fflush(mesg);
+ }
+
+ diag("stating new entries");
+ scan_count = 0;
+ scan_started = 0;
+ Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount));
+ for (f = found; f != NULL;) {
+ Trace((stderr, "zip diagnostic: new file=%s\n", f->oname));
+
+ if (noisy) {
+ /* if updating archive and update was quick, scanning for new files
+ can still take a long time */
+ if (!zip_to_stdout && scan_last == 0 && scan_count % 100 == 0) {
+ time_t current = time(NULL);
+
+ if (current - scan_start > scan_delay) {
+ fprintf(mesg, "Scanning files ");
+ fflush(mesg);
+ mesg_line_started = 1;
+ scan_last = current;
+ }
+ }
+ /* if already displayed Scanning files in newname() or above then continue dots */
+ if (scan_last) {
+ scan_count++;
+ if (scan_count % 100 == 0) {
+ time_t current = time(NULL);
+
+ if (current - scan_last > scan_dot_time) {
+ if (scan_started == 0) {
+ scan_started = 1;
+ fprintf(mesg, " ");
+ fflush(mesg);
+ }
+ scan_last = current;
+ fprintf(mesg, ".");
+ fflush(mesg);
+ }
+ }
+ }
+ }
+ tf = 0;
+ if (action != DELETE && action != FRESHEN) {
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ if (!no_win32_wide)
+ tf = filetimew(f->namew, (ulg *)NULL, (zoff_t *)&usize, NULL);
+ else
+ tf = filetime(f->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+#else
+ tf = filetime(f->name, (ulg *)NULL, (zoff_t *)&usize, NULL);
+#endif
+ }
+
+ if (action == DELETE || action == FRESHEN ||
+ tf == 0 ||
+ tf < before || (after && tf >= after) ||
+ (namecmp(f->zname, zipfile) == 0 && !zip_to_stdout)
+ )
+ f = fexpel(f);
+ else {
+ /* ??? */
+ files_total++;
+ f->usize = 0;
+ if (usize != (uzoff_t) -1 && usize != (uzoff_t) -2) {
+ bytes_total += usize;
+ f->usize = usize;
+ }
+ f = f->nxt;
+ }
+ }
+ if (mesg_line_started) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ }
+#ifdef MACOS
+ PrintStatProgress("done");
+#endif
+
+ if (show_files) {
+ uzoff_t count = 0;
+ uzoff_t bytes = 0;
+
+ if (noisy) {
+ fflush(mesg);
+ }
+
+ if (noisy && (show_files == 1 || show_files == 3 || show_files == 5)) {
+ /* sf, su, sU */
+ if (mesg_line_started) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ }
+ if (kk == 3)
+ /* -sf alone */
+ fprintf(mesg, "Archive contains:\n");
+ else if (action == DELETE)
+ fprintf(mesg, "Would Delete:\n");
+ else if (action == FRESHEN)
+ fprintf(mesg, "Would Freshen:\n");
+ else if (action == ARCHIVE)
+ fprintf(mesg, "Would Copy:\n");
+ else
+ fprintf(mesg, "Would Add/Update:\n");
+ fflush(mesg);
+ }
+
+ if (logfile) {
+ if (logfile_line_started) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ }
+ if (kk == 3)
+ /* -sf alone */
+ fprintf(logfile, "Archive contains:\n");
+ else if (action == DELETE)
+ fprintf(logfile, "Would Delete:\n");
+ else if (action == FRESHEN)
+ fprintf(logfile, "Would Freshen:\n");
+ else if (action == ARCHIVE)
+ fprintf(logfile, "Would Copy:\n");
+ else
+ fprintf(logfile, "Would Add/Update:\n");
+ fflush(logfile);
+ }
+
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (z->mark || kk == 3) {
+ count++;
+ if ((zoff_t)z->len > 0)
+ bytes += z->len;
+ if (noisy && (show_files == 1 || show_files == 3))
+ /* sf, su */
+ fprintf(mesg, " %s\n", z->oname);
+ if (logfile && !(show_files == 5 || show_files == 6))
+ /* not sU or sU- show normal name in log */
+ fprintf(logfile, " %s\n", z->oname);
+
+#ifdef UNICODE_TEST
+ if (create_files) {
+ int r;
+ int dir = 0;
+ FILE *f;
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ char *fn = NULL;
+ wchar_t *fnw = NULL;
+
+ if (!no_win32_wide) {
+ if ((fnw = malloc((wcslen(z->znamew) + 120) * sizeof(wchar_t))) == NULL)
+ ZIPERR(ZE_MEM, "sC");
+ wcscpy(fnw, L"testdir/");
+ wcscat(fnw, z->znamew);
+ if (fnw[wcslen(fnw) - 1] == '/')
+ dir = 1;
+ if (dir)
+ r = _wmkdir(fnw);
+ else
+ f = _wfopen(fnw, L"w");
+ } else {
+ if ((fn = malloc(strlen(z->zname) + 120)) == NULL)
+ ZIPERR(ZE_MEM, "sC");
+ strcpy(fn, "testdir/");
+ strcat(fn, z->zname);
+ if (fn[strlen(fn) - 1] == '/')
+ dir = 1;
+ if (dir)
+ r = mkdir(fn);
+ else
+ f = fopen(fn, "w");
+ }
+#else
+ char *fn = NULL;
+ if ((fn = malloc(strlen(z->zname) + 120)) == NULL)
+ ZIPERR(ZE_MEM, "sC");
+ strcpy(fn, "testdir/");
+ if (z->uname)
+ strcat(fn, z->uname);
+ else
+ strcat(fn, z->zname);
+
+ if (fn[strlen(fn) - 1] == '/')
+ dir = 1;
+ if (dir)
+ r = mkdir(fn, 0777);
+ else
+ f = fopen(fn, "w");
+#endif
+ if (dir) {
+ if (r) {
+ if (errno != 17) {
+ printf(" - could not create directory testdir/%s\n", z->oname);
+ perror(" dir");
+ }
+ } else {
+ printf(" - created directory testdir/%s\n", z->oname);
+ }
+ } else {
+ if (f == NULL) {
+ printf(" - could not open testdir/%s\n", z->oname);
+ perror(" file");
+ } else {
+ fclose(f);
+ printf(" - created testdir/%s\n", z->oname);
+ if (z->uname)
+ printf(" u - created testdir/%s\n", z->uname);
+ }
+ }
+ }
+#endif
+#ifdef UNICODE_SUPPORT
+ if (show_files == 3 || show_files == 4) {
+ /* su, su- */
+ /* Include escaped Unicode name if exists under standard name */
+ if (z->ouname) {
+ if (noisy && show_files == 3)
+ fprintf(mesg, " Escaped Unicode: %s\n", z->ouname);
+ if (logfile)
+ fprintf(logfile, " Escaped Unicode: %s\n", z->ouname);
+ }
+ }
+ if (show_files == 5 || show_files == 6) {
+ /* sU, sU- */
+ /* Display only escaped Unicode name if exists or standard name */
+ if (z->ouname) {
+ /* Unicode name */
+ if (noisy && show_files == 5) {
+ fprintf(mesg, " %s\n", z->ouname);
+ }
+ if (logfile) {
+ fprintf(logfile, " %s\n", z->ouname);
+ }
+ } else {
+ /* No Unicode name so use standard name */
+ if (noisy && show_files == 5) {
+ fprintf(mesg, " %s\n", z->oname);
+ }
+ if (logfile) {
+ fprintf(logfile, " %s\n", z->oname);
+ }
+ }
+ }
+#endif
+ }
+ }
+ for (f = found; f != NULL; f = f->nxt) {
+ count++;
+ if ((zoff_t)f->usize > 0)
+ bytes += f->usize;
+#ifdef UNICODE_SUPPORT
+ if (unicode_escape_all) {
+ char *escaped_unicode;
+ escaped_unicode = local_to_escape_string(f->zname);
+ if (noisy && (show_files == 1 || show_files == 3 || show_files == 5))
+ /* sf, su, sU */
+ fprintf(mesg, " %s\n", escaped_unicode);
+ if (logfile)
+ fprintf(logfile, " %s\n", escaped_unicode);
+ free(escaped_unicode);
+ } else {
+#endif
+ if (noisy && (show_files == 1 || show_files == 3 || show_files == 5))
+ /* sf, su, sU */
+ fprintf(mesg, " %s\n", f->oname);
+ if (logfile)
+ fprintf(logfile, " %s\n", f->oname);
+#ifdef UNICODE_SUPPORT
+ }
+#endif
+ }
+ if (noisy || logfile == NULL)
+ fprintf(mesg, "Total %s entries (%s bytes)\n",
+ zip_fuzofft(count, NULL, NULL),
+ zip_fuzofft(bytes, NULL, NULL));
+ if (logfile)
+ fprintf(logfile, "Total %s entries (%s bytes)\n",
+ zip_fuzofft(count, NULL, NULL),
+ zip_fuzofft(bytes, NULL, NULL));
+ RETURN(finish(ZE_OK));
+ }
+
+ /* Make sure there's something left to do */
+ if (k == 0 && found == NULL && !diff_mode &&
+ !(zfiles == NULL && allow_empty_archive) &&
+ !(zfiles != NULL &&
+ (latest || fix || adjust || junk_sfx || comadd || zipedit))) {
+ if (test && (zfiles != NULL || zipbeg != 0)) {
+#ifndef WINDLL
+ check_zipfile(zipfile, argv[0]);
+#endif
+ RETURN(finish(ZE_OK));
+ }
+ if (action == UPDATE || action == FRESHEN) {
+ RETURN(finish(ZE_NONE));
+ }
+ else if (zfiles == NULL && (latest || fix || adjust || junk_sfx)) {
+ ZIPERR(ZE_NAME, zipfile);
+ }
+#ifndef WINDLL
+ else if (recurse && (pcount == 0) && (first_listarg > 0)) {
+#ifdef VMS
+ strcpy(errbuf, "try: zip \"");
+ for (i = 1; i < (first_listarg - 1); i++)
+ strcat(strcat(errbuf, args[i]), "\" ");
+ strcat(strcat(errbuf, args[i]), " *.* -i");
+#else /* !VMS */
+ strcpy(errbuf, "try: zip");
+ for (i = 1; i < first_listarg; i++)
+ strcat(strcat(errbuf, " "), args[i]);
+# ifdef AMIGA
+ strcat(errbuf, " \"\" -i");
+# else
+ strcat(errbuf, " . -i");
+# endif
+#endif /* ?VMS */
+ for (i = first_listarg; i < argc; i++)
+ strcat(strcat(errbuf, " "), args[i]);
+ ZIPERR(ZE_NONE, errbuf);
+ }
+ else {
+ ZIPERR(ZE_NONE, zipfile);
+ }
+#endif /* !WINDLL */
+ }
+
+ if (filesync && all_current && fcount == 0) {
+ zipmessage("Archive is current", "");
+ RETURN(finish(ZE_OK));
+ }
+
+ d = (d && k == 0 && (zipbeg || zfiles != NULL)); /* d true if appending */
+
+#if CRYPT
+ /* Initialize the crc_32_tab pointer, when encryption was requested. */
+ if (key != NULL) {
+ crc_32_tab = get_crc_table();
+#ifdef EBCDIC
+ /* convert encryption key to ASCII (ISO variant for 8-bit ASCII chars) */
+ strtoasc(key, key);
+#endif /* EBCDIC */
+ }
+#endif /* CRYPT */
+
+ /* Just ignore the spanning signature if a multi-disk archive */
+ if (zfiles && total_disks != 1 && zipbeg == 4) {
+ zipbeg = 0;
+ }
+
+ /* Before we get carried away, make sure zip file is writeable. This
+ * has the undesired side effect of leaving one empty junk file on a WORM,
+ * so when the zipfile does not exist already and when -b is specified,
+ * the writability check is made in replace().
+ */
+ if (strcmp(zipfile, "-"))
+ {
+ if (tempdir && zfiles == NULL && zipbeg == 0) {
+ zip_attributes = 0;
+ } else {
+ x = (have_out || (zfiles == NULL && zipbeg == 0)) ? zfopen(out_path, FOPW) :
+ zfopen(out_path, FOPM);
+ /* Note: FOPW and FOPM expand to several parameters for VMS */
+ if (x == NULL) {
+ ZIPERR(ZE_CREAT, out_path);
+ }
+ fclose(x);
+ zip_attributes = getfileattr(out_path);
+ if (zfiles == NULL && zipbeg == 0)
+ destroy(out_path);
+ }
+ }
+ else
+ zip_attributes = 0;
+
+ /* Throw away the garbage in front of the zip file for -J */
+ if (junk_sfx) zipbeg = 0;
+
+ /* Open zip file and temporary output file */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Open zip file and create temp file\n");
+ fflush(mesg);
+ }
+ diag("opening zip file and creating temporary zip file");
+ x = NULL;
+ tempzn = 0;
+ if (strcmp(zipfile, "-") == 0)
+ {
+#ifdef MSDOS
+ /* It is nonsense to emit the binary data stream of a zipfile to
+ * the (text mode) console. This case should already have been caught
+ * in a call to zipstdout() far above. Therefore, if the following
+ * failsafe check detects a console attached to stdout, zip is stopped
+ * with an "internal logic error"! */
+ if (isatty(fileno(stdout)))
+ ZIPERR(ZE_LOGIC, "tried to write binary zipfile data to console!");
+ /* Set stdout mode to binary for MSDOS systems */
+# ifdef __HIGHC__
+ setmode(stdout, _BINARY);
+# else
+ setmode(fileno(stdout), O_BINARY);
+# endif
+ y = zfdopen(fileno(stdout), FOPW);
+#else
+ y = stdout;
+#endif
+ /* tempzip must be malloced so a later free won't barf */
+ tempzip = malloc(4);
+ if (tempzip == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, "-");
+ }
+ else if (d) /* d true if just appending (-g) */
+ {
+ if (total_disks > 1) {
+ ZIPERR(ZE_PARMS, "cannot grow split archive");
+ }
+ if ((y = zfopen(zipfile, FOPM)) == NULL) {
+ ZIPERR(ZE_NAME, zipfile);
+ }
+ tempzip = zipfile;
+ /*
+ tempzf = y;
+ */
+
+ if (zfseeko(y, cenbeg, SEEK_SET)) {
+ ZIPERR(ferror(y) ? ZE_READ : ZE_EOF, zipfile);
+ }
+ bytes_this_split = cenbeg;
+ tempzn = cenbeg;
+ }
+ else
+ {
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Creating new zip file\n");
+ fflush(mesg);
+ }
+ /* See if there is something at beginning of disk 1 to copy.
+ If not, do nothing as zipcopy() will open files to read
+ as needed. */
+ if (zipbeg) {
+ in_split_path = get_in_split_path(in_path, 0);
+
+ while ((in_file = zfopen(in_split_path, FOPR_EX)) == NULL) {
+ /* could not open split */
+
+ /* Ask for directory with split. Updates in_path */
+ if (ask_for_split_read_path(0) != ZE_OK) {
+ ZIPERR(ZE_ABORT, "could not open archive to read");
+ }
+ free(in_split_path);
+ in_split_path = get_in_split_path(in_path, 1);
+ }
+ }
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+ {
+ int yd;
+ int i;
+
+ /* use mkstemp to avoid race condition and compiler warning */
+
+ if (tempath != NULL)
+ {
+ /* if -b used to set temp file dir use that for split temp */
+ if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, tempath);
+ if (lastchar(tempzip) != '/')
+ strcat(tempzip, "/");
+ }
+ else
+ {
+ /* create path by stripping name and appending template */
+ if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, zipfile);
+ for(i = strlen(tempzip); i > 0; i--) {
+ if (tempzip[i - 1] == '/')
+ break;
+ }
+ tempzip[i] = '\0';
+ }
+ strcat(tempzip, "ziXXXXXX");
+
+ if ((yd = mkstemp(tempzip)) == EOF) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ }
+#else
+ if ((tempzip = tempname(zipfile)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+#endif
+ }
+
+#if (!defined(VMS) && !defined(CMS_MVS))
+ /* Use large buffer to speed up stdio: */
+#if (defined(_IOFBF) || !defined(BUFSIZ))
+ zipbuf = (char *)malloc(ZBSZ);
+#else
+ zipbuf = (char *)malloc(BUFSIZ);
+#endif
+ if (zipbuf == NULL) {
+ ZIPERR(ZE_MEM, tempzip);
+ }
+# ifdef _IOFBF
+ setvbuf(y, zipbuf, _IOFBF, ZBSZ);
+# else
+ setbuf(y, zipbuf);
+# endif /* _IOBUF */
+#endif /* !VMS && !CMS_MVS */
+
+ /* If not seekable set some flags 3/14/05 EG */
+ output_seekable = 1;
+ if (!is_seekable(y)) {
+ output_seekable = 0;
+ use_descriptors = 1;
+ }
+
+ /* Not needed. Only need Zip64 when input file is larger than 2 GB or reading
+ stdin and writing stdout. This is set in putlocal() for each file. */
+#if 0
+ /* If using descriptors and Zip64 enabled force Zip64 3/13/05 EG */
+# ifdef ZIP64_SUPPORT
+ if (use_descriptors && force_zip64 != 0) {
+ force_zip64 = 1;
+ }
+# endif
+#endif
+
+ /* if archive exists, not streaming and not deleting or growing, copy
+ any bytes at beginning */
+ if (strcmp(zipfile, "-") != 0 && !d) /* this must go *after* set[v]buf */
+ {
+ /* copy anything before archive */
+ if (in_file && zipbeg && (r = bfcopy(zipbeg)) != ZE_OK) {
+ ZIPERR(r, r == ZE_TEMP ? tempzip : zipfile);
+ }
+ if (in_file) {
+ fclose(in_file);
+ in_file = NULL;
+ free(in_split_path);
+ }
+ tempzn = zipbeg;
+ if (split_method) {
+ /* add spanning signature */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Adding spanning/splitting signature at top of archive\n");
+ fflush(mesg);
+ }
+ /* write the spanning signature at the top of the archive */
+ errbuf[0] = 0x50 /*'P' except for EBCDIC*/;
+ errbuf[1] = 0x4b /*'K' except for EBCDIC*/;
+ errbuf[2] = 7;
+ errbuf[3] = 8;
+ bfwrite(errbuf, 1, 4, BFWRITE_DATA);
+ /* tempzn updated below */
+ tempzn += 4;
+ }
+ }
+
+ o = 0; /* no ZE_OPEN errors yet */
+
+
+ /* Process zip file, updating marked files */
+#ifdef DEBUG
+ if (zfiles != NULL)
+ diag("going through old zip file");
+#endif
+ if (zfiles != NULL && show_what_doing) {
+ fprintf(mesg, "sd: Going through old zip file\n");
+ fflush(mesg);
+ }
+ w = &zfiles;
+ while ((z = *w) != NULL) {
+ if (z->mark == 1)
+ {
+ uzoff_t len;
+ if ((zoff_t)z->len == -1)
+ /* device */
+ len = 0;
+ else
+ len = z->len;
+
+ /* if not deleting, zip it up */
+ if (action != ARCHIVE && action != DELETE)
+ {
+ struct zlist far *localz; /* local header */
+
+ if (verbose || !(filesync && z->current))
+ DisplayRunningStats();
+ if (noisy)
+ {
+ if (action == FRESHEN) {
+ fprintf(mesg, "freshening: %s", z->oname);
+ mesg_line_started = 1;
+ fflush(mesg);
+ } else if (filesync && z->current) {
+ if (verbose) {
+ fprintf(mesg, " ok: %s", z->oname);
+ mesg_line_started = 1;
+ fflush(mesg);
+ }
+ } else if (!(filesync && z->current)) {
+ fprintf(mesg, "updating: %s", z->oname);
+ mesg_line_started = 1;
+ fflush(mesg);
+ }
+ }
+ if (logall)
+ {
+ if (action == FRESHEN) {
+ fprintf(logfile, "freshening: %s", z->oname);
+ logfile_line_started = 1;
+ fflush(logfile);
+ } else if (filesync && z->current) {
+ if (verbose) {
+ fprintf(logfile, " current: %s", z->oname);
+ logfile_line_started = 1;
+ fflush(logfile);
+ }
+ } else {
+ fprintf(logfile, "updating: %s", z->oname);
+ logfile_line_started = 1;
+ fflush(logfile);
+ }
+ }
+
+ /* Get local header flags and extra fields */
+ if (readlocal(&localz, z) != ZE_OK) {
+ zipwarn("could not read local entry information: ", z->oname);
+ z->lflg = z->flg;
+ z->ext = 0;
+ } else {
+ z->lflg = localz->lflg;
+ z->ext = localz->ext;
+ z->extra = localz->extra;
+ if (localz->nam) free(localz->iname);
+ if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+ if (localz->uname) free(localz->uname);
+#endif
+ free(localz);
+ }
+
+ if (!(filesync && z->current) &&
+ (r = zipup(z)) != ZE_OK && r != ZE_OPEN && r != ZE_MISS)
+ {
+ zipmessage_nl("", 1);
+ /*
+ if (noisy)
+ {
+ if (mesg_line_started) {
+#if (!defined(MACOS) && !defined(WINDLL))
+ putc('\n', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout, "\n");
+ fflush(stdout);
+#endif
+ mesg_line_started = 0;
+ }
+ }
+ if (logall) {
+ if (logfile_line_started) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+ }
+ */
+ sprintf(errbuf, "was zipping %s", z->name);
+ ZIPERR(r, errbuf);
+ }
+ if (filesync && z->current)
+ {
+ /* if filesync if entry matches OS just copy */
+ if ((r = zipcopy(z)) != ZE_OK)
+ {
+ sprintf(errbuf, "was copying %s", z->oname);
+ ZIPERR(r, errbuf);
+ }
+ zipmessage_nl("", 1);
+ /*
+ if (noisy)
+ {
+ if (mesg_line_started) {
+#if (!defined(MACOS) && !defined(WINDLL))
+ putc('\n', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout, "\n");
+ fflush(stdout);
+#endif
+ mesg_line_started = 0;
+ }
+ }
+ if (logall) {
+ if (logfile_line_started) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+ }
+ */
+ }
+ if (r == ZE_OPEN || r == ZE_MISS)
+ {
+ o = 1;
+ zipmessage_nl("", 1);
+ /*
+ if (noisy)
+ {
+#if (!defined(MACOS) && !defined(WINDLL))
+ putc('\n', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout, "\n");
+#endif
+ mesg_line_started = 0;
+ }
+ if (logall) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+ */
+ if (r == ZE_OPEN) {
+ perror(z->oname);
+ zipwarn("could not open for reading: ", z->oname);
+ if (bad_open_is_error) {
+ sprintf(errbuf, "was zipping %s", z->name);
+ ZIPERR(r, errbuf);
+ }
+ } else {
+ zipwarn("file and directory with the same name: ", z->oname);
+ }
+ zipwarn("will just copy entry over: ", z->oname);
+ if ((r = zipcopy(z)) != ZE_OK)
+ {
+ sprintf(errbuf, "was copying %s", z->oname);
+ ZIPERR(r, errbuf);
+ }
+ z->mark = 0;
+ }
+ files_so_far++;
+ good_bytes_so_far += z->len;
+ bytes_so_far += len;
+ w = &z->nxt;
+ }
+ else if (action == ARCHIVE)
+ {
+#ifdef DEBUG
+ zoff_t here = zftello(y);
+#endif
+
+ DisplayRunningStats();
+ if (skip_this_disk - 1 != z->dsk)
+ /* moved to another disk so start copying again */
+ skip_this_disk = 0;
+ if (skip_this_disk - 1 == z->dsk) {
+ /* skipping this disk */
+ if (noisy) {
+ fprintf(mesg, " skipping: %s", z->oname);
+ mesg_line_started = 1;
+ fflush(mesg);
+ }
+ if (logall) {
+ fprintf(logfile, " skipping: %s", z->oname);
+ logfile_line_started = 1;
+ fflush(logfile);
+ }
+ } else {
+ /* copying this entry */
+ if (noisy) {
+ fprintf(mesg, " copying: %s", z->oname);
+ if (display_usize) {
+ fprintf(mesg, " (");
+ DisplayNumString(mesg, z->len );
+ fprintf(mesg, ")");
+ }
+ mesg_line_started = 1;
+ fflush(mesg);
+ }
+ if (logall)
+ {
+ fprintf(logfile, " copying: %s", z->oname);
+ if (display_usize) {
+ fprintf(logfile, " (");
+ DisplayNumString(logfile, z->len );
+ fprintf(logfile, ")");
+ }
+ logfile_line_started = 1;
+ fflush(logfile);
+ }
+ }
+
+ if (skip_this_disk - 1 == z->dsk)
+ /* skip entries on this disk */
+ z->mark = 0;
+ else if ((r = zipcopy(z)) != ZE_OK)
+ {
+ if (r == ZE_ABORT) {
+ ZIPERR(r, "user requested abort");
+ } else if (fix != 1) {
+ /* exit */
+ sprintf(errbuf, "was copying %s", z->oname);
+ zipwarn("(try -F to attempt to fix)", "");
+ ZIPERR(r, errbuf);
+ }
+ else /* if (r == ZE_FORM) */ {
+#ifdef DEBUG
+ zoff_t here = zftello(y);
+#endif
+
+ /* seek back in output to start of this entry so can overwrite */
+ if (zfseeko(y, current_local_offset, SEEK_SET) != 0){
+ ZIPERR(r, "could not seek in output file");
+ }
+ zipwarn("bad - skipping: ", z->oname);
+#ifdef DEBUG
+ here = zftello(y);
+#endif
+ tempzn = current_local_offset;
+ bytes_this_split = current_local_offset;
+ }
+ }
+ if (skip_this_disk || !(fix == 1 && r != ZE_OK))
+ {
+ if (noisy && mesg_line_started) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+ if (logall && logfile_line_started) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+ }
+ /* input counts */
+ files_so_far++;
+ if (r != ZE_OK)
+ bad_bytes_so_far += z->siz;
+ else
+ good_bytes_so_far += z->siz;
+ bytes_so_far += z->siz;
+
+ if (r != ZE_OK && fix == 1) {
+ /* remove bad entry from list */
+ v = z->nxt; /* delete entry from list */
+ free((zvoid *)(z->iname));
+ free((zvoid *)(z->zname));
+ free(z->oname);
+#ifdef UNICODE_SUPPORT
+ if (z->uname) free(z->uname);
+#endif /* def UNICODE_SUPPORT */
+ if (z->ext)
+ /* don't have local extra until zipcopy reads it */
+ if (z->extra) free((zvoid *)(z->extra));
+ if (z->cext && z->cextra != z->extra)
+ free((zvoid *)(z->cextra));
+ if (z->com)
+ free((zvoid *)(z->comment));
+ farfree((zvoid far *)z);
+ *w = v;
+ zcount--;
+ } else {
+ w = &z->nxt;
+ }
+
+#ifdef WINDLL
+#ifdef ZIP64_SUPPORT
+ /* int64 support in caller */
+ if (lpZipUserFunctions->ServiceApplication64 != NULL)
+ {
+ if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, z->siz))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+ else
+ {
+ /* no int64 support in caller */
+ filesize64 = z->siz;
+ low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
+ high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
+ if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
+ if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+ }
+#else
+ if (lpZipUserFunctions->ServiceApplication != NULL) {
+ if ((*lpZipUserFunctions->ServiceApplication)(z->zname, z->siz))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+#endif /* ZIP64_SUPPORT - I added comments around // comments - does that help below? EG */
+/* strange but true: if I delete this and put these two endifs adjacent to
+ each other, the Aztec Amiga compiler never sees the second endif! WTF?? PK */
+#endif /* WINDLL */
+ }
+ else
+ {
+ DisplayRunningStats();
+ if (noisy)
+ {
+ fprintf(mesg, "deleting: %s", z->oname);
+ if (display_usize) {
+ fprintf(mesg, " (");
+ DisplayNumString(mesg, z->len );
+ fprintf(mesg, ")");
+ }
+ fflush(mesg);
+ fprintf(mesg, "\n");
+ }
+ if (logall)
+ {
+ fprintf(logfile, "deleting: %s", z->oname);
+ if (display_usize) {
+ fprintf(logfile, " (");
+ DisplayNumString(logfile, z->len );
+ fprintf(logfile, ")");
+ }
+ fprintf(logfile, "\n");
+ fflush(logfile);
+ }
+ files_so_far++;
+ good_bytes_so_far += z->siz;
+ bytes_so_far += z->siz;
+#ifdef WINDLL
+#ifdef ZIP64_SUPPORT
+ /* int64 support in caller */
+ if (lpZipUserFunctions->ServiceApplication64 != NULL)
+ {
+ if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, z->siz))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+ else
+ {
+ /* no int64 support in caller */
+ filesize64 = z->siz;
+ low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
+ high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
+ if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
+ if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+ }
+#else
+ if (lpZipUserFunctions->ServiceApplication != NULL) {
+ if ((*lpZipUserFunctions->ServiceApplication)(z->zname, z->siz))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+#endif /* ZIP64_SUPPORT - I added comments around // comments - does that help below? EG */
+/* strange but true: if I delete this and put these two endifs adjacent to
+ each other, the Aztec Amiga compiler never sees the second endif! WTF?? PK */
+#endif /* WINDLL */
+
+ v = z->nxt; /* delete entry from list */
+ free((zvoid *)(z->iname));
+ free((zvoid *)(z->zname));
+ free(z->oname);
+#ifdef UNICODE_SUPPORT
+ if (z->uname) free(z->uname);
+#endif /* def UNICODE_SUPPORT */
+ if (z->ext)
+ /* don't have local extra until zipcopy reads it */
+ if (z->extra) free((zvoid *)(z->extra));
+ if (z->cext && z->cextra != z->extra)
+ free((zvoid *)(z->cextra));
+ if (z->com)
+ free((zvoid *)(z->comment));
+ farfree((zvoid far *)z);
+ *w = v;
+ zcount--;
+ }
+ }
+ else
+ {
+ if (action == ARCHIVE) {
+ v = z->nxt; /* delete entry from list */
+ free((zvoid *)(z->iname));
+ free((zvoid *)(z->zname));
+ free(z->oname);
+#ifdef UNICODE_SUPPORT
+ if (z->uname) free(z->uname);
+#endif /* def UNICODE_SUPPORT */
+ if (z->ext)
+ /* don't have local extra until zipcopy reads it */
+ if (z->extra) free((zvoid *)(z->extra));
+ if (z->cext && z->cextra != z->extra)
+ free((zvoid *)(z->cextra));
+ if (z->com)
+ free((zvoid *)(z->comment));
+ farfree((zvoid far *)z);
+ *w = v;
+ zcount--;
+ }
+ else
+ {
+ if (filesync) {
+ /* Delete entries if don't match a file on OS */
+ BlankRunningStats();
+ if (noisy)
+ {
+ fprintf(mesg, "deleting: %s", z->oname);
+ if (display_usize) {
+ fprintf(mesg, " (");
+ DisplayNumString(mesg, z->len );
+ fprintf(mesg, ")");
+ }
+ fflush(mesg);
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ }
+ if (logall)
+ {
+ fprintf(logfile, "deleting: %s", z->oname);
+ if (display_usize) {
+ fprintf(logfile, " (");
+ DisplayNumString(logfile, z->len );
+ fprintf(logfile, ")");
+ }
+ fprintf(logfile, "\n");
+ fflush(logfile);
+ logfile_line_started = 0;
+ }
+ }
+ /* copy the original entry */
+ else if (!d && !diff_mode && (r = zipcopy(z)) != ZE_OK)
+ {
+ sprintf(errbuf, "was copying %s", z->oname);
+ ZIPERR(r, errbuf);
+ }
+ w = &z->nxt;
+ }
+ }
+ }
+
+
+ /* Process the edited found list, adding them to the zip file */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Zipping up new entries\n");
+ fflush(mesg);
+ }
+ diag("zipping up new entries, if any");
+ Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount));
+ for (f = found; f != NULL; f = fexpel(f))
+ {
+ uzoff_t len;
+ /* add a new zfiles entry and set the name */
+ if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+ ZIPERR(ZE_MEM, "was adding files to zip file");
+ }
+ z->nxt = NULL;
+ z->name = f->name;
+ f->name = NULL;
+#ifdef UNICODE_SUPPORT
+ z->uname = NULL; /* UTF-8 name for extra field */
+ z->zuname = NULL; /* externalized UTF-8 name for matching */
+ z->ouname = NULL; /* display version of UTF-8 name with OEM */
+
+#if 0
+ /* New AppNote bit 11 allowing storing UTF-8 in path */
+ if (utf8_force && f->uname) {
+ if (f->iname)
+ free(f->iname);
+ if ((f->iname = malloc(strlen(f->uname) + 1)) == NULL)
+ ZIPERR(ZE_MEM, "Unicode bit 11");
+ strcpy(f->iname, f->uname);
+# ifdef WIN32
+ if (f->inamew)
+ free(f->inamew);
+ f->inamew = utf8_to_wchar_string(f->iname);
+# endif
+ }
+#endif
+
+ /* Only set z->uname if have a non-ASCII Unicode name */
+ /* The Unicode path extra field is created if z->uname is not NULL,
+ unless on a UTF-8 system, then instead of creating the extra field
+ set bit 11 in the General Purpose Bit Flag */
+ {
+ int is_ascii = 0;
+
+# ifdef WIN32
+ if (!no_win32_wide)
+ is_ascii = is_ascii_stringw(f->inamew);
+ else
+ is_ascii = is_ascii_string(f->uname);
+# else
+ is_ascii = is_ascii_string(f->uname);
+# endif
+
+ if (z->uname == NULL) {
+ if (!is_ascii)
+ z->uname = f->uname;
+ else
+ free(f->uname);
+ } else {
+ free(f->uname);
+ }
+ }
+ f->uname = NULL;
+
+#endif
+ z->iname = f->iname;
+ f->iname = NULL;
+ z->zname = f->zname;
+ f->zname = NULL;
+ z->oname = f->oname;
+ f->oname = NULL;
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ z->namew = f->namew;
+ f->namew = NULL;
+ z->inamew = f->inamew;
+ f->inamew = NULL;
+ z->znamew = f->znamew;
+ f->znamew = NULL;
+#endif
+ z->ext = z->cext = z->com = 0;
+ z->extra = z->cextra = NULL;
+ z->mark = 1;
+ z->dosflag = f->dosflag;
+ /* zip it up */
+ DisplayRunningStats();
+ if (noisy)
+ {
+ fprintf(mesg, " adding: %s", z->oname);
+ mesg_line_started = 1;
+ fflush(mesg);
+ }
+ if (logall)
+ {
+ fprintf(logfile, " adding: %s", z->oname);
+ logfile_line_started = 1;
+ fflush(logfile);
+ }
+ /* initial scan */
+ len = f->usize;
+ if ((r = zipup(z)) != ZE_OK && r != ZE_OPEN && r != ZE_MISS)
+ {
+ zipmessage_nl("", 1);
+ /*
+ if (noisy)
+ {
+#if (!defined(MACOS) && !defined(WINDLL))
+ putc('\n', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout, "\n");
+#endif
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+ if (logall) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+ */
+ sprintf(errbuf, "was zipping %s", z->oname);
+ ZIPERR(r, errbuf);
+ }
+ if (r == ZE_OPEN || r == ZE_MISS)
+ {
+ o = 1;
+ zipmessage_nl("", 1);
+ /*
+ if (noisy)
+ {
+#if (!defined(MACOS) && !defined(WINDLL))
+ putc('\n', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout, "\n");
+#endif
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+ if (logall) {
+ fprintf(logfile, "\n");
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+ */
+ if (r == ZE_OPEN) {
+ perror("zip warning");
+ if (logfile)
+ fprintf(logfile, "zip warning: %s\n", strerror(errno));
+ zipwarn("could not open for reading: ", z->oname);
+ if (bad_open_is_error) {
+ sprintf(errbuf, "was zipping %s", z->name);
+ ZIPERR(r, errbuf);
+ }
+ } else {
+ zipwarn("file and directory with the same name: ", z->oname);
+ }
+ files_so_far++;
+ bytes_so_far += len;
+ bad_files_so_far++;
+ bad_bytes_so_far += len;
+ free((zvoid *)(z->name));
+ free((zvoid *)(z->iname));
+ free((zvoid *)(z->zname));
+ free(z->oname);
+#ifdef UNICODE_SUPPORT
+ if (z->uname)
+ free(z->uname);
+# ifdef WIN32
+ if (z->namew)
+ free((zvoid *)(z->namew));
+ if (z->inamew)
+ free((zvoid *)(z->inamew));
+ if (z->znamew)
+ free((zvoid *)(z->znamew));
+# endif
+#endif
+ farfree((zvoid far *)z);
+ }
+ else
+ {
+ files_so_far++;
+ /* current size of file (just before reading) */
+ good_bytes_so_far += z->len;
+ /* size of file on initial scan */
+ bytes_so_far += len;
+ *w = z;
+ w = &z->nxt;
+ zcount++;
+ }
+ }
+ if (key != NULL)
+ {
+ free((zvoid *)key);
+ key = NULL;
+ }
+
+ /* final status 3/17/05 EG */
+ if (noisy && bad_files_so_far)
+ {
+ char tempstrg[100];
+
+ fprintf(mesg, "\nzip warning: Not all files were readable\n");
+ fprintf(mesg, " files/entries read: %lu", files_total - bad_files_so_far);
+ WriteNumString(good_bytes_so_far, tempstrg);
+ fprintf(mesg, " (%s bytes)", tempstrg);
+ fprintf(mesg, " skipped: %lu", bad_files_so_far);
+ WriteNumString(bad_bytes_so_far, tempstrg);
+ fprintf(mesg, " (%s bytes)\n", tempstrg);
+ fflush(mesg);
+ }
+ if (logfile && bad_files_so_far)
+ {
+ char tempstrg[100];
+
+ fprintf(logfile, "\nzip warning: Not all files were readable\n");
+ fprintf(logfile, " files/entries read: %lu", files_total - bad_files_so_far);
+ WriteNumString(good_bytes_so_far, tempstrg);
+ fprintf(logfile, " (%s bytes)", tempstrg);
+ fprintf(logfile, " skipped: %lu", bad_files_so_far);
+ WriteNumString(bad_bytes_so_far, tempstrg);
+ fprintf(logfile, " (%s bytes)", tempstrg);
+ }
+
+ /* Get one line comment for each new entry */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Get comment if any\n");
+ fflush(mesg);
+ }
+#if defined(AMIGA) || defined(MACOS)
+ if (comadd || filenotes)
+ {
+ if (comadd)
+#else
+ if (comadd)
+ {
+#endif
+ {
+ if (comment_stream == NULL) {
+#ifndef RISCOS
+ comment_stream = (FILE*)fdopen(fileno(stderr), "r");
+#else
+ comment_stream = stderr;
+#endif
+ }
+ if ((e = malloc(MAXCOM + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "was reading comment lines");
+ }
+ }
+#ifdef __human68k__
+ setmode(fileno(comment_stream), O_TEXT);
+#endif
+#ifdef MACOS
+ if (noisy) fprintf(mesg, "\nStart commenting files ...\n");
+#endif
+ for (z = zfiles; z != NULL; z = z->nxt)
+ if (z->mark)
+#if defined(AMIGA) || defined(MACOS)
+ if (filenotes && (p = GetComment(z->zname)))
+ {
+ if (z->comment = malloc(k = strlen(p)+1))
+ {
+ z->com = k;
+ strcpy(z->comment, p);
+ }
+ else
+ {
+ free((zvoid *)e);
+ ZIPERR(ZE_MEM, "was reading filenotes");
+ }
+ }
+ else if (comadd)
+#endif /* AMIGA || MACOS */
+ {
+ if (noisy)
+ fprintf(mesg, "Enter comment for %s:\n", z->oname);
+ if (fgets(e, MAXCOM+1, comment_stream) != NULL)
+ {
+ if ((p = malloc((extent)(k = strlen(e))+1)) == NULL)
+ {
+ free((zvoid *)e);
+ ZIPERR(ZE_MEM, "was reading comment lines");
+ }
+ strcpy(p, e);
+ if (p[k-1] == '\n')
+ p[--k] = 0;
+ z->comment = p;
+ /* zip64 support 09/05/2003 R.Nausedat */
+ z->com = (extent)k;
+ }
+ }
+#ifdef MACOS
+ if (noisy) fprintf(mesg, "\n...done");
+#endif
+#if defined(AMIGA) || defined(MACOS)
+ if (comadd)
+ free((zvoid *)e);
+ GetComment(NULL); /* makes it free its internal storage */
+#else
+ free((zvoid *)e);
+#endif
+ }
+
+ /* Get multi-line comment for the zip file */
+ if (zipedit)
+ {
+#ifndef WINDLL
+ if (comment_stream == NULL) {
+#ifndef RISCOS
+ comment_stream = (FILE*)fdopen(fileno(stderr), "r");
+#else
+ comment_stream = stderr;
+#endif
+ }
+ if ((e = malloc(MAXCOM + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "was reading comment lines");
+ }
+ if (noisy && zcomlen)
+ {
+ fputs("current zip file comment is:\n", mesg);
+ fwrite(zcomment, 1, zcomlen, mesg);
+ if (zcomment[zcomlen-1] != '\n')
+ putc('\n', mesg);
+ free((zvoid *)zcomment);
+ }
+ if ((zcomment = malloc(1)) == NULL)
+ ZIPERR(ZE_MEM, "was setting comments to null");
+ zcomment[0] = '\0';
+ if (noisy)
+ fputs("enter new zip file comment (end with .):\n", mesg);
+#if (defined(AMIGA) && (defined(LATTICE)||defined(__SASC)))
+ flushall(); /* tty input/output is out of sync here */
+#endif
+#ifdef __human68k__
+ setmode(fileno(comment_stream), O_TEXT);
+#endif
+#ifdef MACOS
+ printf("\n enter new zip file comment \n");
+ if (fgets(e, MAXCOM+1, comment_stream) != NULL) {
+ if ((p = malloc((k = strlen(e))+1)) == NULL) {
+ free((zvoid *)e);
+ ZIPERR(ZE_MEM, "was reading comment lines");
+ }
+ strcpy(p, e);
+ if (p[k-1] == '\n') p[--k] = 0;
+ zcomment = p;
+ }
+#else /* !MACOS */
+ while (fgets(e, MAXCOM+1, comment_stream) != NULL && strcmp(e, ".\n"))
+ {
+ if (e[(r = strlen(e)) - 1] == '\n')
+ e[--r] = 0;
+ if ((p = malloc((*zcomment ? strlen(zcomment) + 3 : 1) + r)) == NULL)
+ {
+ free((zvoid *)e);
+ ZIPERR(ZE_MEM, "was reading comment lines");
+ }
+ if (*zcomment)
+ strcat(strcat(strcpy(p, zcomment), "\r\n"), e);
+ else
+ strcpy(p, *e ? e : "\r\n");
+ free((zvoid *)zcomment);
+ zcomment = p;
+ }
+#endif /* ?MACOS */
+ free((zvoid *)e);
+#else /* WINDLL */
+ comment(zcomlen);
+ if ((p = malloc(strlen(szCommentBuf)+1)) == NULL) {
+ ZIPERR(ZE_MEM, "was setting comments to null");
+ }
+ if (szCommentBuf[0] != '\0')
+ lstrcpy(p, szCommentBuf);
+ else
+ p[0] = '\0';
+ free((zvoid *)zcomment);
+ GlobalUnlock(hStr);
+ GlobalFree(hStr);
+ zcomment = p;
+#endif /* WINDLL */
+ zcomlen = strlen(zcomment);
+ }
+
+ if (display_globaldots) {
+#ifndef WINDLL
+ putc('\n', mesg);
+#else
+ fprintf(stdout,"%c",'\n');
+#endif
+ mesg_line_started = 0;
+ }
+
+ /* Write central directory and end header to temporary zip */
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Writing central directory\n");
+ fflush(mesg);
+ }
+ diag("writing central directory");
+ k = 0; /* keep count for end header */
+ c = tempzn; /* get start of central */
+ n = t = 0;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ {
+ if (z->mark || !(diff_mode || filesync)) {
+ if ((r = putcentral(z)) != ZE_OK) {
+ ZIPERR(r, tempzip);
+ }
+ tempzn += 4 + CENHEAD + z->nam + z->cext + z->com;
+ n += z->len;
+ t += z->siz;
+ k++;
+ }
+ }
+
+ if (k == 0)
+ zipwarn("zip file empty", "");
+ if (verbose) {
+ fprintf(mesg, "total bytes=%s, compressed=%s -> %d%% savings\n",
+ zip_fzofft(n, NULL, "u"), zip_fzofft(t, NULL, "u"), percent(n, t));
+ fflush(mesg);
+ }
+ if (logall) {
+ fprintf(logfile, "total bytes=%s, compressed=%s -> %d%% savings\n",
+ zip_fzofft(n, NULL, "u"), zip_fzofft(t, NULL, "u"), percent(n, t));
+ fflush(logfile);
+ }
+ t = tempzn - c; /* compute length of central */
+ diag("writing end of central directory");
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Writing end of central directory\n");
+ fflush(mesg);
+ }
+
+ if ((r = putend(k, t, c, zcomlen, zcomment)) != ZE_OK) {
+ ZIPERR(r, tempzip);
+ }
+
+ /*
+ tempzf = NULL;
+ */
+ if (fclose(y)) {
+ ZIPERR(d ? ZE_WRITE : ZE_TEMP, tempzip);
+ }
+ y = NULL;
+ if (in_file != NULL) {
+ fclose(in_file);
+ in_file = NULL;
+ }
+ /*
+ if (x != NULL)
+ fclose(x);
+ */
+
+ /* Free some memory before spawning unzip */
+#ifdef USE_ZLIB
+ zl_deflate_free();
+#else
+ lm_free();
+#endif
+#ifdef BZIP2_SUPPORT
+ bz_compress_free();
+#endif
+
+#ifndef WINDLL
+ /* Test new zip file before overwriting old one or removing input files */
+ if (test)
+ check_zipfile(tempzip, argv[0]);
+#endif
+ /* Replace old zip file with new zip file, leaving only the new one */
+ if (strcmp(zipfile, "-") && !d)
+ {
+ diag("replacing old zip file with new zip file");
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Replacing old zip file\n");
+ fflush(mesg);
+ }
+ if ((r = replace(out_path, tempzip)) != ZE_OK)
+ {
+ zipwarn("new zip file left as: ", tempzip);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ZIPERR(r, "was replacing the original zip file");
+ }
+ free((zvoid *)tempzip);
+ }
+ tempzip = NULL;
+ if (zip_attributes && strcmp(zipfile, "-")) {
+ setfileattr(out_path, zip_attributes);
+#ifdef VMS
+ /* If the zip file existed previously, restore its record format: */
+ if (x != NULL)
+ (void)VMSmunch(out_path, RESTORE_RTYPE, NULL);
+#endif
+ }
+ if (strcmp(zipfile, "-")) {
+ if (show_what_doing) {
+ fprintf(mesg, "sd: Setting file type\n");
+ fflush(mesg);
+ }
+
+ set_filetype(out_path);
+ }
+
+#if defined(WIN32)
+ /* All looks good so, if requested, clear the DOS archive bits */
+ if (clear_archive_bits) {
+ if (noisy)
+ zipmessage("Clearing archive bits...", "");
+ for (z = zfiles; z != NULL; z = z->nxt)
+ {
+# ifdef UNICODE_SUPPORT
+ if (z->mark) {
+ if (!no_win32_wide) {
+ if (!ClearArchiveBitW(z->namew)){
+ zipwarn("Could not clear archive bit for: ", z->oname);
+ }
+ } else {
+ if (!ClearArchiveBit(z->name)){
+ zipwarn("Could not clear archive bit for: ", z->oname);
+ }
+ }
+ }
+# else
+ if (!ClearArchiveBit(z->name)){
+ zipwarn("Could not clear archive bit for: ", z->oname);
+ }
+# endif
+ }
+ }
+#endif
+
+ /* finish logfile (it gets closed in freeup() called by finish()) */
+ if (logfile) {
+ struct tm *now;
+ time_t clocktime;
+
+ fprintf(logfile, "\nTotal %ld entries (", files_total);
+ if (good_bytes_so_far != bytes_total) {
+ fprintf(logfile, "planned ");
+ DisplayNumString(logfile, bytes_total);
+ fprintf(logfile, " bytes, actual ");
+ DisplayNumString(logfile, good_bytes_so_far);
+ fprintf(logfile, " bytes)");
+ } else {
+ DisplayNumString(logfile, bytes_total);
+ fprintf(logfile, " bytes)");
+ }
+
+ /* get current time */
+
+ time(&clocktime);
+ now = localtime(&clocktime);
+ fprintf(logfile, "\nDone %s", asctime(now));
+ }
+
+ /* Finish up (process -o, -m, clean up). Exit code depends on o. */
+#if (!defined(VMS) && !defined(CMS_MVS))
+ free((zvoid *) zipbuf);
+#endif /* !VMS && !CMS_MVS */
+ RETURN(finish(o ? ZE_OPEN : ZE_OK));
+}
diff --git a/zip.h b/zip.h
new file mode 100644
index 0000000..ba03160
--- /dev/null
+++ b/zip.h
@@ -0,0 +1,1081 @@
+/*
+ zip.h - Zip 3
+
+/---------------------------------------------------------------------/
+
+Info-ZIP Licence
+
+This is version 2007-Mar-4 of the Info-ZIP license.
+The definitive version of this document should be available at
+ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and
+a copy at http://www.info-zip.org/pub/infozip/license.html.
+
+
+Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+For the purposes of this copyright and license, "Info-ZIP" is defined as
+the following set of individuals:
+
+ Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,
+ Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth,
+ Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,
+ David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,
+ Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,
+ Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda,
+ Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren,
+ Rich Wales, Mike White.
+
+This software is provided "as is," without warranty of any kind, express
+or implied. In no event shall Info-ZIP or its contributors be held liable
+for any direct, indirect, incidental, special or consequential damages
+arising out of the use of or inability to use this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the above disclaimer and the following restrictions:
+
+ 1. Redistributions of source code (in whole or in part) must retain
+ the above copyright notice, definition, disclaimer, and this list
+ of conditions.
+
+ 2. Redistributions in binary form (compiled executables and libraries)
+ must reproduce the above copyright notice, definition, disclaimer,
+ and this list of conditions in documentation and/or other materials
+ provided with the distribution. The sole exception to this condition
+ is redistribution of a standard UnZipSFX binary (including SFXWiz) as
+ part of a self-extracting archive; that is permitted without inclusion
+ of this license, as long as the normal SFX banner has not been removed
+ from the binary or disabled.
+
+ 3. Altered versions--including, but not limited to, ports to new operating
+ systems, existing ports with new graphical interfaces, versions with
+ modified or added functionality, and dynamic, shared, or static library
+ versions not from Info-ZIP--must be plainly marked as such and must not
+ be misrepresented as being the original source or, if binaries,
+ compiled from the original source. Such altered versions also must not
+ be misrepresented as being Info-ZIP releases--including, but not
+ limited to, labeling of the altered versions with the names "Info-ZIP"
+ (or any variation thereof, including, but not limited to, different
+ capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the
+ explicit permission of Info-ZIP. Such altered versions are further
+ prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP
+ e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP
+ will provide support for the altered versions.
+
+ 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip,"
+ "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its
+ own source and binary releases.
+
+/---------------------------------------------------------------------/
+
+*/
+
+/*
+ * zip.h by Mark Adler
+ */
+#ifndef __zip_h
+#define __zip_h 1
+
+#define ZIP /* for crypt.c: include zip password functions, not unzip */
+
+/* Types centralized here for easy modification */
+#define local static /* More meaningful outside functions */
+typedef unsigned char uch; /* unsigned 8-bit value */
+typedef unsigned short ush; /* unsigned 16-bit value */
+typedef unsigned long ulg; /* unsigned 32-bit value */
+
+/* Set up portability */
+#include "tailor.h"
+
+#ifdef USE_ZLIB
+# include "zlib.h"
+#endif
+
+/* In the utilities, the crc32() function is only used for UNICODE_SUPPORT. */
+#if defined(UTIL) && !defined(UNICODE_SUPPORT)
+# define CRC_TABLE_ONLY
+#endif
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#ifndef WSIZE
+# define WSIZE (0x8000)
+#endif
+/* Maximum window size = 32K. If you are really short of memory, compile
+ * with a smaller WSIZE but this reduces the compression ratio for files
+ * of size > WSIZE. WSIZE must be a power of two in the current implementation.
+ */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+/* Forget FILENAME_MAX (incorrectly = 14 on some System V) */
+#ifdef DOS
+# define FNMAX 256
+#else
+# define FNMAX 1024
+#endif
+
+#ifndef MATCH
+# define MATCH shmatch /* Default for pattern matching: UNIX style */
+#endif
+
+/* Structure carrying extended timestamp information */
+typedef struct iztimes {
+ time_t atime; /* new access time */
+ time_t mtime; /* new modification time */
+ time_t ctime; /* new creation time (!= Unix st.ctime) */
+} iztimes;
+
+/* Lengths of headers after signatures in bytes */
+#define LOCHEAD 26
+#define CENHEAD 42
+#define ENDHEAD 18
+#define EC64LOC 16
+#define EC64REC 52
+
+/* Structures for in-memory file information */
+struct zlist {
+ /* See central header in zipfile.c for what vem..off are */
+ /* Do not rearrange these as less than smart coding in zipfile.c
+ in scanzipf_reg() depends on u being set to ver and then stepping
+ through as a byte array. Ack. Should be fixed. 5/25/2005 EG */
+ /* All the new read code does not rely on this order. */
+ ush vem, ver, flg, how;
+ ulg tim, crc;
+ uzoff_t siz, len; /* zip64 support 08/29/2003 R.Nausedat */
+ /* changed from extent to ush 3/10/2005 EG */
+ ush nam, ext, cext, com; /* offset of ext must be >= LOCHEAD */
+ ulg dsk; /* disk number was ush but now ulg */
+ ush att, lflg; /* offset of lflg must be >= LOCHEAD */
+ uzoff_t off;
+ ulg atx;
+ char *name; /* File name in zip file */
+ char *extra; /* Extra field (set only if ext != 0) */
+ char *cextra; /* Extra in central (set only if cext != 0) */
+ char *comment; /* Comment (set only if com != 0) */
+ char *iname; /* Internal file name after cleanup (stored in archive) */
+ char *zname; /* External version of internal name */
+ char *oname; /* Display version of name used in messages */
+#ifdef UNICODE_SUPPORT
+ /* Unicode support */
+ char *uname; /* UTF-8 version of iname */
+ /* if uname has chars not in local char set, zuname can be different than zname */
+ char *zuname; /* Escaped Unicode zname from uname */
+ char *ouname; /* Display version of zuname */
+# ifdef WIN32
+ char *wuname; /* Converted back ouname for Win32 */
+ wchar_t *namew; /* Windows wide character version of name */
+ wchar_t *inamew; /* Windows wide character version of iname */
+ wchar_t *znamew; /* Windows wide character version of zname */
+# endif
+#endif
+ int mark; /* Marker for files to operate on */
+ int trash; /* Marker for files to delete */
+ int current; /* Marker for files that are current to what is on OS (filesync) */
+ int dosflag; /* Set to force MSDOS file attributes */
+ struct zlist far *nxt; /* Pointer to next header in list */
+};
+struct flist {
+ char *name; /* Raw internal file name */
+ char *iname; /* Internal file name after cleanup */
+ char *zname; /* External version of internal name */
+ char *oname; /* Display version of internal name */
+#ifdef UNICODE_SUPPORT
+ char *uname; /* UTF-8 name */
+# ifdef WIN32
+ wchar_t *namew; /* Windows wide character version of name */
+ wchar_t *inamew; /* Windows wide character version of iname */
+ wchar_t *znamew; /* Windows wide character version of zname */
+# endif
+#endif
+ int dosflag; /* Set to force MSDOS file attributes */
+ uzoff_t usize; /* usize from initial scan */
+ struct flist far *far *lst; /* Pointer to link pointing here */
+ struct flist far *nxt; /* Link to next name */
+};
+struct plist {
+ char *zname; /* External version of internal name */
+ int select; /* Selection flag ('i' or 'x') */
+};
+
+/* internal file attribute */
+#define UNKNOWN (-1)
+#define BINARY 0
+#define ASCII 1
+#define __EBCDIC 2
+
+/* extra field definitions */
+#define EF_VMCMS 0x4704 /* VM/CMS Extra Field ID ("G")*/
+#define EF_MVS 0x470f /* MVS Extra Field ID ("G") */
+#define EF_IZUNIX 0x5855 /* UNIX Extra Field ID ("UX") */
+#define EF_IZUNIX2 0x7855 /* Info-ZIP's new Unix ("Ux") */
+#define EF_TIME 0x5455 /* universal timestamp ("UT") */
+#define EF_OS2EA 0x0009 /* OS/2 Extra Field ID (extended attributes) */
+#define EF_ACL 0x4C41 /* ACL Extra Field ID (access control list, "AL") */
+#define EF_NTSD 0x4453 /* NT Security Descriptor Extra Field ID, ("SD") */
+#define EF_BEOS 0x6542 /* BeOS Extra Field ID ("Be") */
+#define EF_ATHEOS 0x7441 /* AtheOS Extra Field ID ("At") */
+#define EF_QDOS 0xfb4a /* SMS/QDOS ("J\373") */
+#define EF_AOSVS 0x5356 /* AOS/VS ("VS") */
+#define EF_SPARK 0x4341 /* David Pilling's Acorn/SparkFS ("AC") */
+#define EF_THEOS 0x6854 /* THEOS ("Th") */
+#define EF_TANDEM 0x4154 /* Tandem NSK ("TA") */
+
+/* Definitions for extra field handling: */
+#define EF_SIZE_MAX ((unsigned)0xFFFF) /* hard limit of total e.f. length */
+#define EB_HEADSIZE 4 /* length of a extra field block header */
+#define EB_ID 0 /* offset of block ID in header */
+#define EB_LEN 2 /* offset of data length field in header */
+#define EB_MEMCMPR_HSIZ 6 /* header length for memcompressed data */
+#define EB_DEFLAT_EXTRA 10 /* overhead for 64kByte "undeflatable" data */
+
+#define EB_UX_MINLEN 8 /* minimal "UX" field contains atime, mtime */
+#define EB_UX_ATIME 0 /* offset of atime in "UX" extra field data */
+#define EB_UX_MTIME 4 /* offset of mtime in "UX" extra field data */
+
+#define EB_UX_FULLSIZE 12 /* full "UX" field (atime, mtime, uid, gid) */
+#define EB_UX_UID 8 /* byte offset of UID in "UX" field data */
+#define EB_UX_GID 10 /* byte offset of GID in "UX" field data */
+
+#define EB_UT_MINLEN 1 /* minimal UT field contains Flags byte */
+#define EB_UT_FLAGS 0 /* byte offset of Flags field */
+#define EB_UT_TIME1 1 /* byte offset of 1st time value */
+#define EB_UT_FL_MTIME (1 << 0) /* mtime present */
+#define EB_UT_FL_ATIME (1 << 1) /* atime present */
+#define EB_UT_FL_CTIME (1 << 2) /* ctime present */
+#define EB_UT_LEN(n) (EB_UT_MINLEN + 4 * (n))
+
+#define EB_UX2_MINLEN 4 /* minimal Ux field contains UID/GID */
+#define EB_UX2_UID 0 /* byte offset of UID in "Ux" field data */
+#define EB_UX2_GID 2 /* byte offset of GID in "Ux" field data */
+#define EB_UX2_VALID (1 << 8) /* UID/GID present */
+
+/* ASCII definitions for line terminators in text files: */
+#define LF 10 /* '\n' on ASCII machines; must be 10 due to EBCDIC */
+#define CR 13 /* '\r' on ASCII machines; must be 13 due to EBCDIC */
+#define CTRLZ 26 /* DOS & OS/2 EOF marker (used in fileio.c, vms.c) */
+
+/* return codes of password fetches (negative: user abort; positive: error) */
+#define IZ_PW_ENTERED 0 /* got some PWD string, use/try it */
+#define IZ_PW_CANCEL -1 /* no password available (for this entry) */
+#define IZ_PW_CANCELALL -2 /* no password, skip any further PWD request */
+#define IZ_PW_ERROR 5 /* = PK_MEM2 : failure (no mem, no tty, ...) */
+#define IZ_PW_SKIPVERIFY IZ_PW_CANCEL /* skip encrypt. passwd verification */
+
+/* mode flag values of password prompting function */
+#define ZP_PW_ENTER 0 /* request for encryption password */
+#define ZP_PW_VERIFY 1 /* request for reentering password */
+
+/* Error return codes and PERR macro */
+#include "ziperr.h"
+
+#if 0 /* Optimization: use the (const) result of crc32(0L,NULL,0) */
+# define CRCVAL_INITIAL crc32(0L, (uch *)NULL, 0)
+# if 00 /* not used, should be removed !! */
+# define ADLERVAL_INITIAL adler16(0U, (uch *)NULL, 0)
+# endif /* 00 */
+#else
+# define CRCVAL_INITIAL 0L
+# if 00 /* not used, should be removed !! */
+# define ADLERVAL_INITIAL 1
+# endif /* 00 */
+#endif
+
+#define DOSTIME_MINIMUM ((ulg)0x00210000L)
+#define DOSTIME_2038_01_18 ((ulg)0x74320000L)
+
+
+/* Public globals */
+extern uch upper[256]; /* Country dependent case map table */
+extern uch lower[256];
+#ifdef EBCDIC
+extern ZCONST uch ascii[256]; /* EBCDIC <--> ASCII translation tables */
+extern ZCONST uch ebcdic[256];
+#endif /* EBCDIC */
+#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+ extern ZCONST ulg near *crc_32_tab;
+#else
+ extern ZCONST ulg Far *crc_32_tab;
+#endif
+
+/* Are these ever used? 6/12/05 EG */
+#ifdef IZ_ISO2OEM_ARRAY /* ISO 8859-1 (Win CP 1252) --> OEM CP 850 */
+extern ZCONST uch Far iso2oem[128];
+#endif
+#ifdef IZ_OEM2ISO_ARRAY /* OEM CP 850 --> ISO 8859-1 (Win CP 1252) */
+extern ZCONST uch Far oem2iso[128];
+#endif
+
+extern char errbuf[FNMAX+4081]; /* Handy place to build error messages */
+extern int recurse; /* Recurse into directories encountered */
+extern int dispose; /* Remove files after put in zip file */
+extern int pathput; /* Store path with name */
+
+#ifdef RISCOS
+extern int scanimage; /* Scan through image files */
+#endif
+
+#define BEST -1 /* Use best method (deflation or store) */
+#define STORE 0 /* Store method */
+#define DEFLATE 8 /* Deflation method*/
+#define BZIP2 12 /* BZIP2 method */
+#ifdef BZIP2_SUPPORT
+#define LAST_KNOWN_COMPMETHOD BZIP2
+#else
+#define LAST_KNOWN_COMPMETHOD DEFLATE
+#endif
+
+extern int method; /* Restriction on compression method */
+
+extern ulg skip_this_disk;
+extern int des_good; /* Good data descriptor found */
+extern ulg des_crc; /* Data descriptor CRC */
+extern uzoff_t des_csize; /* Data descriptor csize */
+extern uzoff_t des_usize; /* Data descriptor usize */
+extern int dosify; /* Make new entries look like MSDOS */
+extern char *special; /* Don't compress special suffixes */
+extern int verbose; /* Report oddities in zip file structure */
+extern int fix; /* Fix the zip file */
+extern int filesync; /* 1=file sync, delete entries not on file system */
+extern int adjust; /* Adjust the unzipsfx'd zip file */
+extern int level; /* Compression level */
+extern int translate_eol; /* Translate end-of-line LF -> CR LF */
+#ifdef VMS
+ extern int vmsver; /* Append VMS version number to file names */
+ extern int vms_native; /* Store in VMS format */
+ extern int vms_case_2; /* ODS2 file name case in VMS. -1: down. */
+ extern int vms_case_5; /* ODS5 file name case in VMS. +1: preserve. */
+
+/* Accomodation for /NAMES = AS_IS with old header files. */
+# define cma$tis_errno_get_addr CMA$TIS_ERRNO_GET_ADDR
+# define lib$establish LIB$ESTABLISH
+# define lib$get_foreign LIB$GET_FOREIGN
+# define lib$get_input LIB$GET_INPUT
+# define lib$sig_to_ret LIB$SIG_TO_RET
+# define ots$cvt_tu_l OTS$CVT_TU_L
+# define str$concat STR$CONCAT
+# define str$find_first_substring STR$FIND_FIRST_SUBSTRING
+# define str$free1_dx STR$FREE1_DX
+# define sys$asctim SYS$ASCTIM
+# define sys$assign SYS$ASSIGN
+# define sys$bintim SYS$BINTIM
+# define sys$close SYS$CLOSE
+# define sys$connect SYS$CONNECT
+# define sys$dassgn SYS$DASSGN
+# define sys$display SYS$DISPLAY
+# define sys$getjpiw SYS$GETJPIW
+# define sys$open SYS$OPEN
+# define sys$parse SYS$PARSE
+# define sys$qiow SYS$QIOW
+# define sys$read SYS$READ
+# define sys$search SYS$SEARCH
+#endif /* VMS */
+#if defined(OS2) || defined(WIN32)
+ extern int use_longname_ea; /* use the .LONGNAME EA as the file's name */
+#endif
+#if defined (QDOS) || defined(QLZIP)
+extern short qlflag;
+#endif
+/* 9/26/04 EG */
+extern int no_wild; /* wildcards are disabled */
+extern int allow_regex; /* 1 = allow [list] matching (regex) */
+extern int wild_stop_at_dir; /* wildcards do not include / in matches */
+#ifdef UNICODE_SUPPORT
+ extern int using_utf8; /* 1 if current character set is UTF-8 */
+# ifdef WIN32
+ extern int no_win32_wide; /* 1 = no wide functions, like GetFileAttributesW() */
+# endif
+#endif
+/* 10/20/04 */
+extern zoff_t dot_size; /* if not 0 then display dots every size buffers */
+extern zoff_t dot_count; /* if dot_size not 0 counts buffers */
+/* status 10/30/04 */
+extern int display_counts; /* display running file count */
+extern int display_bytes; /* display running bytes remaining */
+extern int display_globaldots; /* display dots for archive instead of for each file */
+extern int display_volume; /* display current input and output volume (disk) numbers */
+extern int display_usize; /* display uncompressed bytes */
+extern ulg files_so_far; /* files processed so far */
+extern ulg bad_files_so_far; /* files skipped so far */
+extern ulg files_total; /* files total to process */
+extern uzoff_t bytes_so_far; /* bytes processed so far (from initial scan) */
+extern uzoff_t good_bytes_so_far;/* good bytes read so far */
+extern uzoff_t bad_bytes_so_far;/* bad bytes skipped so far */
+extern uzoff_t bytes_total; /* total bytes to process (from initial scan) */
+/* logfile 6/5/05 */
+extern int logall; /* 0 = warnings/errors, 1 = all */
+extern FILE *logfile; /* pointer to open logfile or NULL */
+extern int logfile_append; /* append to existing logfile */
+extern char *logfile_path; /* pointer to path of logfile */
+#ifdef WIN32
+extern int nonlocal_name; /* Name has non-local characters */
+extern int nonlocal_path; /* Path has non-local characters */
+#endif
+#ifdef UNICODE_SUPPORT
+/* Unicode 10/12/05 */
+extern int use_wide_to_mb_default;/* use the default MB char instead of escape */
+#endif
+
+extern int hidden_files; /* process hidden and system files */
+extern int volume_label; /* add volume label */
+extern int dirnames; /* include directory names */
+extern int filter_match_case; /* 1=match case when filter() */
+extern int diff_mode; /* 1=require --out and only store changed and add */
+#if defined(WIN32)
+extern int only_archive_set; /* only include if DOS archive bit set */
+extern int clear_archive_bits; /* clear DOS archive bit of included files */
+#endif
+extern int linkput; /* Store symbolic links as such */
+extern int noisy; /* False for quiet operation */
+extern int extra_fields; /* 0=create minimum, 1=don't copy old, 2=keep old */
+#ifdef NTSD_EAS
+ extern int use_privileges; /* use security privilege overrides */
+#endif
+extern int use_descriptors; /* use data descriptors (extended headings) */
+extern int allow_empty_archive; /* if no files, create empty archive anyway */
+extern int copy_only; /* 1 = copy archive with no changes */
+extern int zip_to_stdout; /* output to stdout */
+extern int output_seekable; /* 1 = output seekable 3/13/05 EG */
+#ifdef ZIP64_SUPPORT /* zip64 globals 10/4/03 E. Gordon */
+ extern int force_zip64; /* force use of zip64 when streaming from stdin */
+ extern int zip64_entry; /* current entry needs Zip64 */
+ extern int zip64_archive; /* at least 1 entry needs zip64 */
+#endif
+extern int allow_fifo; /* Allow reading Unix FIFOs, waiting if pipe open */
+extern int show_files; /* show files to operate on and exit (=2 log only) */
+
+extern char *tempzip; /* temp file name */
+extern FILE *y; /* output file now global for splits */
+
+#ifdef UNICODE_SUPPORT
+ extern int utf8_force; /* 1=store UTF-8 as standard per AppNote bit 11 */
+#endif
+extern int unicode_escape_all; /* 1=escape all non-ASCII characters in paths */
+extern int unicode_mismatch; /* unicode mismatch is 0=error, 1=warn, 2=ignore, 3=no */
+
+extern time_t scan_delay; /* seconds before display Scanning files message */
+extern time_t scan_dot_time; /* time in seconds between Scanning files dots */
+extern time_t scan_start; /* start of file scan */
+extern time_t scan_last; /* time of last message */
+extern int scan_started; /* scan has started */
+extern uzoff_t scan_count; /* Used for "Scanning files..." message */
+
+extern ulg before; /* 0=ignore, else exclude files before this time */
+extern ulg after; /* 0=ignore, else exclude files newer than this time */
+
+/* in split globals */
+
+extern ulg total_disks;
+
+extern ulg current_in_disk;
+extern uzoff_t current_in_offset;
+extern ulg skip_current_disk;
+
+
+/* out split globals */
+
+extern ulg current_local_disk; /* disk with current local header */
+
+extern ulg current_disk; /* current disk number */
+extern ulg cd_start_disk; /* central directory start disk */
+extern uzoff_t cd_start_offset; /* offset of start of cd on cd start disk */
+extern uzoff_t cd_entries_this_disk; /* cd entries this disk */
+extern uzoff_t total_cd_entries; /* total cd entries in new/updated archive */
+extern ulg zip64_eocd_disk; /* disk with Zip64 EOCD Record */
+extern uzoff_t zip64_eocd_offset; /* offset of Zip64 EOCD Record */
+/* for split method 1 (keep split with local header open and update) */
+extern char *current_local_tempname; /* name of temp file */
+extern FILE *current_local_file; /* file pointer for current local header */
+extern uzoff_t current_local_offset; /* offset to start of current local header */
+/* global */
+extern uzoff_t bytes_this_split; /* bytes written to current split */
+extern int read_split_archive; /* 1=scanzipf_reg detected spanning signature */
+extern int split_method; /* 0=no splits, 1=seekable, 2=data descs, -1=no */
+extern uzoff_t split_size; /* how big each split should be */
+extern int split_bell; /* when pause for next split ring bell */
+extern uzoff_t bytes_prev_splits; /* total bytes written to all splits before this */
+extern uzoff_t bytes_this_entry; /* bytes written for this entry across all splits */
+extern int noisy_splits; /* note when splits are being created */
+extern int mesg_line_started; /* 1=started writing a line to mesg */
+extern int logfile_line_started; /* 1=started writing a line to logfile */
+extern char *key; /* Scramble password or NULL */
+extern char *tempath; /* Path for temporary files */
+extern FILE *mesg; /* Where informational output goes */
+extern char *zipfile; /* New or existing zip archive (zip file) */
+extern FILE *in_file; /* Current input file for spits */
+extern char *in_path; /* Name of input archive, used to track reading splits */
+extern char *in_split_path; /* in split path */
+extern char *out_path; /* Name of output file, usually same as zipfile */
+extern int zip_attributes;
+
+/* zip64 support 08/31/2003 R.Nausedat */
+extern uzoff_t zipbeg; /* Starting offset of zip structures */
+extern uzoff_t cenbeg; /* Starting offset of central directory */
+extern uzoff_t tempzn; /* Count of bytes written to output zip file */
+
+/* NOTE: zcount and fcount cannot exceed "size_t" (resp. "extent") range.
+ This is an internal limitation built into Zip's action handling:
+ Zip keeps "{z|f}count * struct {z|f}list" arrays in (flat) memory,
+ for sorting, file matching, and building the central-dir structures.
+ */
+
+extern struct zlist far *zfiles;/* Pointer to list of files in zip file */
+extern extent zcount; /* Number of files in zip file */
+extern int zipfile_exists; /* 1 if zipfile exists */
+extern ush zcomlen; /* Length of zip file comment */
+extern char *zcomment; /* Zip file comment (not zero-terminated) */
+extern struct flist far **fsort;/* List of files sorted by name */
+extern struct zlist far **zsort;/* List of files sorted by name */
+#ifdef UNICODE_SUPPORT
+extern struct zlist far **zusort;/* List of files sorted by zuname */
+#endif
+extern struct flist far *found; /* List of names found */
+extern struct flist far *far *fnxt; /* Where to put next in found list */
+extern extent fcount; /* Count of names in found list */
+
+extern struct plist *patterns; /* List of patterns to be matched */
+extern unsigned pcount; /* number of patterns */
+extern unsigned icount; /* number of include only patterns */
+extern unsigned Rcount; /* number of -R include patterns */
+
+#ifdef IZ_CHECK_TZ
+extern int zp_tz_is_valid; /* signals "timezone info is available" */
+#endif
+#if (defined(MACOS) || defined(WINDLL))
+extern int zipstate; /* flag "zipfile has been stat()'ed */
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# ifdef MSDOS
+# undef stderr
+# define stderr stdout
+# endif
+# define diag(where) fprintf(stderr, "zip diagnostic: %s\n", where)
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# ifdef THEOS
+# define Trace(x) _fprintf x
+# define Tracev(x) {if (verbose) _fprintf x ;}
+# define Tracevv(x) {if (verbose>1) _fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) _fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) _fprintf x ;}
+# else
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+# endif
+#else
+# define diag(where)
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+#ifdef DEBUGNAMES
+# define free(x) { int *v;Free(x); v=x;*v=0xdeadbeef;x=(void *)0xdeadbeef; }
+#endif
+
+/* Public function prototypes */
+
+#ifndef UTIL
+#ifdef USE_ZIPMAIN
+int zipmain OF((int, char **));
+#else
+int main OF((int, char **));
+#endif /* USE_ZIPMAIN */
+#endif
+
+#ifdef EBCDIC
+extern int aflag;
+#endif /* EBCDIC */
+#ifdef CMS_MVS
+extern int bflag;
+#endif /* CMS_MVS */
+void zipmessage_nl OF((ZCONST char *, int));
+void zipmessage OF((ZCONST char *, ZCONST char *));
+void zipwarn OF((ZCONST char *, ZCONST char *));
+void ziperr OF((int, ZCONST char *));
+#ifdef UTIL
+# define error(msg) ziperr(ZE_LOGIC, msg)
+#else
+ void error OF((ZCONST char *));
+# ifdef VMSCLI
+ void help OF((void));
+# endif
+ int encr_passwd OF((int, char *, int, ZCONST char *));
+#endif
+
+ /* in zipup.c */
+#ifndef UTIL
+ /* zip64 support 08/31/2003 R.Nausedat */
+ int percent OF((uzoff_t, uzoff_t));
+
+ int zipup OF((struct zlist far *));
+# ifdef USE_ZLIB
+ void zl_deflate_free OF((void));
+# else
+ void flush_outbuf OF((char *, unsigned *));
+ int seekable OF((void));
+ extern unsigned (*read_buf) OF((char *, unsigned int));
+# endif /* !USE_ZLIB */
+# ifdef ZP_NEED_MEMCOMPR
+ ulg memcompress OF((char *, ulg, char *, ulg));
+# endif
+# ifdef BZIP2_SUPPORT
+ void bz_compress_free OF((void));
+# endif
+#endif /* !UTIL */
+
+ /* in zipfile.c */
+#ifndef UTIL
+ struct zlist far *zsearch OF((ZCONST char *));
+# ifdef USE_EF_UT_TIME
+ int get_ef_ut_ztime OF((struct zlist far *, iztimes *));
+# endif /* USE_EF_UT_TIME */
+ int trash OF((void));
+#endif /* !UTIL */
+char *ziptyp OF((char *));
+int readzipfile OF((void));
+int putlocal OF((struct zlist far *, int));
+int putextended OF((struct zlist far *));
+int putcentral OF((struct zlist far *));
+/* zip64 support 09/05/2003 R.Nausedat */
+int putend OF((uzoff_t, uzoff_t, uzoff_t, extent, char *));
+/* moved seekable to separate function 3/14/05 EG */
+int is_seekable OF((FILE *));
+int zipcopy OF((struct zlist far *));
+int readlocal OF((struct zlist far **, struct zlist far *));
+/* made global for handling extra fields */
+char *get_extra_field OF((ush, char *, unsigned));
+char *copy_nondup_extra_fields OF((char *, unsigned, char *, unsigned, unsigned *));
+
+ /* in fileio.c */
+#ifndef UTIL
+ char *getnam OF((FILE *));
+ struct flist far *fexpel OF((struct flist far *));
+ char *last OF((char *, int));
+# ifdef UNICODE_SUPPORT
+ wchar_t *lastw OF((wchar_t *, wchar_t));
+# endif
+ char *msname OF((char *));
+# ifdef UNICODE_SUPPORT
+ wchar_t *msnamew OF((wchar_t *));
+# endif
+ int check_dup OF((void));
+ int filter OF((char *, int));
+ int newname OF((char *, int, int));
+# ifdef UNICODE_SUPPORT
+# ifdef WIN32
+ int newnamew OF((wchar_t *, int, int));
+# endif
+# endif
+ /* used by copy mode */
+ int proc_archive_name OF((char *, int));
+#endif /* !UTIL */
+#if (!defined(UTIL) || defined(W32_STATROOT_FIX))
+ time_t dos2unixtime OF((ulg));
+#endif
+#ifndef UTIL
+ ulg dostime OF((int, int, int, int, int, int));
+ ulg unix2dostime OF((time_t *));
+ int issymlnk OF((ulg a));
+# ifdef S_IFLNK
+# define rdsymlnk(p,b,n) readlink(p,b,n)
+/* extern int readlink OF((char *, char *, int)); */
+# else /* !S_IFLNK */
+# define rdsymlnk(p,b,n) (0)
+# endif /* !S_IFLNK */
+#endif /* !UTIL */
+
+int destroy OF((char *));
+int replace OF((char *, char *));
+int getfileattr OF((char *));
+int setfileattr OF((char *, int));
+char *tempname OF((char *));
+
+/* for splits */
+int close_split OF((ulg, FILE *, char *));
+int ask_for_split_read_path OF((ulg));
+int ask_for_split_write_path OF((ulg));
+char *get_in_split_path OF((char *, ulg));
+char *find_in_split_path OF((char *, ulg));
+char *get_out_split_path OF((char *, ulg));
+int rename_split OF((char *, char *));
+int set_filetype OF((char *));
+
+int bfcopy OF((uzoff_t));
+
+int fcopy OF((FILE *, FILE *, uzoff_t));
+
+#ifdef ZMEM
+ char *memset OF((char *, int, unsigned int));
+ char *memcpy OF((char *, char *, unsigned int));
+ int memcmp OF((char *, char *, unsigned int));
+#endif /* ZMEM */
+
+ /* in system dependent fileio code (<system>.c) */
+#ifndef UTIL
+# ifdef PROCNAME
+ int wild OF((char *));
+# endif
+ char *in2ex OF((char *));
+ char *ex2in OF((char *, int, int *));
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ int has_win32_wide OF((void));
+ wchar_t *in2exw OF((wchar_t *));
+ wchar_t *ex2inw OF((wchar_t *, int, int *));
+ int procnamew OF((wchar_t *, int));
+#endif
+ int procname OF((char *, int));
+ void stamp OF((char *, ulg));
+
+ ulg filetime OF((char *, ulg *, zoff_t *, iztimes *));
+ /* Windows Unicode */
+# ifdef UNICODE_SUPPORT
+# ifdef WIN32
+ ulg filetimew OF((wchar_t *, ulg *, zoff_t *, iztimes *));
+ char *get_win32_utf8path OF((char *));
+ wchar_t *local_to_wchar_string OF ((char *));
+# endif
+# endif
+
+# if !(defined(VMS) && defined(VMS_PK_EXTRA))
+ int set_extra_field OF((struct zlist far *, iztimes *));
+# endif /* ?(VMS && VMS_PK_EXTRA) */
+ int deletedir OF((char *));
+# ifdef MY_ZCALLOC
+ zvoid far *zcalloc OF((unsigned int, unsigned int));
+ zvoid zcfree OF((zvoid far *));
+# endif /* MY_ZCALLOC */
+#endif /* !UTIL */
+void version_local OF((void));
+
+ /* in util.c */
+#ifndef UTIL
+int fseekable OF((FILE *));
+char *isshexp OF((char *));
+#ifdef UNICODE_SUPPORT
+# ifdef WIN32
+ wchar_t *isshexpw OF((wchar_t *));
+ int dosmatchw OF((ZCONST wchar_t *, ZCONST wchar_t *, int));
+# endif
+#endif
+int shmatch OF((ZCONST char *, ZCONST char *, int));
+# if defined(DOS) || defined(WIN32)
+ int dosmatch OF((ZCONST char *, ZCONST char *, int));
+# endif /* DOS || WIN32 */
+#endif /* !UTIL */
+
+/* functions to convert zoff_t to a string */
+char *zip_fuzofft OF((uzoff_t, char *, char*));
+char *zip_fzofft OF((zoff_t, char *, char*));
+
+/* read and write number strings like 10M */
+int DisplayNumString OF ((FILE *file, uzoff_t i));
+int WriteNumString OF((uzoff_t num, char *outstring));
+uzoff_t ReadNumString OF((char *numstring));
+
+/* returns true if abbrev is abbreviation for string */
+int abbrevmatch OF((char *, char *, int, int));
+
+void init_upper OF((void));
+int namecmp OF((ZCONST char *string1, ZCONST char *string2));
+
+#ifdef EBCDIC
+ char *strtoasc OF((char *str1, ZCONST char *str2));
+ char *strtoebc OF((char *str1, ZCONST char *str2));
+ char *memtoasc OF((char *mem1, ZCONST char *mem2, unsigned len));
+ char *memtoebc OF((char *mem1, ZCONST char *mem2, unsigned len));
+#endif /* EBCDIC */
+#ifdef IZ_ISO2OEM_ARRAY
+ char *str_iso_to_oem OF((char *dst, ZCONST char *src));
+#endif
+#ifdef IZ_OEM2ISO_ARRAY
+ char *str_oem_to_iso OF((char *dst, ZCONST char *src));
+#endif
+
+zvoid far **search OF((ZCONST zvoid *, ZCONST zvoid far **, extent,
+ int (*)(ZCONST zvoid *, ZCONST zvoid far *)));
+void envargs OF((int *, char ***, char *, char *));
+void expand_args OF((int *, char ***));
+
+int is_text_buf OF((ZCONST char *buf_ptr, unsigned buf_size));
+/* this is no longer used ...
+unsigned int adler16 OF((unsigned int, ZCONST uch *, extent));
+*/
+ /* crc functions are now declared in crc32.h */
+
+#ifndef UTIL
+#ifndef USE_ZLIB
+ /* in deflate.c */
+void lm_init OF((int, ush *));
+void lm_free OF((void));
+
+uzoff_t deflate OF((void));
+
+ /* in trees.c */
+void ct_init OF((ush *, int *));
+int ct_tally OF((int, int));
+uzoff_t flush_block OF((char far *, ulg, int));
+void bi_init OF((char *, unsigned int, int));
+#endif /* !USE_ZLIB */
+#endif /* !UTIL */
+
+ /* in system specific assembler code, replacing C code in trees.c */
+#if defined(ASMV) && defined(RISCOS)
+ void send_bits OF((int, int));
+ unsigned bi_reverse OF((unsigned int, int));
+#endif /* ASMV && RISCOS */
+
+/*---------------------------------------------------------------------------
+ VMS-only functions:
+ ---------------------------------------------------------------------------*/
+#ifdef VMS
+ int vms_stat OF((char *, stat_t *)); /* vms.c */
+ void vms_exit OF((int)); /* vms.c */
+#ifndef UTIL
+#ifdef VMSCLI
+ ulg vms_zip_cmdline OF((int *, char ***)); /* cmdline.c */
+ void VMSCLI_help OF((void)); /* cmdline.c */
+#endif /* VMSCLI */
+#endif /* !UTIL */
+#endif /* VMS */
+
+/*
+#ifdef ZIP64_SUPPORT
+ update_local_Zip64_extra_field OF((struct zlist far *, FILE *));
+#endif
+*/
+
+/*---------------------------------------------------------------------------
+ WIN32-only functions:
+ ---------------------------------------------------------------------------*/
+#ifdef WIN32
+ int ZipIsWinNT OF((void)); /* win32.c */
+ int ClearArchiveBit OF((char *)); /* win32.c */
+# ifdef UNICODE_SUPPORT
+ int ClearArchiveBitW OF((wchar_t *)); /* win32.c */
+# endif
+#endif /* WIN32 */
+
+#if (defined(WINDLL) || defined(DLL_ZIPAPI))
+/*---------------------------------------------------------------------------
+ Prototypes for public Zip API (DLL) functions.
+ ---------------------------------------------------------------------------*/
+#include "api.h"
+#endif /* WINDLL || DLL_ZIPAPI */
+
+
+ /* WIN32_OEM */
+#ifdef WIN32
+/*
+# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+ /* convert oem to ansi string */
+ char *oem_to_local_string OF((char *, char *));
+/*
+# endif
+*/
+#endif
+
+#ifdef WIN32
+/*
+# if defined(UNICODE_SUPPORT) || defined(WIN32_OEM)
+*/
+ /* convert local string to oem string */
+ char *local_to_oem_string OF((char *, char *));
+/*
+# endif
+*/
+#endif
+
+
+
+/*---------------------------------------------------------------------
+ Unicode Support
+ 28 August 2005
+ ---------------------------------------------------------------------*/
+#ifdef UNICODE_SUPPORT
+
+ /* Default character when a zwchar too big for wchar_t */
+# define zwchar_to_wchar_t_default_char '_'
+
+ /* Default character string when wchar_t does not convert to mb */
+# define wide_to_mb_default_string "_"
+
+ /* wide character type */
+ typedef unsigned long zwchar;
+
+ /* check if string is all ASCII */
+ int is_ascii_string OF((char *));
+#ifdef WIN32
+ int is_ascii_stringw OF((wchar_t *));
+ zwchar *wchar_to_wide_string OF((wchar_t *));
+#endif
+
+ /* convert UTF-8 string to multi-byte string */
+ char *utf8_to_local_string OF((char *));
+ char *utf8_to_escape_string OF((char *));
+
+ /* convert UTF-8 string to wide string */
+ zwchar *utf8_to_wide_string OF((char *));
+
+ /* convert wide string to multi-byte string */
+ char *wide_to_local_string OF((zwchar *));
+ char *wide_to_escape_string OF((zwchar *));
+ char *local_to_escape_string OF((char *));
+#ifdef WIN32
+ /* convert UTF-8 to wchar */
+ wchar_t *utf8_to_wchar_string OF ((char *));
+
+ char *wchar_to_local_string OF((wchar_t *));
+#endif
+
+ /* convert local string to multi-byte display string */
+ char *local_to_display_string OF((char *));
+
+ /* convert wide character to escape string */
+ char *wide_char_to_escape_string OF((unsigned long));
+
+#if 0
+ /* convert escape string to wide character */
+ unsigned long escape_string_to_wide OF((char *));
+#endif
+
+ /* convert local to UTF-8 */
+ char *local_to_utf8_string OF ((char *));
+
+ /* convert local to wide string */
+ zwchar *local_to_wide_string OF ((char *));
+
+ /* convert wide string to UTF-8 */
+ char *wide_to_utf8_string OF((zwchar *));
+#ifdef WIN32
+ char *wchar_to_utf8_string OF((wchar_t *));
+#endif
+
+#endif /* UNICODE_SUPPORT */
+
+
+/*---------------------------------------------------
+ * Split archives
+ *
+ * 10/20/05 EG
+ */
+
+#define BFWRITE_DATA 0
+#define BFWRITE_LOCALHEADER 1
+#define BFWRITE_CENTRALHEADER 2
+#define BFWRITE_HEADER 3 /* data descriptor or end records */
+
+size_t bfwrite OF((ZCONST void *buffer, size_t size, size_t count,
+ int));
+
+/* for putlocal() */
+#define PUTLOCAL_WRITE 0
+#define PUTLOCAL_REWRITE 1
+
+
+/*--------------------------------------------------------------------
+ Long option support
+ 23 August 2003
+ See fileio.c
+ --------------------------------------------------------------------*/
+
+/* The below is for use in the caller-provided options table */
+
+/* value_type - value is always returned as a string. */
+#define o_NO_VALUE 0 /* this option does not take a value */
+#define o_REQUIRED_VALUE 1 /* this option requires a value */
+#define o_OPTIONAL_VALUE 2 /* value is optional (see get_option() for details) */
+#define o_VALUE_LIST 3 /* this option takes a list of values */
+#define o_ONE_CHAR_VALUE 4 /* next char is value (does not end short opt string) */
+#define o_NUMBER_VALUE 5 /* value is integer (does not end short opt string) */
+
+
+/* negatable - a dash following the option (but before any value) sets negated. */
+#define o_NOT_NEGATABLE 0 /* trailing '-' to negate either starts value or generates error */
+#define o_NEGATABLE 1 /* trailing '-' sets negated to TRUE */
+
+
+/* option_num can be this when option not in options table */
+#define o_NO_OPTION_MATCH -1
+
+/* special values returned by get_option - do not use these as option IDs */
+#define o_NON_OPTION_ARG ((unsigned long) 0xFFFF) /* returned for non-option
+ args */
+#define o_ARG_FILE_ERR ((unsigned long) 0xFFFE) /* internal recursion
+ return (user never sees) */
+
+/* options array is set in zip.c */
+struct option_struct {
+ char *shortopt; /* char * to sequence of char that is short option */
+ char Far *longopt; /* char * to long option string */
+ int value_type; /* from above */
+ int negatable; /* from above */
+ unsigned long option_ID; /* value returned by get_option when this option is found */
+ char Far *name; /* optional string for option returned on some errors */
+};
+extern struct option_struct far options[];
+
+
+/* moved here from fileio.c to make global - 10/6/05 EG */
+
+/* If will support wide for Unicode then need to add */
+ /* multi-byte */
+#ifdef _MBCS
+# ifndef MULTIBYTE_GETOPTNS
+# define MULTIBYTE_GETOPTNS
+# endif
+#endif
+#ifdef MULTIBYTE_GETOPTNS
+ int mb_clen OF((ZCONST char *));
+# define MB_CLEN(ptr) mb_clen(ptr)
+# define MB_NEXTCHAR(ptr) ((ptr) += MB_CLEN(ptr))
+#else
+ /* no multi-byte */
+# define MB_CLEN(ptr) (1)
+# define MB_NEXTCHAR(ptr) ((ptr)++)
+#endif
+
+
+/* function prototypes */
+
+/* get the next option from args */
+unsigned long get_option OF((char ***pargs, int *argc, int *argnum, int *optchar,
+ char **value, int *negated, int *first_nonopt_arg,
+ int *option_num, int recursion_depth));
+
+/* copy args - copy an args array, allocating space as needed */
+char **copy_args OF((char **args, int max_args));
+
+/* free args - free args created with one of these functions */
+int free_args OF ((char **args));
+
+/* insert arg - copy an arg into args */
+int insert_arg OF ((char ***args, ZCONST char *arg, int insert_at,
+ int free_args));
+
+
+/*--------------------------------------------------------------------
+ End of Long option support
+ --------------------------------------------------------------------*/
+
+
+#endif /* !__zip_h */
+/* end of zip.h */
diff --git a/zip.txt b/zip.txt
new file mode 100644
index 0000000..85f89b5
--- /dev/null
+++ b/zip.txt
@@ -0,0 +1,2027 @@
+ZIP(1L) ZIP(1L)
+
+NAME
+ zip - package and compress (archive) files
+
+SYNOPSIS
+ zip [-aABcdDeEfFghjklLmoqrRSTuvVwXyz!@$] [--longoption ...] [-b path]
+ [-n suffixes] [-t date] [-tt date] [zipfile [file ...]] [-xi list]
+
+ zipcloak (see separate man page)
+
+ zipnote (see separate man page)
+
+ zipsplit (see separate man page)
+
+ Note: Command line processing in zip has been changed to support long
+ options and handle all options and arguments more consistently. Some
+ old command lines that depend on command line inconsistencies may no
+ longer work.
+
+DESCRIPTION
+ zip is a compression and file packaging utility for Unix, VMS, MSDOS,
+ OS/2, Windows 9x/NT/XP, Minix, Atari, Macintosh, Amiga, and Acorn RISC
+ OS. It is analogous to a combination of the Unix commands tar(1) and
+ compress(1) and is compatible with PKZIP (Phil Katz's ZIP for MSDOS
+ systems).
+
+ A companion program (unzip(1L)) unpacks zip archives. The zip and
+ unzip(1L) programs can work with archives produced by PKZIP (supporting
+ most PKZIP features up to PKZIP version 4.6), and PKZIP and PKUNZIP can
+ work with archives produced by zip (with some exceptions, notably
+ streamed archives, but recent changes in the zip file standard may
+ facilitate better compatibility). zip version 3.0 is compatible with
+ PKZIP 2.04 and also supports the Zip64 extensions of PKZIP 4.5 which
+ allow archives as well as files to exceed the previous 2 GB limit (4 GB
+ in some cases). zip also now supports bzip2 compression if the bzip2
+ library is included when zip is compiled. Note that PKUNZIP 1.10 can-
+ not extract files produced by PKZIP 2.04 or zip 3.0. You must use PKUN-
+ ZIP 2.04g or unzip 5.0p1 (or later versions) to extract them.
+
+ See the EXAMPLES section at the bottom of this page for examples of
+ some typical uses of zip.
+
+ Large Archives and Zip64. zip automatically uses the Zip64 extensions
+ when files larger than 4 GB are added to an archive, an archive con-
+ taining Zip64 entries is updated (if the resulting archive still needs
+ Zip64), the size of the archive will exceed 4 GB, or when the number of
+ entries in the archive will exceed about 64K. Zip64 is also used for
+ archives streamed from standard input as the size of such archives are
+ not known in advance, but the option -fz- can be used to force zip to
+ create PKZIP 2 compatible archives (as long as Zip64 extensions are not
+ needed). You must use a PKZIP 4.5 compatible unzip, such as unzip 6.0
+ or later, to extract files using the Zip64 extensions.
+
+ In addition, streamed archives, entries encrypted with standard encryp-
+ tion, or split archives created with the pause option may not be com-
+ patible with PKZIP as data descriptors are used and PKZIP at the time
+ of this writing does not support data descriptors (but recent changes
+ in the PKWare published zip standard now include some support for the
+ data descriptor format zip uses).
+
+ Mac OS X. Though previous Mac versions had their own zip port, zip
+ supports Mac OS X as part of the Unix port and most Unix features
+ apply. References to "MacOS" below generally refer to MacOS versions
+ older than OS X. Support for some Mac OS features in the Unix Mac OS X
+ port, such as resource forks, is expected in the next zip release.
+
+ For a brief help on zip and unzip, run each without specifying any
+ parameters on the command line.
+
+USE
+ The program is useful for packaging a set of files for distribution;
+ for archiving files; and for saving disk space by temporarily compress-
+ ing unused files or directories.
+
+ The zip program puts one or more compressed files into a single zip
+ archive, along with information about the files (name, path, date, time
+ of last modification, protection, and check information to verify file
+ integrity). An entire directory structure can be packed into a zip
+ archive with a single command. Compression ratios of 2:1 to 3:1 are
+ common for text files. zip has one compression method (deflation) and
+ can also store files without compression. (If bzip2 support is added,
+ zip can also compress using bzip2 compression, but such entries require
+ a reasonably modern unzip to decompress. When bzip2 compression is
+ selected, it replaces deflation as the default method.) zip automati-
+ cally chooses the better of the two (deflation or store or, if bzip2 is
+ selected, bzip2 or store) for each file to be compressed.
+
+ Command format. The basic command format is
+
+ zip options archive inpath inpath ...
+
+ where archive is a new or existing zip archive and inpath is a direc-
+ tory or file path optionally including wildcards. When given the name
+ of an existing zip archive, zip will replace identically named entries
+ in the zip archive (matching the relative names as stored in the
+ archive) or add entries for new names. For example, if foo.zip exists
+ and contains foo/file1 and foo/file2, and the directory foo contains
+ the files foo/file1 and foo/file3, then:
+
+ zip -r foo.zip foo
+
+ or more concisely
+
+ zip -r foo foo
+
+ will replace foo/file1 in foo.zip and add foo/file3 to foo.zip. After
+ this, foo.zip contains foo/file1, foo/file2, and foo/file3, with
+ foo/file2 unchanged from before.
+
+ So if before the zip command is executed foo.zip has:
+
+ foo/file1 foo/file2
+
+ and directory foo has:
+
+ file1 file3
+
+ then foo.zip will have:
+
+ foo/file1 foo/file2 foo/file3
+
+ where foo/file1 is replaced and foo/file3 is new.
+
+ -@ file lists. If a file list is specified as -@ [Not on MacOS], zip
+ takes the list of input files from standard input instead of from the
+ command line. For example,
+
+ zip -@ foo
+
+ will store the files listed one per line on stdin in foo.zip.
+
+ Under Unix, this option can be used to powerful effect in conjunction
+ with the find (1) command. For example, to archive all the C source
+ files in the current directory and its subdirectories:
+
+ find . -name "*.[ch]" -print | zip source -@
+
+ (note that the pattern must be quoted to keep the shell from expanding
+ it).
+
+ Streaming input and output. zip will also accept a single dash ("-")
+ as the zip file name, in which case it will write the zip file to stan-
+ dard output, allowing the output to be piped to another program. For
+ example:
+
+ zip -r - . | dd of=/dev/nrst0 obs=16k
+
+ would write the zip output directly to a tape with the specified block
+ size for the purpose of backing up the current directory.
+
+ zip also accepts a single dash ("-") as the name of a file to be com-
+ pressed, in which case it will read the file from standard input,
+ allowing zip to take input from another program. For example:
+
+ tar cf - . | zip backup -
+
+ would compress the output of the tar command for the purpose of backing
+ up the current directory. This generally produces better compression
+ than the previous example using the -r option because zip can take
+ advantage of redundancy between files. The backup can be restored using
+ the command
+
+ unzip -p backup | tar xf -
+
+ When no zip file name is given and stdout is not a terminal, zip acts
+ as a filter, compressing standard input to standard output. For exam-
+ ple,
+
+ tar cf - . | zip | dd of=/dev/nrst0 obs=16k
+
+ is equivalent to
+
+ tar cf - . | zip - - | dd of=/dev/nrst0 obs=16k
+
+ zip archives created in this manner can be extracted with the program
+ funzip which is provided in the unzip package, or by gunzip which is
+ provided in the gzip package (but some gunzip may not support this if
+ zip used the Zip64 extensions). For example:
+
+ dd if=/dev/nrst0 ibs=16k | funzip | tar xvf -
+
+ The stream can also be saved to a file and unzip used.
+
+ If Zip64 support for large files and archives is enabled and zip is
+ used as a filter, zip creates a Zip64 archive that requires a PKZIP 4.5
+ or later compatible unzip to read it. This is to avoid amgibuities in
+ the zip file structure as defined in the current zip standard (PKWARE
+ AppNote) where the decision to use Zip64 needs to be made before data
+ is written for the entry, but for a stream the size of the data is not
+ known at that point. If the data is known to be smaller than 4 GB, the
+ option -fz- can be used to prevent use of Zip64, but zip will exit with
+ an error if Zip64 was in fact needed. zip 3 and unzip 6 and later can
+ read archives with Zip64 entries. Also, zip removes the Zip64 exten-
+ sions if not needed when archive entries are copied (see the -U
+ (--copy) option).
+
+ When directing the output to another file, note that all options should
+ be before the redirection including -x. For example:
+
+ zip archive "*.h" "*.c" -x donotinclude.h orthis.h > tofile
+
+ Zip files. When changing an existing zip archive, zip will write a
+ temporary file with the new contents, and only replace the old one when
+ the process of creating the new version has been completed without
+ error.
+
+ If the name of the zip archive does not contain an extension, the
+ extension .zip is added. If the name already contains an extension
+ other than .zip, the existing extension is kept unchanged. However,
+ split archives (archives split over multiple files) require the .zip
+ extension on the last split.
+
+ Scanning and reading files. When zip starts, it scans for files to
+ process (if needed). If this scan takes longer than about 5 seconds,
+ zip will display a "Scanning files" message and start displaying
+ progress dots every 2 seconds or every so many entries processed,
+ whichever takes longer. If there is more than 2 seconds between dots
+ it could indicate that finding each file is taking time and could mean
+ a slow network connection for example. (Actually the initial file scan
+ is a two-step process where the directory scan is followed by a sort
+ and these two steps are separated with a space in the dots. If updat-
+ ing an existing archive, a space also appears between the existing file
+ scan and the new file scan.) The scanning files dots are not con-
+ trolled by the -ds dot size option, but the dots are turned off by the
+ -q quiet option. The -sf show files option can be used to scan for
+ files and get the list of files scanned without actually processing
+ them.
+
+ If zip is not able to read a file, it issues a warning but continues.
+ See the -MM option below for more on how zip handles patterns that are
+ not matched and files that are not readable. If some files were
+ skipped, a warning is issued at the end of the zip operation noting how
+ many files were read and how many skipped.
+
+ Command modes. zip now supports two distinct types of command modes,
+ external and internal. The external modes (add, update, and freshen)
+ read files from the file system (as well as from an existing archive)
+ while the internal modes (delete and copy) operate exclusively on
+ entries in an existing archive.
+
+ add
+ Update existing entries and add new files. If the archive does
+ not exist create it. This is the default mode.
+
+ update (-u)
+ Update existing entries if newer on the file system and add new
+ files. If the archive does not exist issue warning then create
+ a new archive.
+
+ freshen (-f)
+ Update existing entries of an archive if newer on the file sys-
+ tem. Does not add new files to the archive.
+
+ delete (-d)
+ Select entries in an existing archive and delete them.
+
+ copy (-U)
+ Select entries in an existing archive and copy them to a new
+ archive. This new mode is similar to update but command line
+ patterns select entries in the existing archive rather than
+ files from the file system and it uses the --out option to write
+ the resulting archive to a new file rather than update the
+ existing archive, leaving the original archive unchanged.
+
+ The new File Sync option (-FS) is also considered a new mode, though it
+ is similar to update. This mode synchronizes the archive with the
+ files on the OS, only replacing files in the archive if the file time
+ or size of the OS file is different, adding new files, and deleting
+ entries from the archive where there is no matching file. As this mode
+ can delete entries from the archive, consider making a backup copy of
+ the archive.
+
+ Also see -DF for creating difference archives.
+
+ See each option description below for details and the EXAMPLES section
+ below for examples.
+
+ Split archives. zip version 3.0 and later can create split archives.
+ A split archive is a standard zip archive split over multiple files.
+ (Note that split archives are not just archives split in to pieces, as
+ the offsets of entries are now based on the start of each split. Con-
+ catenating the pieces together will invalidate these offsets, but unzip
+ can usually deal with it. zip will usually refuse to process such a
+ spliced archive unless the -FF fix option is used to fix the offsets.)
+
+ One use of split archives is storing a large archive on multiple remov-
+ able media. For a split archive with 20 split files the files are typ-
+ ically named (replace ARCHIVE with the name of your archive)
+ ARCHIVE.z01, ARCHIVE.z02, ..., ARCHIVE.z19, ARCHIVE.zip. Note that the
+ last file is the .zip file. In contrast, spanned archives are the
+ original multi-disk archive generally requiring floppy disks and using
+ volume labels to store disk numbers. zip supports split archives but
+ not spanned archives, though a procedure exists for converting split
+ archives of the right size to spanned archives. The reverse is also
+ true, where each file of a spanned archive can be copied in order to
+ files with the above names to create a split archive.
+
+ Use -s to set the split size and create a split archive. The size is
+ given as a number followed optionally by one of k (kB), m (MB), g (GB),
+ or t (TB) (the default is m). The -sp option can be used to pause zip
+ between splits to allow changing removable media, for example, but read
+ the descriptions and warnings for both -s and -sp below.
+
+ Though zip does not update split archives, zip provides the new option
+ -O (--output-file or --out) to allow split archives to be updated and
+ saved in a new archive. For example,
+
+ zip inarchive.zip foo.c bar.c --out outarchive.zip
+
+ reads archive inarchive.zip, even if split, adds the files foo.c and
+ bar.c, and writes the resulting archive to outarchive.zip. If inar-
+ chive.zip is split then outarchive.zip defaults to the same split size.
+ Be aware that if outarchive.zip and any split files that are created
+ with it already exist, these are always overwritten as needed without
+ warning. This may be changed in the future.
+
+ Unicode. Though the zip standard requires storing paths in an archive
+ using a specific character set, in practice zips have stored paths in
+ archives in whatever the local character set is. This creates problems
+ when an archive is created or updated on a system using one character
+ set and then extracted on another system using a different character
+ set. When compiled with Unicode support enabled on platforms that sup-
+ port wide characters, zip now stores, in addition to the standard local
+ path for backward compatibility, the UTF-8 translation of the path.
+ This provides a common universal character set for storing paths that
+ allows these paths to be fully extracted on other systems that support
+ Unicode and to match as close as possible on systems that don't.
+
+ On Win32 systems where paths are internally stored as Unicode but rep-
+ resented in the local character set, it's possible that some paths will
+ be skipped during a local character set directory scan. zip with Uni-
+ code support now can read and store these paths. Note that Win 9x sys-
+ tems and FAT file systems don't fully support Unicode.
+
+ Be aware that console windows on Win32 and Unix, for example, sometimes
+ don't accurately show all characters due to how each operating system
+ switches in character sets for display. However, directory navigation
+ tools should show the correct paths if the needed fonts are loaded.
+
+ Command line format. This version of zip has updated command line pro-
+ cessing and support for long options.
+
+ Short options take the form
+
+ -s[-][s[-]...][value][=value][ value]
+
+ where s is a one or two character short option. A short option that
+ takes a value is last in an argument and anything after it is taken as
+ the value. If the option can be negated and "-" immediately follows
+ the option, the option is negated. Short options can also be given as
+ separate arguments
+
+ -s[-][value][=value][ value] -s[-][value][=value][ value] ...
+
+ Short options in general take values either as part of the same argu-
+ ment or as the following argument. An optional = is also supported.
+ So
+
+ -ttmmddyyyy
+
+ and
+
+ -tt=mmddyyyy
+
+ and
+
+ -tt mmddyyyy
+
+ all work. The -x and -i options accept lists of values and use a
+ slightly different format described below. See the -x and -i options.
+
+ Long options take the form
+
+ --longoption[-][=value][ value]
+
+ where the option starts with --, has a multicharacter name, can include
+ a trailing dash to negate the option (if the option supports it), and
+ can have a value (option argument) specified by preceeding it with =
+ (no spaces). Values can also follow the argument. So
+
+ --before-date=mmddyyyy
+
+ and
+
+ --before-date mmddyyyy
+
+ both work.
+
+ Long option names can be shortened to the shortest unique abbreviation.
+ See the option descriptions below for which support long options. To
+ avoid confusion, avoid abbreviating a negatable option with an embedded
+ dash ("-") at the dash if you plan to negate it (the parser would con-
+ sider a trailing dash, such as for the option --some-option using
+ --some- as the option, as part of the name rather than a negating
+ dash). This may be changed to force the last dash in --some- to be
+ negating in the future.
+
+OPTIONS
+ -a
+ --ascii
+ [Systems using EBCDIC] Translate file to ASCII format.
+
+ -A
+ --adjust-sfx
+ Adjust self-extracting executable archive. A self-extracting
+ executable archive is created by prepending the SFX stub to an
+ existing archive. The -A option tells zip to adjust the entry
+ offsets stored in the archive to take into account this "pream-
+ ble" data.
+
+ Note: self-extracting archives for the Amiga are a special case. At
+ present, only the Amiga port of zip is capable of adjusting or updating
+ these without corrupting them. -J can be used to remove the SFX stub if
+ other updates need to be made.
+
+ -AC
+ --archive-clear
+ [WIN32] Once archive is created (and tested if -T is used,
+ which is recommended), clear the archive bits of files pro-
+ cessed. WARNING: Once the bits are cleared they are cleared.
+ You may want to use the -sf show files option to store the list
+ of files processed in case the archive operation must be
+ repeated. Also consider using the -MM must match option. Be
+ sure to check out -DF as a possibly better way to do incremental
+ backups.
+
+ -AS
+ --archive-set
+ [WIN32] Only include files that have the archive bit set.
+ Directories are not stored when -AS is used, though by default
+ the paths of entries, including directories, are stored as usual
+ and can be used by most unzips to recreate directories.
+
+ The archive bit is set by the operating system when a file is
+ modified and, if used with -AC, -AS can provide an incremental
+ backup capability. However, other applications can modify the
+ archive bit and it may not be a reliable indicator of which
+ files have changed since the last archive operation. Alterna-
+ tive ways to create incremental backups are using -t to use file
+ dates, though this won't catch old files copied to directories
+ being archived, and -DF to create a differential archive.
+
+ -B
+ --binary
+ [VM/CMS and MVS] force file to be read binary (default is text).
+
+ -Bn [TANDEM] set Edit/Enscribe formatting options with n defined as
+ bit 0: Don't add delimiter (Edit/Enscribe)
+ bit 1: Use LF rather than CR/LF as delimiter (Edit/Enscribe)
+ bit 2: Space fill record to maximum record length (Enscribe)
+ bit 3: Trim trailing space (Enscribe)
+ bit 8: Force 30K (Expand) large read for unstructured files
+
+ -b path
+ --temp-path path
+ Use the specified path for the temporary zip archive. For exam-
+ ple:
+
+ zip -b /tmp stuff *
+
+ will put the temporary zip archive in the directory /tmp, copy-
+ ing over stuff.zip to the current directory when done. This
+ option is useful when updating an existing archive and the file
+ system containing this old archive does not have enough space to
+ hold both old and new archives at the same time. It may also be
+ useful when streaming in some cases to avoid the need for data
+ descriptors. Note that using this option may require zip take
+ additional time to copy the archive file when done to the desti-
+ nation file system.
+
+ -c
+ --entry-comments
+ Add one-line comments for each file. File operations (adding,
+ updating) are done first, and the user is then prompted for a
+ one-line comment for each file. Enter the comment followed by
+ return, or just return for no comment.
+
+ -C
+ --preserve-case
+ [VMS] Preserve case all on VMS. Negating this option (-C-)
+ downcases.
+
+ -C2
+ --preserve-case-2
+ [VMS] Preserve case ODS2 on VMS. Negating this option (-C2-)
+ downcases.
+
+ -C5
+ --preserve-case-5
+ [VMS] Preserve case ODS5 on VMS. Negating this option (-C5-)
+ downcases.
+
+ -d
+ --delete
+ Remove (delete) entries from a zip archive. For example:
+
+ zip -d foo foo/tom/junk foo/harry/\* \*.o
+
+ will remove the entry foo/tom/junk, all of the files that start
+ with foo/harry/, and all of the files that end with .o (in any
+ path). Note that shell pathname expansion has been inhibited
+ with backslashes, so that zip can see the asterisks, enabling
+ zip to match on the contents of the zip archive instead of the
+ contents of the current directory. (The backslashes are not
+ used on MSDOS-based platforms.) Can also use quotes to escape
+ the asterisks as in
+
+ zip -d foo foo/tom/junk "foo/harry/*" "*.o"
+
+ Not escaping the asterisks on a system where the shell expands
+ wildcards could result in the asterisks being converted to a
+ list of files in the current directory and that list used to
+ delete entries from the archive.
+
+ Under MSDOS, -d is case sensitive when it matches names in the
+ zip archive. This requires that file names be entered in upper
+ case if they were zipped by PKZIP on an MSDOS system. (We con-
+ sidered making this case insensitive on systems where paths were
+ case insensitive, but it is possible the archive came from a
+ system where case does matter and the archive could include both
+ Bar and bar as separate files in the archive.) But see the new
+ option -ic to ignore case in the archive.
+
+ -db
+ --display-bytes
+ Display running byte counts showing the bytes zipped and the
+ bytes to go.
+
+ -dc
+ --display-counts
+ Display running count of entries zipped and entries to go.
+
+ -dd
+ --display-dots
+ Display dots while each entry is zipped (except on ports that
+ have their own progress indicator). See -ds below for setting
+ dot size. The default is a dot every 10 MB of input file pro-
+ cessed. The -v option also displays dots (previously at a much
+ higher rate than this but now -v also defaults to 10 MB) and
+ this rate is also controlled by -ds.
+
+ -df
+ --datafork
+ [MacOS] Include only data-fork of files zipped into the archive.
+ Good for exporting files to foreign operating-systems.
+ Resource-forks will be ignored at all.
+
+ -dg
+ --display-globaldots
+ Display progress dots for the archive instead of for each file.
+ The command
+
+ zip -qdgds 10m
+
+ will turn off most output except dots every 10 MB.
+
+ -ds size
+ --dot-size size
+ Set amount of input file processed for each dot displayed. See
+ -dd to enable displaying dots. Setting this option implies -dd.
+ Size is in the format nm where n is a number and m is a multi-
+ plier. Currently m can be k (KB), m (MB), g (GB), or t (TB), so
+ if n is 100 and m is k, size would be 100k which is 100 KB. The
+ default is 10 MB.
+
+ The -v option also displays dots and now defaults to 10 MB also.
+ This rate is also controlled by this option. A size of 0 turns
+ dots off.
+
+ This option does not control the dots from the "Scanning files"
+ message as zip scans for input files. The dot size for that is
+ fixed at 2 seconds or a fixed number of entries, whichever is
+ longer.
+
+ -du
+ --display-usize
+ Display the uncompressed size of each entry.
+
+ -dv
+ --display-volume
+ Display the volume (disk) number each entry is being read from,
+ if reading an existing archive, and being written to.
+
+ -D
+ --no-dir-entries
+ Do not create entries in the zip archive for directories.
+ Directory entries are created by default so that their
+ attributes can be saved in the zip archive. The environment
+ variable ZIPOPT can be used to change the default options. For
+ example under Unix with sh:
+
+ ZIPOPT="-D"; export ZIPOPT
+
+ (The variable ZIPOPT can be used for any option, including -i
+ and -x using a new option format detailed below, and can include
+ several options.) The option -D is a shorthand for -x "*/" but
+ the latter previously could not be set as default in the ZIPOPT
+ environment variable as the contents of ZIPOPT gets inserted
+ near the beginning of the command line and the file list had to
+ end at the end of the line.
+
+ This version of zip does allow -x and -i options in ZIPOPT if
+ the form
+
+ -x file file ... @
+
+ is used, where the @ (an argument that is just @) terminates the
+ list.
+
+ -DF
+ --difference-archive
+ Create an archive that contains all new and changed files since
+ the original archive was created. For this to work, the input
+ file list and current directory must be the same as during the
+ original zip operation.
+
+ For example, if the existing archive was created using
+
+ zip -r foofull .
+
+ from the bar directory, then the command
+
+ zip -r foofull . -DF --out foonew
+
+ also from the bar directory creates the archive foonew with just
+ the files not in foofull and the files where the size or file
+ time of the files do not match those in foofull.
+
+ Note that the timezone environment variable TZ should be set
+ according to the local timezone in order for this option to work
+ correctly. A change in timezone since the original archive was
+ created could result in no times matching and all files being
+ included.
+
+ A possible approach to backing up a directory might be to create
+ a normal archive of the contents of the directory as a full
+ backup, then use this option to create incremental backups.
+
+ -e
+ --encrypt
+ Encrypt the contents of the zip archive using a password which
+ is entered on the terminal in response to a prompt (this will
+ not be echoed; if standard error is not a tty, zip will exit
+ with an error). The password prompt is repeated to save the
+ user from typing errors.
+
+ -E
+ --longnames
+ [OS/2] Use the .LONGNAME Extended Attribute (if found) as file-
+ name.
+
+ -f
+ --freshen
+ Replace (freshen) an existing entry in the zip archive only if
+ it has been modified more recently than the version already in
+ the zip archive; unlike the update option (-u) this will not add
+ files that are not already in the zip archive. For example:
+
+ zip -f foo
+
+ This command should be run from the same directory from which
+ the original zip command was run, since paths stored in zip
+ archives are always relative.
+
+ Note that the timezone environment variable TZ should be set
+ according to the local timezone in order for the -f, -u and -o
+ options to work correctly.
+
+ The reasons behind this are somewhat subtle but have to do with
+ the differences between the Unix-format file times (always in
+ GMT) and most of the other operating systems (always local time)
+ and the necessity to compare the two. A typical TZ value is
+ ``MET-1MEST'' (Middle European time with automatic adjustment
+ for ``summertime'' or Daylight Savings Time).
+
+ The format is TTThhDDD, where TTT is the time zone such as MET,
+ hh is the difference between GMT and local time such as -1
+ above, and DDD is the time zone when daylight savings time is in
+ effect. Leave off the DDD if there is no daylight savings time.
+ For the US Eastern time zone EST5EDT.
+
+ -F
+ --fix
+ -FF
+ --fixfix
+ Fix the zip archive. The -F option can be used if some portions
+ of the archive are missing, but requires a reasonably intact
+ central directory. The input archive is scanned as usual, but
+ zip will ignore some problems. The resulting archive should be
+ valid, but any inconsistent entries will be left out.
+
+ When doubled as in -FF, the archive is scanned from the begin-
+ ning and zip scans for special signatures to identify the limits
+ between the archive members. The single -F is more reliable if
+ the archive is not too much damaged, so try this option first.
+
+ If the archive is too damaged or the end has been truncated, you
+ must use -FF. This is a change from zip 2.32, where the -F
+ option is able to read a truncated archive. The -F option now
+ more reliably fixes archives with minor damage and the -FF
+ option is needed to fix archives where -F might have been suffi-
+ cient before.
+
+ Neither option will recover archives that have been incorrectly
+ transferred in ascii mode instead of binary. After the repair,
+ the -t option of unzip may show that some files have a bad CRC.
+ Such files cannot be recovered; you can remove them from the
+ archive using the -d option of zip.
+
+ Note that -FF may have trouble fixing archives that include an
+ embedded zip archive that was stored (without compression) in
+ the archive and, depending on the damage, it may find the
+ entries in the embedded archive rather than the archive itself.
+ Try -F first as it does not have this problem.
+
+ The format of the fix commands have changed. For example, to
+ fix the damaged archive foo.zip,
+
+ zip -F foo --out foofix
+
+ tries to read the entries normally, copying good entries to the
+ new archive foofix.zip. If this doesn't work, as when the
+ archive is truncated, or if some entries you know are in the
+ archive are missed, then try
+
+ zip -FF foo --out foofixfix
+
+ and compare the resulting archive to the archive created by -F.
+ The -FF option may create an inconsistent archive. Depending on
+ what is damaged, you can then use the -F option to fix that
+ archive.
+
+ A split archive with missing split files can be fixed using -F
+ if you have the last split of the archive (the .zip file). If
+ this file is missing, you must use -FF to fix the archive, which
+ will prompt you for the splits you have.
+
+ Currently the fix options can't recover entries that have a bad
+ checksum or are otherwise damaged.
+
+ -FI
+ --fifo [Unix] Normally zip skips reading any FIFOs (named pipes)
+ encountered, as zip can hang if the FIFO is not being fed. This
+ option tells zip to read the contents of any FIFO it finds.
+
+ -FS
+ --filesync
+ Synchronize the contents of an archive with the files on the OS.
+ Normally when an archive is updated, new files are added and
+ changed files are updated but files that no longer exist on the
+ OS are not deleted from the archive. This option enables a new
+ mode that checks entries in the archive against the file system.
+ If the file time and file size of the entry matches that of the
+ OS file, the entry is copied from the old archive instead of
+ being read from the file system and compressed. If the OS file
+ has changed, the entry is read and compressed as usual. If the
+ entry in the archive does not match a file on the OS, the entry
+ is deleted. Enabling this option should create archives that
+ are the same as new archives, but since existing entries are
+ copied instead of compressed, updating an existing archive with
+ -FS can be much faster than creating a new archive. Also con-
+ sider using -u for updating an archive.
+
+ For this option to work, the archive should be updated from the
+ same directory it was created in so the relative paths match.
+ If few files are being copied from the old archive, it may be
+ faster to create a new archive instead.
+
+ Note that the timezone environment variable TZ should be set
+ according to the local timezone in order for this option to work
+ correctly. A change in timezone since the original archive was
+ created could result in no times matching and recompression of
+ all files.
+
+ This option deletes files from the archive. If you need to pre-
+ serve the original archive, make a copy of the archive first or
+ use the --out option to output the updated archive to a new
+ file. Even though it may be slower, creating a new archive with
+ a new archive name is safer, avoids mismatches between archive
+ and OS paths, and is preferred.
+
+ -g
+ --grow
+ Grow (append to) the specified zip archive, instead of creating
+ a new one. If this operation fails, zip attempts to restore the
+ archive to its original state. If the restoration fails, the
+ archive might become corrupted. This option is ignored when
+ there's no existing archive or when at least one archive member
+ must be updated or deleted.
+
+ -h
+ -?
+ --help
+ Display the zip help information (this also appears if zip is
+ run with no arguments).
+
+ -h2
+ --more-help
+ Display extended help including more on command line format,
+ pattern matching, and more obscure options.
+
+ -i files
+ --include files
+ Include only the specified files, as in:
+
+ zip -r foo . -i \*.c
+
+ which will include only the files that end in .c in the current
+ directory and its subdirectories. (Note for PKZIP users: the
+ equivalent command is
+
+ pkzip -rP foo *.c
+
+ PKZIP does not allow recursion in directories other than the
+ current one.) The backslash avoids the shell filename substitu-
+ tion, so that the name matching is performed by zip at all
+ directory levels. [This is for Unix and other systems where \
+ escapes the next character. For other systems where the shell
+ does not process * do not use \ and the above is
+
+ zip -r foo . -i *.c
+
+ Examples are for Unix unless otherwise specified.] So to
+ include dir, a directory directly under the current directory,
+ use
+
+ zip -r foo . -i dir/\*
+
+ or
+
+ zip -r foo . -i "dir/*"
+
+ to match paths such as dir/a and dir/b/file.c [on ports without
+ wildcard expansion in the shell such as MSDOS and Windows
+
+ zip -r foo . -i dir/*
+
+ is used.] Note that currently the trailing / is needed for
+ directories (as in
+
+ zip -r foo . -i dir/
+
+ to include directory dir).
+
+ The long option form of the first example is
+
+ zip -r foo . --include \*.c
+
+ and does the same thing as the short option form.
+
+ Though the command syntax used to require -i at the end of the
+ command line, this version actually allows -i (or --include)
+ anywhere. The list of files terminates at the next argument
+ starting with -, the end of the command line, or the list termi-
+ nator @ (an argument that is just @). So the above can be given
+ as
+
+ zip -i \*.c @ -r foo .
+
+ for example. There must be a space between the option and the
+ first file of a list. For just one file you can use the single
+ value form
+
+ zip -i\*.c -r foo .
+
+ (no space between option and value) or
+
+ zip --include=\*.c -r foo .
+
+ as additional examples. The single value forms are not recom-
+ mended because they can be confusing and, in particular, the
+ -ifile format can cause problems if the first letter of file
+ combines with i to form a two-letter option starting with i.
+ Use -sc to see how your command line will be parsed.
+
+ Also possible:
+
+ zip -r foo . -i@include.lst
+
+ which will only include the files in the current directory and
+ its subdirectories that match the patterns in the file
+ include.lst.
+
+ Files to -i and -x are patterns matching internal archive paths.
+ See -R for more on patterns.
+
+ -I
+ --no-image
+ [Acorn RISC OS] Don't scan through Image files. When used, zip
+ will not consider Image files (eg. DOS partitions or Spark
+ archives when SparkFS is loaded) as directories but will store
+ them as single files.
+
+ For example, if you have SparkFS loaded, zipping a Spark archive
+ will result in a zipfile containing a directory (and its con-
+ tent) while using the 'I' option will result in a zipfile con-
+ taining a Spark archive. Obviously this second case will also be
+ obtained (without the 'I' option) if SparkFS isn't loaded.
+
+ -ic
+ --ignore-case
+ [VMS, WIN32] Ignore case when matching archive entries. This
+ option is only available on systems where the case of files is
+ ignored. On systems with case-insensitive file systems, case is
+ normally ignored when matching files on the file system but is
+ not ignored for -f (freshen), -d (delete), -U (copy), and simi-
+ lar modes when matching against archive entries (currently -f
+ ignores case on VMS) because archive entries can be from systems
+ where case does matter and names that are the same except for
+ case can exist in an archive. The -ic option makes all matching
+ case insensitive. This can result in multiple archive entries
+ matching a command line pattern.
+
+ -j
+ --junk-paths
+ Store just the name of a saved file (junk the path), and do not
+ store directory names. By default, zip will store the full path
+ (relative to the current directory).
+
+ -jj
+ --absolute-path
+ [MacOS] record Fullpath (+ Volname). The complete path including
+ volume will be stored. By default the relative path will be
+ stored.
+
+ -J
+ --junk-sfx
+ Strip any prepended data (e.g. a SFX stub) from the archive.
+
+ -k
+ --DOS-names
+ Attempt to convert the names and paths to conform to MSDOS,
+ store only the MSDOS attribute (just the user write attribute
+ from Unix), and mark the entry as made under MSDOS (even though
+ it was not); for compatibility with PKUNZIP under MSDOS which
+ cannot handle certain names such as those with two dots.
+
+ -l
+ --to-crlf
+ Translate the Unix end-of-line character LF into the MSDOS con-
+ vention CR LF. This option should not be used on binary files.
+ This option can be used on Unix if the zip file is intended for
+ PKUNZIP under MSDOS. If the input files already contain CR LF,
+ this option adds an extra CR. This is to ensure that unzip -a on
+ Unix will get back an exact copy of the original file, to undo
+ the effect of zip -l. See -ll for how binary files are handled.
+
+ -la
+ --log-append
+ Append to existing logfile. Default is to overwrite.
+
+ -lf logfilepath
+ --logfile-path logfilepath
+ Open a logfile at the given path. By default any existing file
+ at that location is overwritten, but the -la option will result
+ in an existing file being opened and the new log information
+ appended to any existing information. Only warnings and errors
+ are written to the log unless the -li option is also given, then
+ all information messages are also written to the log.
+
+ -li
+ --log-info
+ Include information messages, such as file names being zipped,
+ in the log. The default is to only include the command line,
+ any warnings and errors, and the final status.
+
+ -ll
+ --from-crlf
+ Translate the MSDOS end-of-line CR LF into Unix LF. This option
+ should not be used on binary files. This option can be used on
+ MSDOS if the zip file is intended for unzip under Unix. If the
+ file is converted and the file is later determined to be binary
+ a warning is issued and the file is probably corrupted. In this
+ release if -ll detects binary in the first buffer read from a
+ file, zip now issues a warning and skips line end conversion on
+ the file. This check seems to catch all binary files tested,
+ but the original check remains and if a converted file is later
+ determined to be binary that warning is still issued. A new
+ algorithm is now being used for binary detection that should
+ allow line end conversion of text files in UTF-8 and similar
+ encodings.
+
+ -L
+ --license
+ Display the zip license.
+
+ -m
+ --move
+ Move the specified files into the zip archive; actually, this
+ deletes the target directories/files after making the specified
+ zip archive. If a directory becomes empty after removal of the
+ files, the directory is also removed. No deletions are done
+ until zip has created the archive without error. This is useful
+ for conserving disk space, but is potentially dangerous so it is
+ recommended to use it in combination with -T to test the archive
+ before removing all input files.
+
+ -MM
+ --must-match
+ All input patterns must match at least one file and all input
+ files found must be readable. Normally when an input pattern
+ does not match a file the "name not matched" warning is issued
+ and when an input file has been found but later is missing or
+ not readable a missing or not readable warning is issued. In
+ either case zip continues creating the archive, with missing or
+ unreadable new files being skipped and files already in the
+ archive remaining unchanged. After the archive is created, if
+ any files were not readable zip returns the OPEN error code (18
+ on most systems) instead of the normal success return (0 on most
+ systems). With -MM set, zip exits as soon as an input pattern
+ is not matched (whenever the "name not matched" warning would be
+ issued) or when an input file is not readable. In either case
+ zip exits with an OPEN error and no archive is created.
+
+ This option is useful when a known list of files is to be zipped
+ so any missing or unreadable files will result in an error. It
+ is less useful when used with wildcards, but zip will still exit
+ with an error if any input pattern doesn't match at least one
+ file and if any matched files are unreadable. If you want to
+ create the archive anyway and only need to know if files were
+ skipped, don't use -MM and just check the return code. Also -lf
+ could be useful.
+
+ -n suffixes
+ --suffixes suffixes
+ Do not attempt to compress files named with the given suffixes.
+ Such files are simply stored (0% compression) in the output zip
+ file, so that zip doesn't waste its time trying to compress
+ them. The suffixes are separated by either colons or semi-
+ colons. For example:
+
+ zip -rn .Z:.zip:.tiff:.gif:.snd foo foo
+
+ will copy everything from foo into foo.zip, but will store any
+ files that end in .Z, .zip, .tiff, .gif, or .snd without trying
+ to compress them (image and sound files often have their own
+ specialized compression methods). By default, zip does not com-
+ press files with extensions in the list
+ .Z:.zip:.zoo:.arc:.lzh:.arj. Such files are stored directly in
+ the output archive. The environment variable ZIPOPT can be used
+ to change the default options. For example under Unix with csh:
+
+ setenv ZIPOPT "-n .gif:.zip"
+
+ To attempt compression on all files, use:
+
+ zip -n : foo
+
+ The maximum compression option -9 also attempts compression on
+ all files regardless of extension.
+
+ On Acorn RISC OS systems the suffixes are actually filetypes (3
+ hex digit format). By default, zip does not compress files with
+ filetypes in the list DDC:D96:68E (i.e. Archives, CFS files and
+ PackDir files).
+
+ -nw
+ --no-wild
+ Do not perform internal wildcard processing (shell processing of
+ wildcards is still done by the shell unless the arguments are
+ escaped). Useful if a list of paths is being read and no wild-
+ card substitution is desired.
+
+ -N
+ --notes
+ [Amiga, MacOS] Save Amiga or MacOS filenotes as zipfile com-
+ ments. They can be restored by using the -N option of unzip. If
+ -c is used also, you are prompted for comments only for those
+ files that do not have filenotes.
+
+ -o
+ --latest-time
+ Set the "last modified" time of the zip archive to the latest
+ (oldest) "last modified" time found among the entries in the zip
+ archive. This can be used without any other operations, if
+ desired. For example:
+
+ zip -o foo
+
+ will change the last modified time of foo.zip to the latest time
+ of the entries in foo.zip.
+
+ -O output-file
+ --output-file output-file
+ Process the archive changes as usual, but instead of updating
+ the existing archive, output the new archive to output-file.
+ Useful for updating an archive without changing the existing
+ archive and the input archive must be a different file than the
+ output archive.
+
+ This option can be used to create updated split archives. It
+ can also be used with -U to copy entries from an existing
+ archive to a new archive. See the EXAMPLES section below.
+
+ Another use is converting zip files from one split size to
+ another. For instance, to convert an archive with 700 MB CD
+ splits to one with 2 GB DVD splits, can use:
+
+ zip -s 2g cd-split.zip --out dvd-split.zip
+
+ which uses copy mode. See -U below. Also:
+
+ zip -s 0 split.zip --out unsplit.zip
+
+ will convert a split archive to a single-file archive.
+
+ Copy mode will convert stream entries (using data descriptors
+ and which should be compatible with most unzips) to normal
+ entries (which should be compatible with all unzips), except if
+ standard encryption was used. For archives with encrypted
+ entries, zipcloak will decrypt the entries and convert them to
+ normal entries.
+
+ -p
+ --paths
+ Include relative file paths as part of the names of files stored
+ in the archive. This is the default. The -j option junks the
+ paths and just stores the names of the files.
+
+ -P password
+ --password password
+ Use password to encrypt zipfile entries (if any). THIS IS INSE-
+ CURE! Many multi-user operating systems provide ways for any
+ user to see the current command line of any other user; even on
+ stand-alone systems there is always the threat of over-the-
+ shoulder peeking. Storing the plaintext password as part of a
+ command line in an automated script is even worse. Whenever
+ possible, use the non-echoing, interactive prompt to enter pass-
+ words. (And where security is truly important, use strong
+ encryption such as Pretty Good Privacy instead of the relatively
+ weak standard encryption provided by zipfile utilities.)
+
+ -q
+ --quiet
+ Quiet mode; eliminate informational messages and comment
+ prompts. (Useful, for example, in shell scripts and background
+ tasks).
+
+ -Qn
+ --Q-flag n
+ [QDOS] store information about the file in the file header with
+ n defined as
+ bit 0: Don't add headers for any file
+ bit 1: Add headers for all files
+ bit 2: Don't wait for interactive key press on exit
+
+ -r
+ --recurse-paths
+ Travel the directory structure recursively; for example:
+
+ zip -r foo.zip foo
+
+ or more concisely
+
+ zip -r foo foo
+
+ In this case, all the files and directories in foo are saved in
+ a zip archive named foo.zip, including files with names starting
+ with ".", since the recursion does not use the shell's file-name
+ substitution mechanism. If you wish to include only a specific
+ subset of the files in directory foo and its subdirectories, use
+ the -i option to specify the pattern of files to be included.
+ You should not use -r with the name ".*", since that matches
+ ".." which will attempt to zip up the parent directory (proba-
+ bly not what was intended).
+
+ Multiple source directories are allowed as in
+
+ zip -r foo foo1 foo2
+
+ which first zips up foo1 and then foo2, going down each direc-
+ tory.
+
+ Note that while wildcards to -r are typically resolved while
+ recursing down directories in the file system, any -R, -x, and
+ -i wildcards are applied to internal archive pathnames once the
+ directories are scanned. To have wildcards apply to files in
+ subdirectories when recursing on Unix and similar systems where
+ the shell does wildcard substitution, either escape all wild-
+ cards or put all arguments with wildcards in quotes. This lets
+ zip see the wildcards and match files in subdirectories using
+ them as it recurses.
+
+ -R
+ --recurse-patterns
+ Travel the directory structure recursively starting at the cur-
+ rent directory; for example:
+
+ zip -R foo "*.c"
+
+ In this case, all the files matching *.c in the tree starting at
+ the current directory are stored into a zip archive named
+ foo.zip. Note that *.c will match file.c, a/file.c and a/b/.c.
+ More than one pattern can be listed as separate arguments. Note
+ for PKZIP users: the equivalent command is
+
+ pkzip -rP foo *.c
+
+ Patterns are relative file paths as they appear in the archive,
+ or will after zipping, and can have optional wildcards in them.
+ For example, given the current directory is foo and under it are
+ directories foo1 and foo2 and in foo1 is the file bar.c,
+
+ zip -R foo/*
+
+ will zip up foo, foo/foo1, foo/foo1/bar.c, and foo/foo2.
+
+ zip -R */bar.c
+
+ will zip up foo/foo1/bar.c. See the note for -r on escaping
+ wildcards.
+
+ -RE
+ --regex
+ [WIN32] Before zip 3.0, regular expression list matching was
+ enabled by default on Windows platforms. Because of confusion
+ resulting from the need to escape "[" and "]" in names, it is
+ now off by default for Windows so "[" and "]" are just normal
+ characters in names. This option enables [] matching again.
+
+ -s splitsize
+ --split-size splitsize
+ Enable creating a split archive and set the split size. A split
+ archive is an archive that could be split over many files. As
+ the archive is created, if the size of the archive reaches the
+ specified split size, that split is closed and the next split
+ opened. In general all splits but the last will be the split
+ size and the last will be whatever is left. If the entire
+ archive is smaller than the split size a single-file archive is
+ created.
+
+ Split archives are stored in numbered files. For example, if
+ the output archive is named archive and three splits are
+ required, the resulting archive will be in the three files
+ archive.z01, archive.z02, and archive.zip. Do not change the
+ numbering of these files or the archive will not be readable as
+ these are used to determine the order the splits are read.
+
+ Split size is a number optionally followed by a multiplier.
+ Currently the number must be an integer. The multiplier can
+ currently be one of k (kilobytes), m (megabytes), g (gigabytes),
+ or t (terabytes). As 64k is the minimum split size, numbers
+ without multipliers default to megabytes. For example, to cre-
+ ate a split archive called foo with the contents of the bar
+ directory with splits of 670 MB that might be useful for burning
+ on CDs, the command:
+
+ zip -s 670m -r foo bar
+
+ could be used.
+
+ Currently the old splits of a split archive are not excluded
+ from a new archive, but they can be specifically excluded. If
+ possible, keep the input and output archives out of the path
+ being zipped when creating split archives.
+
+ Using -s without -sp as above creates all the splits where foo
+ is being written, in this case the current directory. This
+ split mode updates the splits as the archive is being created,
+ requiring all splits to remain writable, but creates split
+ archives that are readable by any unzip that supports split
+ archives. See -sp below for enabling split pause mode which
+ allows splits to be written directly to removable media.
+
+ The option -sv can be used to enable verbose splitting and pro-
+ vide details of how the splitting is being done. The -sb option
+ can be used to ring the bell when zip pauses for the next split
+ destination.
+
+ Split archives cannot be updated, but see the -O (--out) option
+ for how a split archive can be updated as it is copied to a new
+ archive. A split archive can also be converted into a single-
+ file archive using a split size of 0 or negating the -s option:
+
+ zip -s 0 split.zip --out single.zip
+
+ Also see -U (--copy) for more on using copy mode.
+
+ -sb
+ --split-bell
+ If splitting and using split pause mode, ring the bell when zip
+ pauses for each split destination.
+
+ -sc
+ --show-command
+ Show the command line starting zip as processed and exit. The
+ new command parser permutes the arguments, putting all options
+ and any values associated with them before any non-option argu-
+ ments. This allows an option to appear anywhere in the command
+ line as long as any values that go with the option go with it.
+ This option displays the command line as zip sees it, including
+ any arguments from the environment such as from the ZIPOPT vari-
+ able. Where allowed, options later in the command line can
+ override options earlier in the command line.
+
+ -sf
+ --show-files
+ Show the files that would be operated on, then exit. For
+ instance, if creating a new archive, this will list the files
+ that would be added. If the option is negated, -sf-, output
+ only to an open log file. Screen display is not recommended for
+ large lists.
+
+ -so
+ --show-options
+ Show all available options supported by zip as compiled on the
+ current system. As this command reads the option table, it
+ should include all options. Each line includes the short option
+ (if defined), the long option (if defined), the format of any
+ value that goes with the option, if the option can be negated,
+ and a small description. The value format can be no value,
+ required value, optional value, single character value, number
+ value, or a list of values. The output of this option is not
+ intended to show how to use any option but only show what
+ options are available.
+
+ -sp
+ --split-pause
+ If splitting is enabled with -s, enable split pause mode. This
+ creates split archives as -s does, but stream writing is used so
+ each split can be closed as soon as it is written and zip will
+ pause between each split to allow changing split destination or
+ media.
+
+ Though this split mode allows writing splits directly to remov-
+ able media, it uses stream archive format that may not be read-
+ able by some unzips. Before relying on splits created with -sp,
+ test a split archive with the unzip you will be using.
+
+ To convert a stream split archive (created with -sp) to a stan-
+ dard archive see the --out option.
+
+ -su
+ --show-unicode
+ As -sf, but also show Unicode version of the path if exists.
+
+ -sU
+ --show-just-unicode
+ As -sf, but only show Unicode version of the path if exists,
+ otherwise show the standard version of the path.
+
+ -sv
+ --split-verbose
+ Enable various verbose messages while splitting, showing how the
+ splitting is being done.
+
+ -S
+ --system-hidden
+ [MSDOS, OS/2, WIN32 and ATARI] Include system and hidden files.
+ [MacOS] Includes finder invisible files, which are ignored oth-
+ erwise.
+
+ -t mmddyyyy
+ --from-date mmddyyyy
+ Do not operate on files modified prior to the specified date,
+ where mm is the month (00-12), dd is the day of the month
+ (01-31), and yyyy is the year. The ISO 8601 date format
+ yyyy-mm-dd is also accepted. For example:
+
+ zip -rt 12071991 infamy foo
+
+ zip -rt 1991-12-07 infamy foo
+
+ will add all the files in foo and its subdirectories that were
+ last modified on or after 7 December 1991, to the zip archive
+ infamy.zip.
+
+ -tt mmddyyyy
+ --before-date mmddyyyy
+ Do not operate on files modified after or at the specified date,
+ where mm is the month (00-12), dd is the day of the month
+ (01-31), and yyyy is the year. The ISO 8601 date format
+ yyyy-mm-dd is also accepted. For example:
+
+ zip -rtt 11301995 infamy foo
+
+ zip -rtt 1995-11-30 infamy foo
+
+ will add all the files in foo and its subdirectories that were
+ last modified before 30 November 1995, to the zip archive
+ infamy.zip.
+
+ -T
+ --test
+ Test the integrity of the new zip file. If the check fails, the
+ old zip file is unchanged and (with the -m option) no input
+ files are removed.
+
+ -TT cmd
+ --unzip-command cmd
+ Use command cmd instead of 'unzip -tqq' to test an archive when
+ the -T option is used. On Unix, to use a copy of unzip in the
+ current directory instead of the standard system unzip, could
+ use:
+
+ zip archive file1 file2 -T -TT "./unzip -tqq"
+
+ In cmd, {} is replaced by the name of the temporary archive,
+ otherwise the name of the archive is appended to the end of the
+ command. The return code is checked for success (0 on Unix).
+
+ -u
+ --update
+ Replace (update) an existing entry in the zip archive only if it
+ has been modified more recently than the version already in the
+ zip archive. For example:
+
+ zip -u stuff *
+
+ will add any new files in the current directory, and update any
+ files which have been modified since the zip archive stuff.zip
+ was last created/modified (note that zip will not try to pack
+ stuff.zip into itself when you do this).
+
+ Note that the -u option with no input file arguments acts like
+ the -f (freshen) option.
+
+ -U
+ --copy-entries
+ Copy entries from one archive to another. Requires the --out
+ option to specify a different output file than the input
+ archive. Copy mode is the reverse of -d delete. When delete is
+ being used with --out, the selected entries are deleted from the
+ archive and all other entries are copied to the new archive,
+ while copy mode selects the files to include in the new archive.
+ Unlike -u update, input patterns on the command line are matched
+ against archive entries only and not the file system files. For
+ instance,
+
+ zip inarchive "*.c" --copy --out outarchive
+
+ copies entries with names ending in .c from inarchive to out-
+ archive. The wildcard must be escaped on some systems to pre-
+ vent the shell from substituting names of files from the file
+ system which may have no relevance to the entries in the
+ archive.
+
+ If no input files appear on the command line and --out is used,
+ copy mode is assumed:
+
+ zip inarchive --out outarchive
+
+ This is useful for changing split size for instance. Encrypting
+ and decrypting entries is not yet supported using copy mode.
+ Use zipcloak for that.
+
+ -UN v
+ --unicode v
+ Determine what zip should do with Unicode file names. zip 3.0,
+ in addition to the standard file path, now includes the UTF-8
+ translation of the path if the entry path is not entirely 7-bit
+ ASCII. When an entry is missing the Unicode path, zip reverts
+ back to the standard file path. The problem with using the
+ standard path is this path is in the local character set of the
+ zip that created the entry, which may contain characters that
+ are not valid in the character set being used by the unzip.
+ When zip is reading an archive, if an entry also has a Unicode
+ path, zip now defaults to using the Unicode path to recreate the
+ standard path using the current local character set.
+
+ This option can be used to determine what zip should do with
+ this path if there is a mismatch between the stored standard
+ path and the stored UTF-8 path (which can happen if the standard
+ path was updated). In all cases, if there is a mismatch it is
+ assumed that the standard path is more current and zip uses
+ that. Values for v are
+
+ q - quit if paths do not match
+
+ w - warn, continue with standard path
+
+ i - ignore, continue with standard path
+
+ n - no Unicode, do not use Unicode paths
+
+ The default is to warn and continue.
+
+ Characters that are not valid in the current character set are
+ escaped as #Uxxxx and #Lxxxxxx, where x is an ASCII character
+ for a hex digit. The first is used if a 16-bit character number
+ is sufficient to represent the Unicode character and the second
+ if the character needs more than 16 bits to represent it's Uni-
+ code character code. Setting -UN to
+
+ e - escape
+
+ as in
+
+ zip archive -sU -UN=e
+
+ forces zip to escape all characters that are not printable 7-bit
+ ASCII.
+
+ Normally zip stores UTF-8 directly in the standard path field on
+ systems where UTF-8 is the current character set and stores the
+ UTF-8 in the new extra fields otherwise. The option
+
+ u - UTF-8
+
+ as in
+
+ zip archive dir -r -UN=UTF8
+
+ forces zip to store UTF-8 as native in the archive. Note that
+ storing UTF-8 directly is the default on Unix systems that sup-
+ port it. This option could be useful on Windows systems where
+ the escaped path is too large to be a valid path and the UTF-8
+ version of the path is smaller, but native UTF-8 is not backward
+ compatible on Windows systems.
+
+ -v
+ --verbose
+ Verbose mode or print diagnostic version info.
+
+ Normally, when applied to real operations, this option enables
+ the display of a progress indicator during compression (see -dd
+ for more on dots) and requests verbose diagnostic info about
+ zipfile structure oddities.
+
+ However, when -v is the only command line argument a diagnostic
+ screen is printed instead. This should now work even if stdout
+ is redirected to a file, allowing easy saving of the information
+ for sending with bug reports to Info-ZIP. The version screen
+ provides the help screen header with program name, version, and
+ release date, some pointers to the Info-ZIP home and distribu-
+ tion sites, and shows information about the target environment
+ (compiler type and version, OS version, compilation date and the
+ enabled optional features used to create the zip executable).
+
+ -V
+ --VMS-portable
+ [VMS] Save VMS file attributes. (Files are truncated at EOF.)
+ When a -V archive is unpacked on a non-VMS system, some file
+ types (notably Stream_LF text files and pure binary files
+ like fixed-512) should be extracted intact. Indexed files and
+ file types with embedded record sizes (notably variable-length
+ record types) will probably be seen as corrupt elsewhere.
+
+ -VV
+ --VMS-specific
+ [VMS] Save VMS file attributes, and all allocated blocks in a
+ file, including any data beyond EOF. Useful for moving ill-
+ formed files among VMS systems. When a -VV archive is
+ unpacked on a non-VMS system, almost all files will appear cor-
+ rupt.
+
+ -w
+ --VMS-versions
+ [VMS] Append the version number of the files to the name,
+ including multiple versions of files. Default is to use only
+ the most recent version of a specified file.
+
+ -ww
+ --VMS-dot-versions
+ [VMS] Append the version number of the files to the name,
+ including multiple versions of files, using the .nnn format.
+ Default is to use only the most recent version of a specified
+ file.
+
+ -ws
+ --wild-stop-dirs
+ Wildcards match only at a directory level. Normally zip handles
+ paths as strings and given the paths
+
+ /foo/bar/dir/file1.c
+
+ /foo/bar/file2.c
+
+ an input pattern such as
+
+ /foo/bar/*
+
+ normally would match both paths, the * matching dir/file1.c and
+ file2.c. Note that in the first case a directory boundary (/)
+ was crossed in the match. With -ws no directory bounds will be
+ included in the match, making wildcards local to a specific
+ directory level. So, with -ws enabled, only the second path
+ would be matched.
+
+ When using -ws, use ** to match across directory boundaries as *
+ does normally.
+
+ -x files
+ --exclude files
+ Explicitly exclude the specified files, as in:
+
+ zip -r foo foo -x \*.o
+
+ which will include the contents of foo in foo.zip while exclud-
+ ing all the files that end in .o. The backslash avoids the
+ shell filename substitution, so that the name matching is per-
+ formed by zip at all directory levels.
+
+ Also possible:
+
+ zip -r foo foo -x@exclude.lst
+
+ which will include the contents of foo in foo.zip while exclud-
+ ing all the files that match the patterns in the file
+ exclude.lst.
+
+ The long option forms of the above are
+
+ zip -r foo foo --exclude \*.o
+
+ and
+
+ zip -r foo foo --exclude @exclude.lst
+
+ Multiple patterns can be specified, as in:
+
+ zip -r foo foo -x \*.o \*.c
+
+ If there is no space between -x and the pattern, just one value
+ is assumed (no list):
+
+ zip -r foo foo -x\*.o
+
+ See -i for more on include and exclude.
+
+ -X
+ --no-extra
+ Do not save extra file attributes (Extended Attributes on OS/2,
+ uid/gid and file times on Unix). The zip format uses extra
+ fields to include additional information for each entry. Some
+ extra fields are specific to particular systems while others are
+ applicable to all systems. Normally when zip reads entries from
+ an existing archive, it reads the extra fields it knows, strips
+ the rest, and adds the extra fields applicable to that system.
+ With -X, zip strips all old fields and only includes the Unicode
+ and Zip64 extra fields (currently these two extra fields cannot
+ be disabled).
+
+ Negating this option, -X-, includes all the default extra
+ fields, but also copies over any unrecognized extra fields.
+
+ -y
+ --symlinks
+ For UNIX and VMS (V8.3 and later), store symbolic links as such
+ in the zip archive, instead of compressing and storing the file
+ referred to by the link. This can avoid multiple copies of
+ files being included in the archive as zip recurses the direc-
+ tory trees and accesses files directly and by links.
+
+ -z
+ --archive-comment
+ Prompt for a multi-line comment for the entire zip archive. The
+ comment is ended by a line containing just a period, or an end
+ of file condition (^D on Unix, ^Z on MSDOS, OS/2, and VMS). The
+ comment can be taken from a file:
+
+ zip -z foo < foowhat
+
+ -Z cm
+ --compression-method cm
+ Set the default compression method. Currently the main methods
+ supported by zip are store and deflate. Compression method can
+ be set to:
+
+ store - Setting the compression method to store forces zip to
+ store entries with no compression. This is generally faster
+ than compressing entries, but results in no space savings. This
+ is the same as using -0 (compression level zero).
+
+ deflate - This is the default method for zip. If zip determines
+ that storing is better than deflation, the entry will be stored
+ instead.
+
+ bzip2 - If bzip2 support is compiled in, this compression method
+ also becomes available. Only some modern unzips currently sup-
+ port the bzip2 compression method, so test the unzip you will be
+ using before relying on archives using this method (compression
+ method 12).
+
+ For example, to add bar.c to archive foo using bzip2 compres-
+ sion:
+
+ zip -Z bzip2 foo bar.c
+
+ The compression method can be abbreviated:
+
+ zip -Zb foo bar.c
+
+ -#
+ (-0, -1, -2, -3, -4, -5, -6, -7, -8, -9)
+ Regulate the speed of compression using the specified digit #,
+ where -0 indicates no compression (store all files), -1 indi-
+ cates the fastest compression speed (less compression) and -9
+ indicates the slowest compression speed (optimal compression,
+ ignores the suffix list). The default compression level is -6.
+
+ Though still being worked, the intention is this setting will
+ control compression speed for all compression methods. Cur-
+ rently only deflation is controlled.
+
+ -!
+ --use-privileges
+ [WIN32] Use priviliges (if granted) to obtain all aspects of
+ WinNT security.
+
+ -@
+ --names-stdin
+ Take the list of input files from standard input. Only one file-
+ name per line.
+
+ -$
+ --volume-label
+ [MSDOS, OS/2, WIN32] Include the volume label for the drive
+ holding the first file to be compressed. If you want to include
+ only the volume label or to force a specific drive, use the
+ drive name as first file name, as in:
+
+ zip -$ foo a: c:bar
+
+EXAMPLES
+ The simplest example:
+
+ zip stuff *
+
+ creates the archive stuff.zip (assuming it does not exist) and puts all
+ the files in the current directory in it, in compressed form (the .zip
+ suffix is added automatically, unless the archive name contains a dot
+ already; this allows the explicit specification of other suffixes).
+
+ Because of the way the shell on Unix does filename substitution, files
+ starting with "." are not included; to include these as well:
+
+ zip stuff .* *
+
+ Even this will not include any subdirectories from the current direc-
+ tory.
+
+ To zip up an entire directory, the command:
+
+ zip -r foo foo
+
+ creates the archive foo.zip, containing all the files and directories
+ in the directory foo that is contained within the current directory.
+
+ You may want to make a zip archive that contains the files in foo,
+ without recording the directory name, foo. You can use the -j option
+ to leave off the paths, as in:
+
+ zip -j foo foo/*
+
+ If you are short on disk space, you might not have enough room to hold
+ both the original directory and the corresponding compressed zip
+ archive. In this case, you can create the archive in steps using the
+ -m option. If foo contains the subdirectories tom, dick, and harry,
+ you can:
+
+ zip -rm foo foo/tom
+ zip -rm foo foo/dick
+ zip -rm foo foo/harry
+
+ where the first command creates foo.zip, and the next two add to it.
+ At the completion of each zip command, the last created archive is
+ deleted, making room for the next zip command to function.
+
+ Use -s to set the split size and create a split archive. The size is
+ given as a number followed optionally by one of k (kB), m (MB), g (GB),
+ or t (TB). The command
+
+ zip -s 2g -r split.zip foo
+
+ creates a split archive of the directory foo with splits no bigger than
+ 2 GB each. If foo contained 5 GB of contents and the contents were
+ stored in the split archive without compression (to make this example
+ simple), this would create three splits, split.z01 at 2 GB, split.z02
+ at 2 GB, and split.zip at a little over 1 GB.
+
+ The -sp option can be used to pause zip between splits to allow chang-
+ ing removable media, for example, but read the descriptions and warn-
+ ings for both -s and -sp below.
+
+ Though zip does not update split archives, zip provides the new option
+ -O (--output-file) to allow split archives to be updated and saved in a
+ new archive. For example,
+
+ zip inarchive.zip foo.c bar.c --out outarchive.zip
+
+ reads archive inarchive.zip, even if split, adds the files foo.c and
+ bar.c, and writes the resulting archive to outarchive.zip. If inar-
+ chive.zip is split then outarchive.zip defaults to the same split size.
+ Be aware that outarchive.zip and any split files that are created with
+ it are always overwritten without warning. This may be changed in the
+ future.
+
+PATTERN MATCHING
+ This section applies only to Unix. Watch this space for details on
+ MSDOS and VMS operation. However, the special wildcard characters *
+ and [] below apply to at least MSDOS also.
+
+ The Unix shells (sh, csh, bash, and others) normally do filename sub-
+ stitution (also called "globbing") on command arguments. Generally the
+ special characters are:
+
+ ? match any single character
+
+ * match any number of characters (including none)
+
+ [] match any character in the range indicated within the brackets
+ (example: [a-f], [0-9]). This form of wildcard matching allows
+ a user to specify a list of characters between square brackets
+ and if any of the characters match the expression matches. For
+ example:
+
+ zip archive "*.[hc]"
+
+ would archive all files in the current directory that end in .h
+ or .c.
+
+ Ranges of characters are supported:
+
+ zip archive "[a-f]*"
+
+ would add to the archive all files starting with "a" through
+ "f".
+
+ Negation is also supported, where any character in that position
+ not in the list matches. Negation is supported by adding ! or ^
+ to the beginning of the list:
+
+ zip archive "*.[!o]"
+
+ matches files that don't end in ".o".
+
+ On WIN32, [] matching needs to be turned on with the -RE option
+ to avoid the confusion that names with [ or ] have caused.
+
+ When these characters are encountered (without being escaped with a
+ backslash or quotes), the shell will look for files relative to the
+ current path that match the pattern, and replace the argument with a
+ list of the names that matched.
+
+ The zip program can do the same matching on names that are in the zip
+ archive being modified or, in the case of the -x (exclude) or -i
+ (include) options, on the list of files to be operated on, by using
+ backslashes or quotes to tell the shell not to do the name expansion.
+ In general, when zip encounters a name in the list of files to do, it
+ first looks for the name in the file system. If it finds it, it then
+ adds it to the list of files to do. If it does not find it, it looks
+ for the name in the zip archive being modified (if it exists), using
+ the pattern matching characters described above, if present. For each
+ match, it will add that name to the list of files to be processed,
+ unless this name matches one given with the -x option, or does not
+ match any name given with the -i option.
+
+ The pattern matching includes the path, and so patterns like \*.o match
+ names that end in ".o", no matter what the path prefix is. Note that
+ the backslash must precede every special character (i.e. ?*[]), or the
+ entire argument must be enclosed in double quotes ("").
+
+ In general, use backslashes or double quotes for paths that have wild-
+ cards to make zip do the pattern matching for file paths, and always
+ for paths and strings that have spaces or wildcards for -i, -x, -R, -d,
+ and -U and anywhere zip needs to process the wildcards.
+
+ENVIRONMENT
+ The following environment variables are read and used by zip as
+ described.
+
+ ZIPOPT
+ contains default options that will be used when running zip.
+ The contents of this environment variable will get added to the
+ command line just after the zip command.
+
+ ZIP
+ [Not on RISC OS and VMS] see ZIPOPT
+
+ Zip$Options
+ [RISC OS] see ZIPOPT
+
+ Zip$Exts
+ [RISC OS] contains extensions separated by a : that will cause
+ native filenames with one of the specified extensions to be
+ added to the zip file with basename and extension swapped.
+
+ ZIP_OPTS
+ [VMS] see ZIPOPT
+
+SEE ALSO
+ compress(1), shar(1L), tar(1), unzip(1L), gzip(1L)
+
+DIAGNOSTICS
+ The exit status (or error level) approximates the exit codes defined by
+ PKWARE and takes on the following values, except under VMS:
+
+ 0 normal; no errors or warnings detected.
+
+ 2 unexpected end of zip file.
+
+ 3 a generic error in the zipfile format was detected. Pro-
+ cessing may have completed successfully anyway; some bro-
+ ken zipfiles created by other archivers have simple work-
+ arounds.
+
+ 4 zip was unable to allocate memory for one or more buffers
+ during program initialization.
+
+ 5 a severe error in the zipfile format was detected. Pro-
+ cessing probably failed immediately.
+
+ 6 entry too large to be processed (such as input files
+ larger than 2 GB when not using Zip64 or trying to read
+ an existing archive that is too large) or entry too large
+ to be split with zipsplit
+
+ 7 invalid comment format
+
+ 8 zip -T failed or out of memory
+
+ 9 the user aborted zip prematurely with control-C (or simi-
+ lar)
+
+ 10 zip encountered an error while using a temp file
+
+ 11 read or seek error
+
+ 12 zip has nothing to do
+
+ 13 missing or empty zip file
+
+ 14 error writing to a file
+
+ 15 zip was unable to create a file to write to
+
+ 16 bad command line parameters
+
+ 18 zip could not open a specified file to read
+
+ 19 zip was compiled with options not supported on this sys-
+ tem
+
+ VMS interprets standard Unix (or PC) return values as other, scarier-
+ looking things, so zip instead maps them into VMS-style status codes.
+ In general, zip sets VMS Facility = 1955 (0x07A3), Code = 2* Unix_sta-
+ tus, and an appropriate Severity (as specified in ziperr.h). More
+ details are included in the VMS-specific documentation. See
+ [.vms]NOTES.TXT and [.vms]vms_msg_gen.c.
+
+BUGS
+ zip 3.0 is not compatible with PKUNZIP 1.10. Use zip 1.1 to produce zip
+ files which can be extracted by PKUNZIP 1.10.
+
+ zip files produced by zip 3.0 must not be updated by zip 1.1 or PKZIP
+ 1.10, if they contain encrypted members or if they have been produced
+ in a pipe or on a non-seekable device. The old versions of zip or PKZIP
+ would create an archive with an incorrect format. The old versions can
+ list the contents of the zip file but cannot extract it anyway (because
+ of the new compression algorithm). If you do not use encryption and
+ use regular disk files, you do not have to care about this problem.
+
+ Under VMS, not all of the odd file formats are treated properly. Only
+ stream-LF format zip files are expected to work with zip. Others can
+ be converted using Rahul Dhesi's BILF program. This version of zip
+ handles some of the conversion internally. When using Kermit to trans-
+ fer zip files from VMS to MSDOS, type "set file type block" on VMS.
+ When transfering from MSDOS to VMS, type "set file type fixed" on VMS.
+ In both cases, type "set file type binary" on MSDOS.
+
+ Under some older VMS versions, zip may hang for file specifications
+ that use DECnet syntax foo::*.*.
+
+ On OS/2, zip cannot match some names, such as those including an excla-
+ mation mark or a hash sign. This is a bug in OS/2 itself: the 32-bit
+ DosFindFirst/Next don't find such names. Other programs such as GNU
+ tar are also affected by this bug.
+
+ Under OS/2, the amount of Extended Attributes displayed by DIR is (for
+ compatibility) the amount returned by the 16-bit version of DosQuery-
+ PathInfo(). Otherwise OS/2 1.3 and 2.0 would report different EA sizes
+ when DIRing a file. However, the structure layout returned by the
+ 32-bit DosQueryPathInfo() is a bit different, it uses extra padding
+ bytes and link pointers (it's a linked list) to have all fields on
+ 4-byte boundaries for portability to future RISC OS/2 versions. There-
+ fore the value reported by zip (which uses this 32-bit-mode size) dif-
+ fers from that reported by DIR. zip stores the 32-bit format for
+ portability, even the 16-bit MS-C-compiled version running on OS/2 1.3,
+ so even this one shows the 32-bit-mode size.
+
+AUTHORS
+ Copyright (C) 1997-2008 Info-ZIP.
+
+ Currently distributed under the Info-ZIP license.
+
+ Copyright (C) 1990-1997 Mark Adler, Richard B. Wales, Jean-loup Gailly,
+ Onno van der Linden, Kai Uwe Rommel, Igor Mandrichenko, John Bush and
+ Paul Kienitz.
+
+ Original copyright:
+
+ Permission is granted to any individual or institution to use, copy, or
+ redistribute this software so long as all of the original files are
+ included, that it is not sold for profit, and that this copyright
+ notice is retained.
+
+ LIKE ANYTHING ELSE THAT'S FREE, ZIP AND ITS ASSOCIATED UTILITIES ARE
+ PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED
+ OR IMPLIED. IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE.
+
+ Please send bug reports and comments using the web page at: www.info-
+ zip.org. For bug reports, please include the version of zip (see
+ zip -h), the make options used to compile it (see zip -v), the machine
+ and operating system in use, and as much additional information as pos-
+ sible.
+
+ACKNOWLEDGEMENTS
+ Thanks to R. P. Byrne for his Shrink.Pas program, which inspired this
+ project, and from which the shrink algorithm was stolen; to Phil Katz
+ for placing in the public domain the zip file format, compression for-
+ mat, and .ZIP filename extension, and for accepting minor changes to
+ the file format; to Steve Burg for clarifications on the deflate for-
+ mat; to Haruhiko Okumura and Leonid Broukhis for providing some useful
+ ideas for the compression algorithm; to Keith Petersen, Rich Wales,
+ Hunter Goatley and Mark Adler for providing a mailing list and ftp site
+ for the Info-ZIP group to use; and most importantly, to the Info-ZIP
+ group itself (listed in the file infozip.who) without whose tireless
+ testing and bug-fixing efforts a portable zip would not have been pos-
+ sible. Finally we should thank (blame) the first Info-ZIP moderator,
+ David Kirschbaum, for getting us into this mess in the first place.
+ The manual page was rewritten for Unix by R. P. C. Rodgers and updated
+ by E. Gordon for zip 3.0.
+
+Info-ZIP 16 June 2008 (v3.0) ZIP(1L)
diff --git a/zip30.ann b/zip30.ann
new file mode 100644
index 0000000..2e8cfce
--- /dev/null
+++ b/zip30.ann
@@ -0,0 +1,95 @@
+Zip 3.0
+
+We have posted Zip 3.0, July 5th 2008. This is a major upgrade
+from Zip 2.32, the current Zip 2.x release. A quick summary of
+features is below, but see the file WhatsNew for the detailed list
+of major features and upgrades as well as what's on the list for
+Zip 3.1. Send in your feature suggestions and bug reports.
+
+Quick list of major changes in Zip 3.0:
+
+- Large files. Support for files and archives greater than 2 GB using
+ large file I/O and the Zip64 extensions. Also can now have more
+ than 64K entries in an archive.
+
+- Split archives. Zip now supports split archives, zip archives
+ split into a set of files that can then be stored on removable media
+ for instance.
+
+- Unicode. If Unicode support is enabled and supported on the system
+ Zip is run on, Zip now can read paths not in the current character
+ set and store those paths in portable UTF-8 format. These Unicode
+ paths can then be used to partially or fully recreate the paths on
+ other systems depending on the character set support provided by
+ the unzip on the receiving system. In particular, this allows
+ portability of paths between Windows and Unix. Unicode comments
+ are also supported on systems where UTF-8 is the current character
+ set. Unicode comment support for other systems is expected in
+ Zip 3.1.
+
+- New command line parser. This new parser allows for command line
+ permuting, where options can appear almost anywhere on the command
+ line. This allows adding options to the end of the command line,
+ for instance. It also supports long options, allowing for
+ more readable command lines, and also allows lists for the -x
+ exclude and -i include options to appear not just at the end of
+ the command line. And some bugs in command line processing in
+ Zip 2.32 have been fixed.
+
+- Unix 32-bit UIDs/GIDs. Now UIDs/GIDs larger than 16 bits are
+ supported, but UnZip 6.0 is needed to restore these larger
+ UIDs/GIDs. If Zip detects that the current system does not use
+ 16-bit UIDs/GIDs, the old 16-bit UID/GID storage is not used
+ as putting 32-bit UIDs/GIDs into 16-bit fields can cause
+ problems.
+
+- New modes. Additional archive modes have been added, including a
+ difference mode for supporting incremental backups, a file sync
+ mode for synchronizing an existing archive with the current file
+ system (which can be much faster than creating a new archive), and
+ a copy mode that allows copying entries from one archive to another.
+
+- Compression using bzip2. Now can add bzip2 compression as a
+ compression option in Zip. bzip2 compression can result in much
+ more compact entries in some cases, but the user should verify
+ that bzip2 is supported on the target unzip before using this new
+ compression choice.
+
+- New Windows dll. The Windows dll has been updated to support the
+ new Zip64 large file and larger number of entries limits. This
+ new dll is not backward compatible with the Zip 2.32 dll, as the
+ arguments to the dll have been updated to support the added
+ capabilities, but modifying existing programs to use the new dll
+ should be simple. See the included Visual Basic example project
+ for details.
+
+- Better streaming and piping. Zip now has better support of
+ streaming and piping and handles Unix FIFOs (named pipes) better.
+
+- Gobs of new progress information. Zip can now output progress
+ information, such as how many entries processed and to go, how
+ many bytes processed and to go, and adjustable size progress
+ dots. If the initial file scan takes longer than about 5
+ seconds, Zip now outputs dots during the scan to avoid a long
+ period of quiet. Zip can also now generate log files.
+
+- Updated archive fixing. The archive fixing capability is
+ slightly improved, and now can fix split archives.
+
+- Windows Archive bit support. The Windows archive bit is now
+ supported, though the new difference mode is probably more
+ reliable than relying on the Windows archive bit for creating
+ incremental backups.
+
+- File lists. Zip can list the files that would be added to an
+ archive as well as the files in an existing archive.
+
+- Extended help. A new extended help option lists a very terse
+ summary of the major features of Zip and how to use them.
+
+- Many bug fixes.
+
+As always, see the Zip manual page for details on what Zip has and
+how to use all features.
+
+Enjoy!
diff --git a/zip30f.ann b/zip30f.ann
new file mode 100644
index 0000000..79285e0
--- /dev/null
+++ b/zip30f.ann
@@ -0,0 +1,61 @@
+Zip 3.0f
+
+We have posted Zip Beta 3.0f, September 24th 2007. This is a beta
+release, but is more or less complete. See the file WhatsNew for
+a list of major features implemented and what's left.
+
+The archive reading and writing code in this beta has been redone to
+support split archives. We've extensively tested the code over the
+last year, but you should thoroughly test it yourself before relying
+on it. Also note that Unicode support is preliminary and may change
+before release, but currently there seems agreement between Info-ZIP
+and others on how to handle storing UTF-8 paths and that approach is
+implemented in Zip 3.0.
+
+Please test this beta and let us know if we're ready to officially
+release Zip 3.0.
+
+New things in Zip 3.0f
+- Split archives - Zip now can create and indirectly update split
+ archives
+- Unicode support - Zip now stores Unicode paths that should be more
+ portable across character sets and languages and Zip now can
+ read Windows file names in most all character sets using Unicode,
+ but this support is preliminary and may change by release
+- bzip2 - bzip2 compression is now supported
+- Console writing - Messages to the console are more consistently
+ formatted
+- Streaming - Directories are now handled better when streaming
+- Date range - Can now use -t and -tt to set a date range
+- UnZip Check - Check if UnZip 6.00 or later is available for
+ testing a Zip64 archive
+- License - minor updates to the license
+- Difference mode - A new option -DF (--dif) creates an output archive that
+ includes only files changed or added since the input archive was created,
+ and might be useful for incremental backups
+- File Sync - New option -FS synchronizes the entries in an archive with the
+ files on the file system, adding, updating, and deleting entries as needed,
+ creating an updated archive that should be the same as a new archive, but
+ since existing entries are copied and not recompressed it can be faster
+- Fix options - Options -F and -FF now fix split archives
+- Copy Mode - This new mode allows selecting archive entries to copy
+ to a new archive
+- Case matching - On Windows and VMS, option -ic (ignore case) turns off
+ case-sensitive matching of command line input patterns when matching
+ entries in an archive
+- Windows OEM - With this compile option, file names are saved on
+ Windows in the local OEM character set, as some other zips do
+- Windows Archive Bit support - On Windows can now select files
+ using the Windows archive bit
+- Global dots - Can now set quiet mode, but output progress dots every
+ so many bytes read, settable from KB to TB, allowing progress to be
+ displayed for large archives without the screen scrolling
+- Empty archives - Options -i or -i@ can now output empty archives,
+ which is useful in some scripts
+- Keep extra fields option - Option -X- allows passing through extra
+ fields that Zip does not process
+- Large file encryption bug fixed - Fix for bug that very rarely
+ results in bad data being stored when deflating and encrypting
+ uncompressable large amounts of data and resulting in CRC errors
+- Show Files option - Can list the files that would be operated on
+- Delete date bug fixed - Bug when using -d with -t or -tt is fixed
diff --git a/zip30g.ann b/zip30g.ann
new file mode 100644
index 0000000..8ec2e38
--- /dev/null
+++ b/zip30g.ann
@@ -0,0 +1,33 @@
+Zip 3.0g
+
+We have posted Zip Beta 3.0g, January 30th 2008. This is a beta
+release, but is more or less complete and is considered a release
+candidate. See the file WhatsNew for a list of major features
+implemented and what's left.
+
+The archive reading and writing code in Zip 3.0 has been redone to
+support split archives. We've extensively tested the code over the
+last year, but you should thoroughly test it yourself before relying
+on it. Also note that Unicode support has been added and should comply
+with the latest AppNote, but is still new and so may need refining.
+
+Please test this beta and let us know if we're ready to officially
+release Zip 3.0.
+
+New things in Zip 3.0g
+- Add split support to VB project for Zip64.
+
+- Disable reading of Unix FIFOs unless new -FI option used to avoid an
+ archiving operation stopping when it hits an active unfed FIFO.
+
+- The [list] wildcard expression (regular expression matching of any
+ character or range of characters in list) is now disabled on DOS and
+ Windows as it has caused confusion when filenames have [ and ] in
+ them. The new -RE option reenables it.
+
+- Add negation to many display options such as -dc and -db.
+
+- Allow -FF to read and fix archives having local entries that appear
+ after central directory entries.
+
+- Many small bug fixes.
diff --git a/zip30h.ann b/zip30h.ann
new file mode 100644
index 0000000..48bda34
--- /dev/null
+++ b/zip30h.ann
@@ -0,0 +1,47 @@
+Zip 3.0h
+
+We have posted Zip Beta 3.0h, May 31st 2008. This is a beta
+release, but is more or less complete and is considered a release
+candidate. See the file WhatsNew for a list of major features
+implemented and what's left.
+
+The archive reading and writing code in Zip 3.0 has been redone to
+support split archives. We've extensively tested the code over the
+last year, but you should thoroughly test it yourself before relying
+on it. Also note that Unicode support has been added and should comply
+with the latest AppNote, but is still new and so may need refining.
+
+Please test this beta and let us know if we're ready to officially
+release Zip 3.0.
+
+New things in Zip 3.0h
+- Allow -@ and -x to work together.
+
+- Change long Unicode escapes from #Lxxxxxxxx to #Lxxxxxx.
+
+- Unicode code cleanup to support additional compilers and also
+ some memory leak fixes.
+
+- Update symbolic link checks.
+
+- Add support for 32-bit UIDs/GIDs.
+
+- Update VMS notes.
+
+- Fix bug where directory scan using -AS (include only files
+ with Windows archive bit set) would skip files in directories
+ with bit not set.
+
+- Add Unix IBM support.
+
+- Change -W to -ws to free -W for later use.
+
+- Fix large file support for MinGW.
+
+- Fix large file support for bzip2.
+
+- Fix compile error in ZipCloak when UNICODE_SUPPORT is not enabled.
+
+- Fix Unicode bug in ZipCloak involving Unicode paths.
+
+- Additional small bug fixes.
diff --git a/zipcloak.c b/zipcloak.c
new file mode 100644
index 0000000..37bd414
--- /dev/null
+++ b/zipcloak.c
@@ -0,0 +1,771 @@
+/*
+ zipcloak.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ This code was originally written in Europe and could be freely distributed
+ from any country except the U.S.A. If this code was imported into the U.S.A,
+ it could not be re-exported from the U.S.A to another country. (This
+ restriction might seem curious but this is what US law required.)
+
+ Now this code can be freely exported and imported. See README.CR.
+ */
+#define __ZIPCLOAK_C
+
+#ifndef UTIL
+# define UTIL
+#endif
+#include "zip.h"
+#define DEFCPYRT /* main module: enable copyright string defines! */
+#include "revision.h"
+#include "crc32.h"
+#include "crypt.h"
+#include "ttyio.h"
+#include <signal.h>
+#ifndef NO_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if CRYPT /* defined (as TRUE or FALSE) in crypt.h */
+
+int main OF((int argc, char **argv));
+
+local void handler OF((int sig));
+local void license OF((void));
+local void help OF((void));
+local void version_info OF((void));
+
+/* Temporary zip file pointer */
+local FILE *tempzf;
+
+/* Pointer to CRC-32 table (used for decryption/encryption) */
+#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
+ZCONST ulg near *crc_32_tab;
+#else
+ZCONST uLongf *crc_32_tab;
+#endif
+
+int set_filetype(out_path)
+ char *out_path;
+{
+#ifdef __BEOS__
+ /* Set the filetype of the zipfile to "application/zip" */
+ setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+ /* Set the filetype of the zipfile to "application/x-zip" */
+ setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+ /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+ setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+ /* Set the filetype of the zipfile to &DDC */
+ setfiletype(out_path, 0xDDC);
+#endif
+ return ZE_OK;
+}
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ */
+int rename_split(temp_name, out_path)
+ char *temp_name;
+ char *out_path;
+{
+ int r;
+ /* Replace old zip file with new zip file, leaving only the new one */
+ if ((r = replace(out_path, temp_name)) != ZE_OK)
+ {
+ zipwarn("new zip file left as: ", temp_name);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ZIPERR(r, "was replacing split file");
+ }
+ if (zip_attributes) {
+ setfileattr(out_path, zip_attributes);
+ }
+ return ZE_OK;
+}
+
+void zipmessage_nl(a, nl)
+ZCONST char *a; /* message string to output */
+int nl; /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+ If nl true, print and add new line. */
+{
+ if (noisy) {
+ fprintf(mesg, "%s", a);
+ if (nl) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ } else {
+ mesg_line_started = 1;
+ }
+ fflush(mesg);
+ }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b; /* message strings juxtaposed in output */
+/* Print a message to mesg and flush. Write new line first
+ if current line has output already. */
+{
+ if (noisy) {
+ if (mesg_line_started)
+ fprintf(mesg, "\n");
+ fprintf(mesg, "%s%s\n", a, b);
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+}
+
+/***********************************************************************
+ * Issue a message for the error, clean up files and memory, and exit.
+ */
+void ziperr(code, msg)
+ int code; /* error code from the ZE_ class */
+ ZCONST char *msg; /* message about how it happened */
+{
+ if (PERR(code)) perror("zipcloak error");
+ fprintf(mesg, "zipcloak error: %s (%s)\n", ZIPERRORS(code), msg);
+ if (tempzf != NULL) fclose(tempzf);
+ if (tempzip != NULL) {
+ destroy(tempzip);
+ free((zvoid *)tempzip);
+ }
+ if (zipfile != NULL) free((zvoid *)zipfile);
+ EXIT(code);
+}
+
+/***********************************************************************
+ * Print a warning message to mesg (usually stderr) and return.
+ */
+void zipwarn(msg1, msg2)
+ ZCONST char *msg1, *msg2; /* message strings juxtaposed in output */
+{
+ fprintf(mesg, "zipcloak warning: %s%s\n", msg1, msg2);
+}
+
+
+/***********************************************************************
+ * Upon getting a user interrupt, turn echo back on for tty and abort
+ * cleanly using ziperr().
+ */
+local void handler(sig)
+ int sig; /* signal number (ignored) */
+{
+#if (!defined(MSDOS) && !defined(__human68k__) && !defined(RISCOS))
+ echon();
+ putc('\n', mesg);
+#endif
+ ziperr(ZE_ABORT +sig-sig, "aborting");
+ /* dummy usage of sig to avoid compiler warnings */
+}
+
+
+static ZCONST char *public[] = {
+"The encryption code of this program is not copyrighted and is",
+"put in the public domain. It was originally written in Europe",
+"and can be freely distributed in both source and object forms",
+"from any country, including the USA under License Exception",
+"TSU of the U.S. Export Administration Regulations (section",
+"740.13(e)) of 6 June 2002. (Prior to January 2000, re-export",
+"from the US was a violation of US law.)"
+};
+
+/***********************************************************************
+ * Print license information to stdout.
+ */
+local void license()
+{
+ extent i; /* counter for copyright array */
+
+ for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++) {
+ puts(swlicense[i]);
+ }
+ putchar('\n');
+ printf("Export notice:\n");
+ for (i = 0; i < sizeof(public)/sizeof(char *); i++) {
+ puts(public[i]);
+ }
+}
+
+
+static ZCONST char *help_info[] = {
+"",
+"ZipCloak %s (%s)",
+#ifdef VM_CMS
+"Usage: zipcloak [-dq] [-b fm] zipfile",
+#else
+"Usage: zipcloak [-dq] [-b path] zipfile",
+#endif
+" the default action is to encrypt all unencrypted entries in the zip file",
+"",
+" -d --decrypt decrypt encrypted entries (copy if given wrong password)",
+#ifdef VM_CMS
+" -b --temp-mode use \"fm\" as the filemode for the temporary zip file",
+#else
+" -b --temp-path use \"path\" for the temporary zip file",
+#endif
+" -O --output-file write output to new zip file",
+" -q --quiet quiet operation, suppress some informational messages",
+" -h --help show this help",
+" -v --version show version info",
+" -L --license show software license"
+ };
+
+/***********************************************************************
+ * Print help (along with license info) to stdout.
+ */
+local void help()
+{
+ extent i; /* counter for help array */
+
+ for (i = 0; i < sizeof(help_info)/sizeof(char *); i++) {
+ printf(help_info[i], VERSION, REVDATE);
+ putchar('\n');
+ }
+}
+
+
+local void version_info()
+/* Print verbose info about program version and compile time options
+ to stdout. */
+{
+ extent i; /* counter in text arrays */
+
+ /* Options info array */
+ static ZCONST char *comp_opts[] = {
+#ifdef DEBUG
+ "DEBUG",
+#endif
+#if CRYPT && defined(PASSWD_FROM_STDIN)
+ "PASSWD_FROM_STDIN",
+#endif /* CRYPT && PASSWD_FROM_STDIN */
+ NULL
+ };
+
+ for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+ {
+ printf(copyright[i], "zipcloak");
+ putchar('\n');
+ }
+ putchar('\n');
+
+ for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+ {
+ printf(versinfolines[i], "ZipCloak", VERSION, REVDATE);
+ putchar('\n');
+ }
+
+ version_local();
+
+ puts("ZipCloak special compilation options:");
+ for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+ {
+ printf("\t%s\n",comp_opts[i]);
+ }
+ printf("\t[encryption, version %d.%d%s of %s]\n",
+ CR_MAJORVER, CR_MINORVER, CR_BETA_VER, CR_VERSION_DATE);
+}
+
+/* options for zipcloak - 3/5/2004 EG */
+struct option_struct far options[] = {
+ /* short longopt value_type negatable ID name */
+#ifdef VM_CMS
+ {"b", "temp-mode", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'b', "temp file mode"},
+#else
+ {"b", "temp-path", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'b', "path for temp file"},
+#endif
+ {"d", "decrypt", o_NO_VALUE, o_NOT_NEGATABLE, 'd', "decrypt"},
+ {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
+ {"L", "license", o_NO_VALUE, o_NOT_NEGATABLE, 'L', "license"},
+ {"l", "", o_NO_VALUE, o_NOT_NEGATABLE, 'L', "license"},
+ {"O", "output-file", o_REQUIRED_VALUE, o_NOT_NEGATABLE, 'O', "output to new archive"},
+ {"v", "version", o_NO_VALUE, o_NOT_NEGATABLE, 'v', "version"},
+ /* the end of the list */
+ {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
+ };
+
+
+/***********************************************************************
+ * Encrypt or decrypt all of the entries in a zip file. See the command
+ * help in help() above.
+ */
+
+int main(argc, argv)
+ int argc; /* number of tokens in command line */
+ char **argv; /* command line tokens */
+{
+ int attr; /* attributes of zip file */
+ zoff_t start_offset; /* start of central directory */
+ int decrypt; /* decryption flag */
+ int temp_path; /* 1 if next argument is path for temp files */
+ char passwd[IZ_PWLEN+1]; /* password for encryption or decryption */
+ char verify[IZ_PWLEN+1]; /* password for encryption or decryption */
+#if 0
+ char *q; /* steps through option arguments */
+ int r; /* arg counter */
+#endif
+ int res; /* result code */
+ zoff_t length; /* length of central directory */
+ FILE *inzip, *outzip; /* input and output zip files */
+ struct zlist far *z; /* steps through zfiles linked list */
+ /* used by get_option */
+ unsigned long option; /* option ID returned by get_option */
+ int argcnt = 0; /* current argcnt in args */
+ int argnum = 0; /* arg number */
+ int optchar = 0; /* option state */
+ char *value = NULL; /* non-option arg, option value or NULL */
+ int negated = 0; /* 1 = option negated */
+ int fna = 0; /* current first non-opt arg */
+ int optnum = 0; /* index in table */
+
+ char **args; /* copy of argv that can be freed */
+
+#ifdef THEOS
+ setlocale(LC_CTYPE, "I");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+ /* For Unix, set the locale to UTF-8. Any UTF-8 locale is
+ OK and they should all be the same. This allows seeing,
+ writing, and displaying (if the fonts are loaded) all
+ characters in UTF-8. */
+ {
+ char *loc;
+
+ /*
+ loc = setlocale(LC_CTYPE, NULL);
+ printf(" Initial language locale = '%s'\n", loc);
+ */
+
+ loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+ /*
+ printf("langinfo %s\n", nl_langinfo(CODESET));
+ */
+
+ if (loc != NULL) {
+ /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+ using_utf8 = 1;
+ /*
+ printf(" Locale set to %s\n", loc);
+ */
+ } else {
+ /*
+ printf(" Could not set Unicode UTF-8 locale\n");
+ */
+ }
+ }
+# endif
+#endif
+
+ /* If no args, show help */
+ if (argc == 1) {
+ help();
+ EXIT(ZE_OK);
+ }
+
+ /* Informational messages are written to stdout. */
+ mesg = stdout;
+
+ init_upper(); /* build case map table */
+
+ crc_32_tab = get_crc_table();
+ /* initialize crc table for crypt */
+
+ /* Go through args */
+ zipfile = tempzip = NULL;
+ tempzf = NULL;
+#ifdef SIGINT
+ signal(SIGINT, handler);
+#endif
+#ifdef SIGTERM /* Some don't have SIGTERM */
+ signal(SIGTERM, handler);
+#endif
+#ifdef SIGABRT
+ signal(SIGABRT, handler);
+#endif
+#ifdef SIGBREAK
+ signal(SIGBREAK, handler);
+#endif
+#ifdef SIGBUS
+ signal(SIGBUS, handler);
+#endif
+#ifdef SIGILL
+ signal(SIGILL, handler);
+#endif
+#ifdef SIGSEGV
+ signal(SIGSEGV, handler);
+#endif
+ temp_path = decrypt = 0;
+#if 0
+ /* old command line */
+ for (r = 1; r < argc; r++) {
+ if (*argv[r] == '-') {
+ if (!argv[r][1]) ziperr(ZE_PARMS, "zip file cannot be stdin");
+ for (q = argv[r]+1; *q; q++) {
+ switch (*q) {
+ case 'b': /* Specify path for temporary file */
+ if (temp_path) {
+ ziperr(ZE_PARMS, "use -b before zip file name");
+ }
+ temp_path = 1; /* Next non-option is path */
+ break;
+ case 'd':
+ decrypt = 1; break;
+ case 'h': /* Show help */
+ help();
+ EXIT(ZE_OK);
+ case 'l': case 'L': /* Show copyright and disclaimer */
+ license();
+ EXIT(ZE_OK);
+ case 'q': /* Quiet operation, suppress info messages */
+ noisy = 0; break;
+ case 'v': /* Show version info */
+ version_info();
+ EXIT(ZE_OK);
+ default:
+ ziperr(ZE_PARMS, "unknown option");
+ } /* switch */
+ } /* for */
+
+ } else if (temp_path == 0) {
+ if (zipfile != NULL) {
+ ziperr(ZE_PARMS, "can only specify one zip file");
+
+ } else if ((zipfile = ziptyp(argv[r])) == NULL) {
+ ziperr(ZE_MEM, "was processing arguments");
+ }
+ } else {
+ tempath = argv[r];
+ temp_path = 0;
+ } /* if */
+ } /* for */
+
+#else
+
+ /* new command line */
+
+ zipfile = NULL;
+ out_path = NULL;
+
+ /* make copy of args that can use with insert_arg() */
+ args = copy_args(argv, 0);
+
+ /*
+ -------------------------------------------
+ Process command line using get_option
+ -------------------------------------------
+
+ Each call to get_option() returns either a command
+ line option and possible value or a non-option argument.
+ Arguments are permuted so that all options (-r, -b temp)
+ are returned before non-option arguments (zipfile).
+ Returns 0 when nothing left to read.
+ */
+
+ /* set argnum = 0 on first call to init get_option */
+ argnum = 0;
+
+ /* get_option returns the option ID and updates parameters:
+ args - usually same as argv if no argument file support
+ argcnt - current argc for args
+ value - char* to value (free() when done with it) or NULL if no value
+ negated - option was negated with trailing -
+ */
+
+ while ((option = get_option(&args, &argcnt, &argnum,
+ &optchar, &value, &negated,
+ &fna, &optnum, 0)))
+ {
+ switch (option)
+ {
+ case 'b': /* Specify path for temporary file */
+ if (temp_path) {
+ ziperr(ZE_PARMS, "more than one temp_path");
+ }
+ temp_path = 1;
+ tempath = value;
+ break;
+ case 'd':
+ decrypt = 1; break;
+ case 'h': /* Show help */
+ help();
+ EXIT(ZE_OK);
+ case 'l': case 'L': /* Show copyright and disclaimer */
+ license();
+ EXIT(ZE_OK);
+ case 'O': /* Output to new zip file instead of updating original zip file */
+ if ((out_path = ziptyp(value)) == NULL) {
+ ziperr(ZE_MEM, "was processing arguments");
+ }
+ free(value);
+ break;
+ case 'q': /* Quiet operation, suppress info messages */
+ noisy = 0; break;
+ case 'v': /* Show version info */
+ version_info();
+ EXIT(ZE_OK);
+ case o_NON_OPTION_ARG:
+ /* not an option */
+ /* no more options as permuting */
+ /* just dash also ends up here */
+
+ if (strcmp(value, "-") == 0) {
+ ziperr(ZE_PARMS, "zip file cannot be stdin");
+ } else if (zipfile != NULL) {
+ ziperr(ZE_PARMS, "can only specify one zip file");
+ }
+
+ if ((zipfile = ziptyp(value)) == NULL) {
+ ziperr(ZE_MEM, "was processing arguments");
+ }
+ free(value);
+ break;
+
+ default:
+ ziperr(ZE_PARMS, "unknown option");
+ }
+ }
+
+ free_args(args);
+
+#endif
+
+ if (zipfile == NULL) ziperr(ZE_PARMS, "need to specify zip file");
+
+ /* in_path is the input zip file */
+ if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+ ziperr(ZE_MEM, "input");
+ }
+ strcpy(in_path, zipfile);
+
+ /* out_path defaults to in_path */
+ if (out_path == NULL) {
+ if ((out_path = malloc(strlen(zipfile) + 1)) == NULL) {
+ ziperr(ZE_MEM, "output");
+ }
+ strcpy(out_path, zipfile);
+ }
+
+ /* Read zip file */
+ if ((res = readzipfile()) != ZE_OK) ziperr(res, zipfile);
+ if (zfiles == NULL) ziperr(ZE_NAME, zipfile);
+
+ /* Check for something to do */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (decrypt ? z->flg & 1 : !(z->flg & 1)) break;
+ }
+ if (z == NULL) {
+ ziperr(ZE_NONE, decrypt ? "no encrypted files"
+ : "all files encrypted already");
+ }
+
+ /* Before we get carried away, make sure zip file is writeable */
+ if ((inzip = fopen(zipfile, "a")) == NULL) ziperr(ZE_CREAT, zipfile);
+ fclose(inzip);
+ attr = getfileattr(zipfile);
+
+ /* Open output zip file for writing */
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+ {
+ int yd;
+ int i;
+
+ /* use mkstemp to avoid race condition and compiler warning */
+
+ if (tempath != NULL)
+ {
+ /* if -b used to set temp file dir use that for split temp */
+ if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, tempath);
+ if (lastchar(tempzip) != '/')
+ strcat(tempzip, "/");
+ }
+ else
+ {
+ /* create path by stripping name and appending template */
+ if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, zipfile);
+ for(i = strlen(tempzip); i > 0; i--) {
+ if (tempzip[i - 1] == '/')
+ break;
+ }
+ tempzip[i] = '\0';
+ }
+ strcat(tempzip, "ziXXXXXX");
+
+ if ((yd = mkstemp(tempzip)) == EOF) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ if ((y = tempzf = outzip = fdopen(yd, FOPW_TMP)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ }
+#else
+ if ((y = tempzf = outzip = fopen(tempzip = tempname(zipfile), FOPW)) == NULL) {
+ ziperr(ZE_TEMP, tempzip);
+ }
+#endif
+
+ /* Get password */
+ if (getp("Enter password: ", passwd, IZ_PWLEN+1) == NULL)
+ ziperr(ZE_PARMS,
+ "stderr is not a tty (you may never see this message!)");
+
+ if (decrypt == 0) {
+ if (getp("Verify password: ", verify, IZ_PWLEN+1) == NULL)
+ ziperr(ZE_PARMS,
+ "stderr is not a tty (you may never see this message!)");
+
+ if (strcmp(passwd, verify))
+ ziperr(ZE_PARMS, "password verification failed");
+
+ if (*passwd == '\0')
+ ziperr(ZE_PARMS, "zero length password not allowed");
+ }
+
+ /* Open input zip file again, copy preamble if any */
+ if ((in_file = fopen(zipfile, FOPR)) == NULL) ziperr(ZE_NAME, zipfile);
+
+ if (zipbeg && (res = bfcopy(zipbeg)) != ZE_OK)
+ {
+ ziperr(res, res == ZE_TEMP ? tempzip : zipfile);
+ }
+ tempzn = zipbeg;
+
+ /* Go through local entries, copying, encrypting, or decrypting */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (decrypt && (z->flg & 1)) {
+ printf("decrypting: %s", z->zname);
+ fflush(stdout);
+ if ((res = zipbare(z, passwd)) != ZE_OK)
+ {
+ if (res != ZE_MISS) ziperr(res, "was decrypting an entry");
+ printf(" (wrong password--just copying)");
+ fflush(stdout);
+ }
+ putchar('\n');
+
+ } else if ((!decrypt) && !(z->flg & 1)) {
+ printf("encrypting: %s\n", z->zname);
+ fflush(stdout);
+ if ((res = zipcloak(z, passwd)) != ZE_OK)
+ {
+ ziperr(res, "was encrypting an entry");
+ }
+ } else {
+ printf(" copying: %s\n", z->zname);
+ fflush(stdout);
+ if ((res = zipcopy(z)) != ZE_OK)
+ {
+ ziperr(res, "was copying an entry");
+ }
+ } /* if */
+ } /* for */
+
+ fclose(in_file);
+
+
+ /* Write central directory and end of central directory */
+
+ /* get start of central */
+ if ((start_offset = zftello(outzip)) == (zoff_t)-1)
+ ziperr(ZE_TEMP, tempzip);
+
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if ((res = putcentral(z)) != ZE_OK) ziperr(res, tempzip);
+ }
+
+ /* get end of central */
+ if ((length = zftello(outzip)) == (zoff_t)-1)
+ ziperr(ZE_TEMP, tempzip);
+
+ length -= start_offset; /* compute length of central */
+ if ((res = putend((zoff_t)zcount, length, start_offset, zcomlen,
+ zcomment)) != ZE_OK) {
+ ziperr(res, tempzip);
+ }
+ tempzf = NULL;
+ if (fclose(outzip)) ziperr(ZE_TEMP, tempzip);
+ if ((res = replace(out_path, tempzip)) != ZE_OK) {
+ zipwarn("new zip file left as: ", tempzip);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ziperr(res, "was replacing the original zip file");
+ }
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ setfileattr(zipfile, attr);
+#ifdef RISCOS
+ /* Set the filetype of the zipfile to &DDC */
+ setfiletype(zipfile, 0xDDC);
+#endif
+ free((zvoid *)in_path);
+ free((zvoid *)out_path);
+
+ free((zvoid *)zipfile);
+ zipfile = NULL;
+
+ /* Done! */
+ RETURN(0);
+}
+#else /* !CRYPT */
+
+
+/* below is only used if crypt is not enabled */
+
+struct option_struct far options[] = {
+ /* short longopt value_type negatable ID name */
+ {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
+ /* the end of the list */
+ {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
+ };
+
+
+int main OF((void));
+
+void zipwarn(msg1, msg2)
+ZCONST char *msg1, *msg2;
+{
+ /* Tell picky compilers to shut up about unused variables */
+ msg1 = msg1; msg2 = msg2;
+}
+
+void ziperr(c, h)
+int c;
+ZCONST char *h;
+{
+ /* Tell picky compilers to shut up about unused variables */
+ c = c; h = h;
+}
+
+int main()
+{
+ fprintf(mesg, "\
+This version of ZipCloak does not support encryption. Get the current Zip\n\
+source distribution and recompile ZipCloak after you have added an option to\n\
+define the symbol USE_CRYPT to the C compiler's command arguments.\n");
+ RETURN(1);
+}
+
+#endif /* ?CRYPT */
diff --git a/zipcloak.txt b/zipcloak.txt
new file mode 100644
index 0000000..0f24dc0
--- /dev/null
+++ b/zipcloak.txt
@@ -0,0 +1,75 @@
+zipcloak(1) zipcloak(1)
+
+NAME
+ zipcloak - encrypt entries in a zipfile
+
+SYNOPSIS
+ zipcloak [-d] [-b path] [-h] [-v] [-L] zipfile
+
+ARGUMENTS
+ zipfile Zipfile to encrypt entries in
+
+OPTIONS
+ -b path
+ --temp-path path
+ Use the directory given by path for the temporary zip file.
+
+ -d
+ --decrypt
+ Decrypt encrypted entries (copy if given wrong password).
+
+ -h
+ --help
+ Show a short help.
+
+ -L
+ --license
+ Show software license.
+
+ -O path
+ --output-file zipfile
+ Write output to new archive zipfile, leaving original archive as
+ is.
+
+ -q
+ --quiet
+ Quiet operation. Suppresses some informational messages.
+
+ -v
+ --version
+ Show version information.
+
+DESCRIPTION
+ zipcloak encrypts all unencrypted entries in the zipfile. This is the
+ default action.
+
+ The -d option is used to decrypt encrypted entries in the zipfile.
+
+ zipcloak uses original zip encryption which is considered weak.
+
+ Note: The encryption code of this program is not copyrighted and is
+ put in the public domain. It was originally written in Europe
+ and can be freely distributed from any country including the
+ U.S.A. (Previously if this program was imported into the U.S.A,
+ it could not be re-exported from the U.S.A to another country.)
+ See the file README.CR included in the source distribution for
+ more on this. Otherwise, the Info-ZIP license applies.
+
+EXAMPLES
+ To be added.
+
+BUGS
+ Large files (> 2 GB) and large archives not yet supported.
+
+ Split archives not yet supported. A work around is to convert the
+ split archive to a single-file archive using zip and then use zipcloak
+ on the single-file archive. If needed, the resulting archive can then
+ be split again using zip.
+
+SEE ALSO
+ zip(1), unzip(1)
+
+AUTHOR
+ Info-ZIP
+
+ v3.0 of 8 May 2008 zipcloak(1)
diff --git a/ziperr.h b/ziperr.h
new file mode 100644
index 0000000..19c7655
--- /dev/null
+++ b/ziperr.h
@@ -0,0 +1,115 @@
+/*
+ ziperr.h - Zip 3
+
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * ziperr.h by Mark Adler
+ */
+
+
+/*
+ * VMS message file ident string. (The "-xxx" suffix should be
+ * incremented when messages are changed for a particular program
+ * version.) Used only when generating the VMS message source file, but
+ * that can be done on a non-VMS system.
+ */
+#define VMS_MSG_IDENT "V3.0-000"
+
+/* VMS-compatible "severity" values (bits 2:0): */
+#define ZE_S_WARNING 0x00
+#define ZE_S_SUCCESS 0x01
+#define ZE_S_ERROR 0x02
+#define ZE_S_INFO 0x03
+#define ZE_S_SEVERE 0x04
+#define ZE_S_UNUSED 0x07
+
+/* Flags: */
+#define ZE_S_PERR 0x10
+
+
+ /* Error return values. The values 0..4 and 12..18 follow the conventions
+ of PKZIP. The values 4..10 are all assigned to "insufficient memory"
+ by PKZIP, so the codes 5..10 are used here for other purposes. */
+#define ZE_MISS -1 /* used by procname(), zipbare() */
+#define ZE_OK 0 /* success */
+#define ZE_EOF 2 /* unexpected end of zip file */
+#define ZE_FORM 3 /* zip file structure error */
+#define ZE_MEM 4 /* out of memory */
+#define ZE_LOGIC 5 /* internal logic error */
+#define ZE_BIG 6 /* entry too large to split, read, or write */
+#define ZE_NOTE 7 /* invalid comment format */
+#define ZE_TEST 8 /* zip test (-T) failed or out of memory */
+#define ZE_ABORT 9 /* user interrupt or termination */
+#define ZE_TEMP 10 /* error using a temp file */
+#define ZE_READ 11 /* read or seek error */
+#define ZE_NONE 12 /* nothing to do */
+#define ZE_NAME 13 /* missing or empty zip file */
+#define ZE_WRITE 14 /* error writing to a file */
+#define ZE_CREAT 15 /* couldn't open to write */
+#define ZE_PARMS 16 /* bad command line */
+#define ZE_OPEN 18 /* could not open a specified file to read */
+#define ZE_COMPERR 19 /* error in compilation options */
+#define ZE_ZIP64 20 /* Zip64 not supported */
+
+#define ZE_MAXERR 20 /* the highest error number */
+
+
+/* Error messages for the ziperr() function in the zip programs. */
+
+#ifdef GLOBALS
+struct
+{
+ char *name;
+ char *string;
+ int severity;
+} ziperrors[ZE_MAXERR + 1] = {
+/* 0 */ { "OK", "Normal successful completion", ZE_S_SUCCESS },
+/* 1 */ { "", "", ZE_S_UNUSED },
+/* 2 */ { "EOF", "Unexpected end of zip file", ZE_S_SEVERE },
+/* 3 */ { "FORM", "Zip file structure invalid", ZE_S_ERROR },
+/* 4 */ { "MEM", "Out of memory", ZE_S_SEVERE },
+/* 5 */ { "LOGIC", "Internal logic error", ZE_S_SEVERE },
+/* 6 */ { "BIG", "Entry too big to split, read, or write",
+ ZE_S_ERROR },
+/* 7 */ { "NOTE", "Invalid comment format", ZE_S_ERROR },
+/* 8 */ { "TEST", "Zip file invalid, could not spawn unzip, or wrong unzip",
+ ZE_S_SEVERE },
+/* 9 */ { "ABORT", "Interrupted", ZE_S_ERROR },
+/* 10 */ { "TEMP", "Temporary file failure", ZE_S_SEVERE | ZE_S_PERR },
+/* 11 */ { "READ", "Input file read failure", ZE_S_SEVERE | ZE_S_PERR },
+/* 12 */ { "NONE", "Nothing to do!", ZE_S_WARNING },
+/* 13 */ { "NAME", "Missing or empty zip file", ZE_S_ERROR },
+/* 14 */ { "WRITE", "Output file write failure", ZE_S_SEVERE | ZE_S_PERR },
+/* 15 */ { "CREAT", "Could not create output file", ZE_S_SEVERE | ZE_S_PERR },
+/* 16 */ { "PARMS", "Invalid command arguments", ZE_S_ERROR },
+/* 17 */ { "", "", ZE_S_UNUSED },
+/* 18 */ { "OPEN", "File not found or no read permission",
+ ZE_S_ERROR | ZE_S_PERR },
+/* 19 */ { "COMPERR", "Not supported", ZE_S_SEVERE },
+/* 20 */ { "ZIP64", "Attempt to read unsupported Zip64 archive",
+ ZE_S_SEVERE }
+# ifdef AZTEC_C
+ , /* extremely lame compiler bug workaround */
+# endif
+};
+#else /* !GLOBALS */
+/* Error messages for ziperr() */
+extern struct
+{
+ char *name;
+ char *string;
+ int severity;
+} ziperrors[ZE_MAXERR + 1];
+#endif /* ?GLOBALS */
+
+/* Macro to determine whether to call perror() or not. */
+#define PERR(e) (ziperrors[e].severity & ZE_S_PERR)
+
+/* Macro for easy access to the message string. */
+#define ZIPERRORS(e) ziperrors[e].string
diff --git a/zipfile.c b/zipfile.c
new file mode 100644
index 0000000..1990cde
--- /dev/null
+++ b/zipfile.c
@@ -0,0 +1,6820 @@
+/*
+ zipfile.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * zipfile.c by Mark Adler.
+ */
+#define __ZIPFILE_C
+
+#include "zip.h"
+#include "revision.h"
+#ifdef UNICODE_SUPPORT
+# include "crc32.h"
+#endif
+
+/* for realloc 2/6/2005 EG */
+#include <stdlib.h>
+
+#include <errno.h>
+
+/* for toupper() */
+#include <ctype.h>
+
+#ifdef VMS
+# include "vms/vms.h"
+# include "vms/vmsmunch.h"
+# include "vms/vmsdefs.h"
+#endif
+
+#ifdef WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
+/*
+ * XXX start of zipfile.h
+ */
+#ifdef THEOS
+ /* Macros cause stack overflow in compiler */
+ ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); }
+ ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); }
+#else /* !THEOS */
+ /* Macros for converting integers in little-endian to machine format */
+# define SH(a) ((ush)(((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8)))
+# define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
+# ifdef ZIP64_SUPPORT /* zip64 support 08/31/2003 R.Nausedat */
+# define LLG(a) ((zoff_t)LG(a) | ((zoff_t)LG((a)+4) << 32))
+# endif
+#endif /* ?THEOS */
+
+/* Macros for writing machine integers to little-endian format */
+#define PUTSH(a,f) {putc((char)((a) & 0xff),(f)); putc((char)((a) >> 8),(f));}
+#define PUTLG(a,f) {PUTSH((a) & 0xffff,(f)) PUTSH((a) >> 16,(f))}
+
+#ifdef ZIP64_SUPPORT /* zip64 support 08/31/2003 R.Nausedat */
+# define PUTLLG(a,f) {PUTLG((a) & 0xffffffff,(f)) PUTLG((a) >> 32,(f))}
+#endif
+
+
+/* -- Structure of a ZIP file -- */
+
+/* Signatures for zip file information headers */
+#define LOCSIG 0x04034b50L
+#define CENSIG 0x02014b50L
+#define ENDSIG 0x06054b50L
+#define EXTLOCSIG 0x08074b50L
+
+/* Offsets of values in headers */
+/* local header */
+#define LOCVER 0 /* version needed to extract */
+#define LOCFLG 2 /* encrypt, deflate flags */
+#define LOCHOW 4 /* compression method */
+#define LOCTIM 6 /* last modified file time, DOS format */
+#define LOCDAT 8 /* last modified file date, DOS format */
+#define LOCCRC 10 /* uncompressed crc-32 for file */
+#define LOCSIZ 14 /* compressed size in zip file */
+#define LOCLEN 18 /* uncompressed size */
+#define LOCNAM 22 /* length of filename */
+#define LOCEXT 24 /* length of extra field */
+
+/* extended local header (data descriptor) following file data (if bit 3 set) */
+/* if Zip64 then all are 8 byte and not below - 11/1/03 EG */
+#define EXTCRC 0 /* uncompressed crc-32 for file */
+#define EXTSIZ 4 /* compressed size in zip file */
+#define EXTLEN 8 /* uncompressed size */
+
+/* central directory header */
+#define CENVEM 0 /* version made by */
+#define CENVER 2 /* version needed to extract */
+#define CENFLG 4 /* encrypt, deflate flags */
+#define CENHOW 6 /* compression method */
+#define CENTIM 8 /* last modified file time, DOS format */
+#define CENDAT 10 /* last modified file date, DOS format */
+#define CENCRC 12 /* uncompressed crc-32 for file */
+#define CENSIZ 16 /* compressed size in zip file */
+#define CENLEN 20 /* uncompressed size */
+#define CENNAM 24 /* length of filename */
+#define CENEXT 26 /* length of extra field */
+#define CENCOM 28 /* file comment length */
+#define CENDSK 30 /* disk number start */
+#define CENATT 32 /* internal file attributes */
+#define CENATX 34 /* external file attributes */
+#define CENOFF 38 /* relative offset of local header */
+
+/* end of central directory record */
+#define ENDDSK 0 /* number of this disk */
+#define ENDBEG 2 /* number of the starting disk */
+#define ENDSUB 4 /* entries on this disk */
+#define ENDTOT 6 /* total number of entries */
+#define ENDSIZ 8 /* size of entire central directory */
+#define ENDOFF 12 /* offset of central on starting disk */
+#define ENDCOM 16 /* length of zip file comment */
+
+/* zip64 support 08/31/2003 R.Nausedat */
+
+/* EOCDL_SIG used to detect Zip64 archive */
+#define ZIP64_EOCDL_SIG 0x07064b50
+/* EOCDL size is used in the empty archive check */
+#define ZIP64_EOCDL_OFS_SIZE 20
+
+#define ZIP_UWORD16_MAX 0xFFFF /* border value */
+#define ZIP_UWORD32_MAX 0xFFFFFFFF /* border value */
+#define ZIP_EF_HEADER_SIZE 4 /* size of pre-header of extra fields */
+
+#ifdef ZIP64_SUPPORT
+# define ZIP64_EXTCRC 0 /* uncompressed crc-32 for file */
+# define ZIP64_EXTSIZ 4 /* compressed size in zip file */
+# define ZIP64_EXTLEN 12 /* uncompressed size */
+# define ZIP64_EOCD_SIG 0x06064b50
+# define ZIP64_EOCD_OFS_SIZE 40
+# define ZIP64_EOCD_OFS_CD_START 48
+# define ZIP64_EOCDL_OFS_SIZE 20
+# define ZIP64_EOCDL_OFS_EOCD_START 8
+# define ZIP64_EOCDL_OFS_TOTALDISKS 16
+# define ZIP64_MIN_VER 45 /* min version to set in the CD extra records */
+# define ZIP64_CENTRAL_DIR_TAIL_SIZE (56 - 8 - 4) /* size of zip64 central dir tail, minus sig and size field bytes */
+# define ZIP64_CENTRAL_DIR_TAIL_SIG 0x06064B50L /* zip64 central dir tail signature */
+# define ZIP64_CENTRAL_DIR_TAIL_END_SIG 0x07064B50L /* zip64 end of cen dir locator signature */
+# define ZIP64_LARGE_FILE_HEAD_SIZE 32 /* total size of zip64 extra field */
+# define ZIP64_EF_TAG 0x0001 /* ID for zip64 extra field */
+# define ZIP64_EFIELD_OFS_OSIZE ZIP_EF_HEADER_SIZE /* zip64 extra field: offset to original file size */
+# define ZIP64_EFIELD_OFS_CSIZE (ZIP64_EFIELD_OFS_OSIZE + 8) /* zip64 extra field: offset to compressed file size */
+# define ZIP64_EFIELD_OFS_OFS (ZIP64_EFIELD_OFS_CSIZE + 8) /* zip64 extra field: offset to offset in archive */
+# define ZIP64_EFIELD_OFS_DISK (ZIP64_EFIELD_OFS_OFS + 8) /* zip64 extra field: offset to start disk # */
+/* -------------------------------------------------------------------------------------------------------------------------- */
+ local int adjust_zip_local_entry OF((struct zlist far *));
+ local void adjust_zip_central_entry OF((struct zlist far *));
+#if 0
+ local int remove_local_extra_field OF((struct zlist far *, ulg));
+ local int remove_central_extra_field OF((struct zlist far *, ulg));
+#endif
+ local int add_central_zip64_extra_field OF((struct zlist far *));
+ local int add_local_zip64_extra_field OF((struct zlist far *));
+#endif /* ZIP64_SUPPORT */
+#ifdef UNICODE_SUPPORT
+# define UTF8_PATH_EF_TAG 0x7075 /* ID for Unicode path (up) extra field */
+ local int add_Unicode_Path_local_extra_field OF((struct zlist far *));
+ local int add_Unicode_Path_cen_extra_field OF((struct zlist far *));
+#endif
+
+/* New General Purpose Bit Flag bit 11 flags when entry path and
+ comment are in UTF-8 */
+#define UTF8_BIT (1 << 11)
+
+/* moved out of ZIP64_SUPPORT - 2/6/2005 EG */
+local void write_ushort_to_mem OF((ush, char *)); /* little endian conversions */
+local void write_ulong_to_mem OF((ulg, char *));
+#ifdef ZIP64_SUPPORT
+ local void write_int64_to_mem OF((uzoff_t, char *));
+#endif /* def ZIP64_SUPPORT */
+#ifdef UNICODE_SUPPORT
+ local void write_string_to_mem OF((char *, char *));
+#endif
+#if 0
+local char *get_extra_field OF((ush, char *, unsigned)); /* zip64 */
+#endif
+#ifdef UNICODE_SUPPORT
+local void read_Unicode_Path_entry OF((struct zlist far *));
+local void read_Unicode_Path_local_entry OF((struct zlist far *));
+#endif
+
+/* added these self allocators - 2/6/2005 EG */
+local void append_ushort_to_mem OF((ush, char **, extent *, extent *));
+local void append_ulong_to_mem OF((ulg, char **, extent *, extent *));
+#ifdef ZIP64_SUPPORT
+ local void append_int64_to_mem OF((uzoff_t, char **, extent *, extent *));
+#endif /* def ZIP64_SUPPORT */
+local void append_string_to_mem OF((char *, int, char**, extent *, extent *));
+
+
+/* Local functions */
+
+local int find_next_signature OF((FILE *f));
+local int find_signature OF((FILE *, ZCONST char *));
+local int is_signature OF((ZCONST char *, ZCONST char *));
+local int at_signature OF((FILE *, ZCONST char *));
+
+local int zqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
+#ifdef UNICODE_SUPPORT
+local int zuqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
+#endif
+#if 0
+ local int scanzipf_reg OF((FILE *f));
+#endif
+local int scanzipf_regnew OF((void));
+#ifndef UTIL
+ local int rqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
+ local int zbcmp OF((ZCONST zvoid *, ZCONST zvoid far *));
+# ifdef UNICODE_SUPPORT
+ local int zubcmp OF((ZCONST zvoid *, ZCONST zvoid far *));
+# if 0
+ local int zuebcmp OF((ZCONST zvoid *, ZCONST zvoid far *));
+# endif
+# endif /* UNICODE_SUPPORT */
+ local void zipoddities OF((struct zlist far *));
+# if 0
+ local int scanzipf_fix OF((FILE *f));
+# endif
+ local int scanzipf_fixnew OF((void));
+# ifdef USE_EF_UT_TIME
+ local int ef_scan_ut_time OF((char *ef_buf, extent ef_len, int ef_is_cent,
+ iztimes *z_utim));
+# endif /* USE_EF_UT_TIME */
+ local void cutpath OF((char *p, int delim));
+#endif /* !UTIL */
+
+/*
+ * XXX end of zipfile.h
+ */
+
+/* Local data */
+
+#ifdef HANDLE_AMIGA_SFX
+ ulg amiga_sfx_offset; /* place where size field needs updating */
+#endif
+
+local int zqcmp(a, b)
+ZCONST zvoid *a, *b; /* pointers to pointers to zip entries */
+/* Used by qsort() to compare entries in the zfile list.
+ * Compares the internal names z->iname */
+{
+ char *aname = (*(struct zlist far **)a)->iname;
+ char *bname = (*(struct zlist far **)b)->iname;
+
+ return namecmp(aname, bname);
+}
+
+#ifdef UNICODE_SUPPORT
+local int zuqcmp(a, b)
+ZCONST zvoid *a, *b; /* pointers to pointers to zip entries */
+/* Used by qsort() to compare entries in the zfile list.
+ * Compares the internal names z->zuname */
+{
+ char *aname = (*(struct zlist far **)a)->iname;
+ char *bname = (*(struct zlist far **)b)->iname;
+
+ /* zuname could be NULL */
+ if ((*(struct zlist far **)a)->zuname)
+ aname = (*(struct zlist far **)a)->zuname;
+ if ((*(struct zlist far **)b)->zuname)
+ bname = (*(struct zlist far **)b)->zuname;
+ return namecmp(aname, bname);
+}
+#endif
+
+
+#ifndef UTIL
+
+local int rqcmp(a, b)
+ZCONST zvoid *a, *b; /* pointers to pointers to zip entries */
+/* Used by qsort() to compare entries in the zfile list.
+ * Compare the internal names z->iname, but in reverse order. */
+{
+ return namecmp((*(struct zlist far **)b)->iname,
+ (*(struct zlist far **)a)->iname);
+}
+
+
+local int zbcmp(n, z)
+ZCONST zvoid *n; /* string to search for */
+ZCONST zvoid far *z; /* pointer to a pointer to a zip entry */
+/* Used by search() to compare a target to an entry in the zfile list. */
+{
+ return namecmp((char *)n, ((struct zlist far *)z)->zname);
+}
+
+#ifdef UNICODE_SUPPORT
+/* search unicode paths */
+local int zubcmp(n, z)
+ZCONST zvoid *n; /* string to search for */
+ZCONST zvoid far *z; /* pointer to a pointer to a zip entry */
+/* Used by search() to compare a target to an entry in the zfile list. */
+{
+ char *zuname = ((struct zlist far *)z)->zuname;
+
+ /* zuname is NULL if no UTF-8 name */
+ if (zuname == NULL)
+ zuname = ((struct zlist far *)z)->zname;
+
+ return namecmp((char *)n, zuname);
+}
+
+#if 0
+/* search escaped unicode paths */
+local int zuebcmp(n, z)
+ZCONST zvoid *n; /* string to search for */
+ZCONST zvoid far *z; /* pointer to a pointer to a zip entry */
+/* Used by search() to compare a target to an entry in the zfile list. */
+{
+ char *zuname = ((struct zlist far *)z)->zuname;
+ char *zuename;
+ int k;
+
+ /* zuname is NULL if no UTF-8 name */
+ if (zuname == NULL)
+ zuname = ((struct zlist far *)z)->zname;
+ zuename = local_to_escape_string(zuname);
+ k = namecmp((char *)n, zuename);
+ free(zuename);
+
+ return k;
+}
+#endif
+#endif
+
+
+struct zlist far *zsearch(n)
+ ZCONST char *n; /* name to find */
+/* Return a pointer to the entry in zfile with the name n, or NULL if
+ not found. */
+{
+ zvoid far **p; /* result of search() */
+
+ if (zcount) {
+ if ((p = search(n, (ZCONST zvoid far **)zsort, zcount, zbcmp)) != NULL)
+ return *(struct zlist far **)p;
+#ifdef UNICODE_SUPPORT
+ else if (unicode_mismatch != 3 && fix != 2 &&
+ (p = search(n, (ZCONST zvoid far **)zusort, zcount, zubcmp)) != NULL)
+ return *(struct zlist far **)p;
+#endif
+ else
+ return NULL;
+ }
+ return NULL;
+}
+
+#endif /* !UTIL */
+
+#ifndef VMS /* See [.VMS]VMS.C for VMS-specific ziptyp(). */
+# ifndef PATHCUT
+# define PATHCUT '/'
+# endif
+
+char *ziptyp(s)
+ char *s; /* file name to force to zip */
+/* If the file name *s has a dot (other than the first char), or if
+ the -A option is used (adjust self-extracting file) then return
+ the name, otherwise append .zip to the name. Allocate the space for
+ the name in either case. Return a pointer to the new name, or NULL
+ if malloc() fails. */
+{
+ char *q; /* temporary pointer */
+ char *t; /* pointer to malloc'ed string */
+# ifdef THEOS
+ char *r; /* temporary pointer */
+ char *disk;
+# endif
+
+ if ((t = malloc(strlen(s) + 5)) == NULL)
+ return NULL;
+ strcpy(t, s);
+# ifdef __human68k__
+ _toslash(t);
+# endif
+# ifdef MSDOS
+ for (q = t; *q; INCSTR(q))
+ if (*q == '\\')
+ *q = '/';
+# endif /* MSDOS */
+# if defined(__RSXNT__) || defined(WIN32_CRT_OEM)
+ /* RSXNT/EMX C rtl uses OEM charset */
+ AnsiToOem(t, t);
+# endif
+ if (adjust) return t;
+# ifndef RISCOS
+# ifndef QDOS
+# ifdef AMIGA
+ if ((q = MBSRCHR(t, '/')) == NULL)
+ q = MBSRCHR(t, ':');
+ if (MBSRCHR((q ? q + 1 : t), '.') == NULL)
+# else /* !AMIGA */
+# ifdef THEOS
+ /* the argument expansion add a dot to the end of file names when
+ * there is no extension and at least one of a argument has wild cards.
+ * So check for at least one character in the extension if there is a dot
+ * in file name */
+ if ((q = MBSRCHR((q = MBSRCHR(t, PATHCUT)) == NULL ? t : q + 1, '.')) == NULL
+ || q[1] == '\0') {
+# else /* !THEOS */
+# ifdef TANDEM
+ if (MBSRCHR((q = MBSRCHR(t, '.')) == NULL ? t : q + 1, ' ') == NULL)
+# else /* !TANDEM */
+ if (MBSRCHR((q = MBSRCHR(t, PATHCUT)) == NULL ? t : q + 1, '.') == NULL)
+# endif /* ?TANDEM */
+# endif /* ?THEOS */
+# endif /* ?AMIGA */
+# ifdef CMS_MVS
+ if (strncmp(t,"dd:",3) != 0 && strncmp(t,"DD:",3) != 0)
+# endif /* CMS_MVS */
+# ifdef THEOS
+ /* insert .zip extension before disk name */
+ if ((r = MBSRCHR(t, ':')) != NULL) {
+ /* save disk name */
+ if ((disk = strdup(r)) == NULL)
+ return NULL;
+ strcpy(r[-1] == '.' ? r - 1 : r, ".zip");
+ strcat(t, disk);
+ free(disk);
+ } else {
+ if (q != NULL && *q == '.')
+ strcpy(q, ".zip");
+ else
+ strcat(t, ".zip");
+ }
+ }
+# else /* !THEOS */
+# ifdef TANDEM /* Tandem can't cope with extensions */
+ strcat(t, " ZIP");
+# else /* !TANDEM */
+ strcat(t, ".zip");
+# endif /* ?TANDEM */
+# endif /* ?THEOS */
+# else /* QDOS */
+ q = LastDir(t);
+ if(MBSRCHR(q, '_') == NULL && MBSRCHR(q, '.') == NULL)
+ {
+ strcat(t, "_zip");
+ }
+# endif /* QDOS */
+# endif /* !RISCOS */
+ return t;
+}
+#endif /* ndef VMS */
+
+/* ---------------------------------------------------- */
+
+/* moved out of ZIP64_SUPPORT - 2/6/2005 EG */
+
+/* 08/31/2003 R.Nausedat */
+
+local void write_ushort_to_mem( OFT( ush) usValue,
+ OFT( char *)pPtr)
+#ifdef NO_PROTO
+ ush usValue;
+ char *pPtr;
+#endif /* def NO_PROTO */
+{
+ *pPtr++ = ((char)(usValue) & 0xff);
+ *pPtr = ((char)(usValue >> 8) & 0xff);
+}
+
+local void write_ulong_to_mem(uValue, pPtr)
+ulg uValue;
+char *pPtr;
+{
+ write_ushort_to_mem((ush)(uValue & 0xffff), pPtr);
+ write_ushort_to_mem((ush)((uValue >> 16) & 0xffff), pPtr + 2);
+}
+
+#ifdef ZIP64_SUPPORT
+
+local void write_int64_to_mem(l64Value,pPtr)
+ uzoff_t l64Value;
+ char *pPtr;
+{
+ write_ulong_to_mem((ulg)(l64Value & 0xffffffff),pPtr);
+ write_ulong_to_mem((ulg)((l64Value >> 32) & 0xffffffff),pPtr + 4);
+}
+
+#endif /* def ZIP64_SUPPORT */
+
+#ifdef UNICODE_SUPPORT
+
+/* Write a string to memory */
+local void write_string_to_mem(strValue, pPtr)
+ char *strValue;
+ char *pPtr;
+{
+ if (strValue != NULL) {
+ int ssize = strlen(strValue);
+ int i;
+
+ for (i = 0; i < ssize; i++) {
+ *(pPtr + i) = *(strValue + i);
+ }
+ }
+}
+
+#endif /* def UNICODE_SUPPORT */
+
+
+
+/* same as above but allocate memory as needed and keep track of current end
+ using offset - 2/6/05 EG */
+
+#if 0 /* ubyte version not used */
+local void append_ubyte_to_mem( OFT( unsigned char) ubValue,
+ OFT( char **) pPtr,
+ OFT( extent *) offset,
+ OFT( extent *) blocksize)
+#ifdef NO_PROTO
+ unsigned char ubValue; /* byte to append */
+ char **pPtr; /* start of block */
+ extent *offset; /* next byte to write */
+ extent *blocksize; /* current size of block */
+#endif /* def NO_PROTO */
+{
+ if (*pPtr == NULL) {
+ /* malloc a 1K block */
+ (*blocksize) = 1024;
+ *pPtr = (char *) malloc(*blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_ubyte_to_mem");
+ }
+ }
+ /* if (*offset) + 1 > (*blocksize) - 1 */
+ else if ((*offset) > (*blocksize) - (1 + 1)) {
+ /* realloc a bigger block in 1 K increments */
+ (*blocksize) += 1024;
+ *pPtr = realloc(*pPtr, *blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_ubyte_to_mem");
+ }
+ }
+ *(*pPtr + *offset) = ubValue;
+ (*offset)++;
+}
+#endif
+
+local void append_ushort_to_mem( OFT( ush) usValue,
+ OFT( char **) pPtr,
+ OFT( extent *) offset,
+ OFT( extent *) blocksize)
+#ifdef NO_PROTO
+ ush usValue;
+ char **pPtr;
+ extent *offset;
+ extent *blocksize;
+#endif /* def NO_PROTO */
+{
+ if (*pPtr == NULL) {
+ /* malloc a 1K block */
+ (*blocksize) = 1024;
+ *pPtr = (char *) malloc(*blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_ushort_to_mem");
+ }
+ }
+ /* if (*offset) + 2 > (*blocksize) - 1 */
+ else if ((*offset) > (*blocksize) - (1 + 2)) {
+ /* realloc a bigger block in 1 K increments */
+ (*blocksize) += 1024;
+ *pPtr = realloc(*pPtr, (extent)*blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_ushort_to_mem");
+ }
+ }
+ write_ushort_to_mem(usValue, (*pPtr) + (*offset));
+ (*offset) += 2;
+}
+
+local void append_ulong_to_mem(uValue, pPtr, offset, blocksize)
+ ulg uValue;
+ char **pPtr;
+ extent *offset;
+ extent *blocksize;
+{
+ if (*pPtr == NULL) {
+ /* malloc a 1K block */
+ (*blocksize) = 1024;
+ *pPtr = (char *) malloc(*blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_ulong_to_mem");
+ }
+ }
+ else if ((*offset) > (*blocksize) - (1 + 4)) {
+ /* realloc a bigger block in 1 K increments */
+ (*blocksize) += 1024;
+ *pPtr = realloc(*pPtr, *blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_ulong_to_mem");
+ }
+ }
+ write_ulong_to_mem(uValue, (*pPtr) + (*offset));
+ (*offset) += 4;
+}
+
+#ifdef ZIP64_SUPPORT
+
+local void append_int64_to_mem(l64Value, pPtr, offset, blocksize)
+ uzoff_t l64Value;
+ char **pPtr;
+ extent *offset;
+ extent *blocksize;
+{
+ if (*pPtr == NULL) {
+ /* malloc a 1K block */
+ (*blocksize) = 1024;
+ *pPtr = (char *) malloc(*blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_int64_to_mem");
+ }
+ }
+ else if ((*offset) > (*blocksize) - (1 + 8)) {
+ /* realloc a bigger block in 1 K increments */
+ (*blocksize) += 1024;
+ *pPtr = realloc(*pPtr, *blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_int64_to_mem");
+ }
+ }
+ write_int64_to_mem(l64Value, (*pPtr) + (*offset));
+ (*offset) += 8;
+}
+
+#endif /* def ZIP64_SUPPORT */
+
+/* Append a string to the memory block. */
+local void append_string_to_mem(strValue, strLength, pPtr, offset, blocksize)
+ char *strValue;
+ int strLength;
+ char **pPtr;
+ extent *offset;
+ extent *blocksize;
+{
+ if (strValue != NULL) {
+ unsigned bsize = 1024;
+ unsigned ssize = strLength;
+ unsigned i;
+
+ if (ssize > bsize) {
+ bsize = ssize;
+ }
+ if (*pPtr == NULL) {
+ /* malloc a 1K block */
+ (*blocksize) = bsize;
+ *pPtr = (char *) malloc(*blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_string_to_mem");
+ }
+ }
+ else if ((*offset) + ssize > (*blocksize) - 1) {
+ /* realloc a bigger block in 1 K increments */
+ (*blocksize) += bsize;
+ *pPtr = realloc(*pPtr, *blocksize);
+ if (*pPtr == NULL) {
+ ziperr(ZE_MEM, "append_string_to_mem");
+ }
+ }
+ for (i = 0; i < ssize; i++) {
+ *(*pPtr + *offset + i) = *(strValue + i);
+ }
+ (*offset) += ssize;
+ }
+}
+
+/* ---------------------------------------------------- */
+
+/* zip64 support 08/31/2003 R.Nausedat */
+/* moved out of zip64 support 10/22/05 */
+
+/* Searches pExtra for extra field with specified tag.
+ * If it finds one it returns a pointer to it, else NULL.
+ * Renamed and made generic. 10/3/03
+ */
+char *get_extra_field( OFT( ush) tag,
+ OFT( char *) pExtra,
+ OFT( unsigned) iExtraLen)
+#ifdef NO_PROTO
+ ush tag; /* tag to look for */
+ char *pExtra; /* pointer to extra field in memory */
+ unsigned iExtraLen; /* length of extra field */
+#endif /* def NO_PROTO */
+{
+ char *pTemp;
+ ush usBlockTag;
+ ush usBlockSize;
+
+ if( pExtra == NULL )
+ return NULL;
+
+ for (pTemp = pExtra; pTemp < pExtra + iExtraLen - ZIP_EF_HEADER_SIZE;)
+ {
+ usBlockTag = SH(pTemp); /* get tag */
+ usBlockSize = SH(pTemp + 2); /* get field data size */
+ if (usBlockTag == tag)
+ return pTemp;
+ pTemp += (usBlockSize + ZIP_EF_HEADER_SIZE);
+ }
+ return NULL;
+}
+
+/* copy_nondup_extra_fields
+ *
+ * Copy any extra fields in old that are not in new to new.
+ * Returns the new extra fields block and newLen is new length.
+ */
+char *copy_nondup_extra_fields(oldExtra, oldExtraLen, newExtra, newExtraLen, newLen)
+ char *oldExtra; /* pointer to old extra fields */
+ unsigned oldExtraLen; /* length of old extra fields */
+ char *newExtra; /* pointer to new extra fields */
+ unsigned newExtraLen; /* length of new extra fields */
+ unsigned *newLen; /* length of new extra fields after copy */
+{
+ char *returnExtra = NULL;
+ ush returnExtraLen = 0;
+ char *tempExtra;
+ char *pTemp;
+ ush tag;
+ ush blocksize;
+
+ if( oldExtra == NULL ) {
+ /* no old extra fields so return copy of newExtra */
+ if (newExtra == NULL || newExtraLen == 0) {
+ *newLen = 0;
+ return NULL;
+ } else {
+ if ((returnExtra = malloc(newExtraLen)) == NULL)
+ ZIPERR(ZE_MEM, "extra field copy");
+ memcpy(returnExtra, newExtra, newExtraLen);
+ returnExtraLen = newExtraLen;
+ *newLen = returnExtraLen;
+ return returnExtra;
+ }
+ }
+
+ /* allocate block large enough for all extra fields */
+ if ((tempExtra = malloc(0xFFFF)) == NULL)
+ ZIPERR(ZE_MEM, "extra field copy");
+
+ /* look for each old extra field in new block */
+ for (pTemp = oldExtra; pTemp < oldExtra + oldExtraLen;)
+ {
+ tag = SH(pTemp); /* get tag */
+ blocksize = SH(pTemp + 2); /* get field data size */
+ if (get_extra_field(tag, newExtra, newExtraLen) == NULL) {
+ /* tag not in new block so add it */
+ memcpy(tempExtra + returnExtraLen, pTemp, blocksize + 4);
+ returnExtraLen += blocksize + 4;
+ }
+ pTemp += blocksize + 4;
+ }
+
+ /* copy all extra fields from new block */
+ memcpy(tempExtra + returnExtraLen, newExtra, newExtraLen);
+ returnExtraLen += newExtraLen;
+
+ /* copy tempExtra to returnExtra */
+ if ((returnExtra = malloc(returnExtraLen)) == NULL)
+ ZIPERR(ZE_MEM, "extra field copy");
+ memcpy(returnExtra, tempExtra, returnExtraLen);
+ free(tempExtra);
+
+ *newLen = returnExtraLen;
+ return returnExtra;
+}
+
+#ifdef UNICODE_SUPPORT
+
+/* The latest format is
+ 1 byte Version of Unicode Path Extra Field
+ 4 bytes Name Field CRC32 Checksum
+ variable UTF-8 Version Of Name
+ */
+
+local void read_Unicode_Path_entry(pZipListEntry)
+ struct zlist far *pZipListEntry;
+{
+ char *pTemp;
+ char *UPath;
+ char *iname;
+ ush ELen;
+ uch Version;
+ ush ULen;
+ ulg chksum = CRCVAL_INITIAL;
+ ulg iname_chksum;
+
+ /* check if we have a Unicode Path extra field ... */
+ pTemp = get_extra_field( UTF8_PATH_EF_TAG, pZipListEntry->cextra, pZipListEntry->cext );
+ pZipListEntry->uname = NULL;
+ if( pTemp == NULL ) {
+ return;
+ }
+
+ /* ... if so, update corresponding entries in struct zlist */
+
+ pTemp += 2;
+
+ /* length of this extra field */
+ ELen = SH(pTemp);
+ pTemp += 2;
+
+ /* version */
+ Version = (uch) *pTemp;
+ pTemp += 1;
+ if (Version > 1) {
+ zipwarn("Unicode Path Extra Field version > 1 - skipping", pZipListEntry->oname);
+ return;
+ }
+
+ /* iname CRC */
+ iname_chksum = LG(pTemp);
+ pTemp += 4;
+
+ /*
+ * Compute the CRC-32 checksum of iname
+ */
+/*
+ crc_16 = crc16f((uch *)(pZipListEntry->iname), strlen(pZipListEntry->iname));
+ */
+
+ if ((iname = malloc(strlen(pZipListEntry->iname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "write Unicode");
+ }
+ strcpy(iname, pZipListEntry->iname);
+
+ chksum = crc32(chksum, (uch *)(iname), strlen(iname));
+
+ free(iname);
+
+/* chksum = adler16(ADLERVAL_INITIAL,
+ (uch *)(pZipListEntry->iname), strlen(pZipListEntry->iname));
+*/
+
+ /* If the checksums's don't match then likely iname has been modified and
+ * the Unicode Path is no longer valid
+ */
+ if (chksum != iname_chksum) {
+ printf("unicode_mismatch = %d\n", unicode_mismatch);
+ if (unicode_mismatch == 1) {
+ /* warn and continue */
+ zipwarn("Unicode does not match path - ignoring Unicode: ", pZipListEntry->oname);
+ } else if (unicode_mismatch == 2) {
+ /* ignore and continue */
+ } else if (unicode_mismatch == 0) {
+ /* error */
+ sprintf(errbuf, "Unicode does not match path: %s\n", pZipListEntry->oname);
+ strcat(errbuf,
+ " Likely entry name changed but Unicode not updated\n");
+ strcat(errbuf,
+ " Use -UN=i to ignore errors or n for no Unicode paths");
+ zipwarn(errbuf, "");
+ ZIPERR(ZE_FORM, "Unicode path error");
+ }
+ return;
+ }
+
+ ULen = ELen - 5;
+
+ /* UTF-8 Path */
+ if (ULen == 0) {
+ /* standard path is UTF-8 so use that */
+ ULen = pZipListEntry->nam;
+ if ((UPath = malloc(ULen + 1)) == NULL) {
+ return;
+ }
+ strcpy(UPath, pZipListEntry->name);
+ } else {
+ /* use Unicode path */
+ if ((UPath = malloc(ULen + 1)) == NULL) {
+ return;
+ }
+ strncpy(UPath, pTemp, ULen);
+ UPath[ULen] = '\0';
+ }
+ pZipListEntry->uname = UPath;
+ return;
+}
+
+local void read_Unicode_Path_local_entry(pZipListEntry)
+ struct zlist far *pZipListEntry;
+{
+ char *pTemp;
+ char *UPath;
+ char *iname;
+ ush ELen;
+ uch Version;
+ ush ULen;
+ ulg chksum = CRCVAL_INITIAL;
+ ulg iname_chksum;
+
+ /* check if we have a Unicode Path extra field ... */
+ pTemp = get_extra_field( UTF8_PATH_EF_TAG, pZipListEntry->extra, pZipListEntry->ext );
+ pZipListEntry->uname = NULL;
+ if( pTemp == NULL ) {
+ return;
+ }
+
+ /* ... if so, update corresponding entries in struct zlist */
+
+ pTemp += 2;
+
+ /* length of this extra field */
+ ELen = SH(pTemp);
+ pTemp += 2;
+
+ /* version */
+ Version = (uch) *pTemp;
+ pTemp += 1;
+ if (Version > 1) {
+ zipwarn("Unicode Path Extra Field version > 1 - skipping", pZipListEntry->oname);
+ return;
+ }
+
+ /* iname CRC */
+ iname_chksum = LG(pTemp);
+ pTemp += 4;
+
+ /*
+ * Compute 32-bit crc of iname and AND halves to make 16-bit version
+ */
+ /*
+ chksum = adler16(ADLERVAL_INITIAL,
+ (uch *)(pZipListEntry->iname), strlen(pZipListEntry->iname));
+ */
+
+ if ((iname = malloc(strlen(pZipListEntry->iname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "write Unicode");
+ }
+ strcpy(iname, pZipListEntry->iname);
+
+ chksum = crc32(chksum, (uch *)(iname), strlen(iname));
+
+ free(iname);
+
+ /* If the checksums's don't match then likely iname has been modified and
+ * the Unicode Path is no longer valid
+ */
+ if (chksum != iname_chksum) {
+ if (unicode_mismatch == 1) {
+ /* warn and continue */
+ zipwarn("Unicode does not match path - ignoring Unicode: ", pZipListEntry->oname);
+ } else if (unicode_mismatch == 2) {
+ /* ignore and continue */
+ } else if (unicode_mismatch == 0) {
+ /* error */
+ sprintf(errbuf, "Unicode does not match path: %s\n", pZipListEntry->oname);
+ strcat(errbuf,
+ " Likely entry name changed but Unicode not updated\n");
+ strcat(errbuf,
+ " Use -UN=i to ignore errors or n for no Unicode paths");
+ zipwarn(errbuf, "");
+ ZIPERR(ZE_FORM, "Unicode path error");
+ }
+ return;
+ }
+
+ ULen = ELen - 5;
+
+ /* UTF-8 Path */
+ if (ULen == 0) {
+ /* standard path is UTF-8 so use that */
+ ULen = pZipListEntry->nam;
+ if ((UPath = malloc(ULen + 1)) == NULL) {
+ return;
+ }
+ strcpy(UPath, pZipListEntry->name);
+ } else {
+ /* use Unicode path */
+ if ((UPath = malloc(ULen + 1)) == NULL) {
+ return;
+ }
+ strncpy(UPath, pTemp, ULen);
+ UPath[ULen] = '\0';
+ }
+ pZipListEntry->uname = UPath;
+ return;
+}
+
+#endif /* def UNICODE_SUPPORT */
+
+#ifdef ZIP64_SUPPORT /* zip64 support 08/31/2003 R.Nausedat */
+
+/* searches the cextra member of zlist for a zip64 extra field. if it finds one it */
+/* updates the len, siz and off members of zlist with the corresponding values of */
+/* the zip64 extra field, that is if either the len, siz or off member of zlist is */
+/* set to its max value we have to use the corresponding value from the zip64 extra */
+/* field. as of now the dsk member of zlist is not much of interest since we should */
+/* not modify multi volume archives at all. */
+local void adjust_zip_central_entry(pZipListEntry)
+ struct zlist far *pZipListEntry;
+{
+ char *pTemp;
+
+ /* assume not using zip64 fields */
+ zip64_entry = 0;
+
+ /* check if we have a "large file" Zip64 extra field ... */
+ pTemp = get_extra_field( ZIP64_EF_TAG, pZipListEntry->cextra, pZipListEntry->cext );
+ if( pTemp == NULL )
+ return;
+
+ /* using zip64 field */
+ zip64_entry = 1;
+ pTemp += ZIP_EF_HEADER_SIZE;
+
+ /* ... if so, update corresponding entries in struct zlist */
+ if (pZipListEntry->len == ZIP_UWORD32_MAX)
+ {
+ pZipListEntry->len = LLG(pTemp);
+ pTemp += 8;
+ }
+
+ if (pZipListEntry->siz == ZIP_UWORD32_MAX)
+ {
+ pZipListEntry->siz = LLG(pTemp);
+ pTemp += 8;
+ }
+
+ if (pZipListEntry->off == ZIP_UWORD32_MAX)
+ {
+ pZipListEntry->off = LLG(pTemp);
+ pTemp += 8;
+ }
+
+ if (pZipListEntry->dsk == ZIP_UWORD16_MAX)
+ {
+ pZipListEntry->dsk = LG(pTemp);
+ }
+
+}
+
+
+/* adjust_zip_local_entry
+ *
+ * Return 1 if there is a Zip64 extra field and 0 if not
+ */
+local int adjust_zip_local_entry(pZipListEntry)
+ struct zlist far *pZipListEntry;
+{
+ char *pTemp;
+
+ /* assume not using zip64 fields */
+ zip64_entry = 0;
+
+ /* check if we have a "large file" Zip64 extra field ... */
+ pTemp = get_extra_field(ZIP64_EF_TAG, pZipListEntry->extra, pZipListEntry->ext );
+ if( pTemp == NULL )
+ return zip64_entry;
+
+ /* using zip64 field */
+ zip64_entry = 1;
+ pTemp += ZIP_EF_HEADER_SIZE;
+
+ /* ... if so, update corresponding entries in struct zlist */
+ if (pZipListEntry->len == ZIP_UWORD32_MAX)
+ {
+ pZipListEntry->len = LLG(pTemp);
+ pTemp += 8;
+ }
+
+ if (pZipListEntry->siz == ZIP_UWORD32_MAX)
+ {
+ pZipListEntry->siz = LLG(pTemp);
+ pTemp += 8;
+ }
+ return zip64_entry;
+}
+
+/* adds a zip64 extra field to the data the cextra member of zlist points to. If
+ * there is already a zip64 extra field present delete it first.
+ */
+local int add_central_zip64_extra_field(pZipListEntry)
+ struct zlist far *pZipListEntry;
+{
+ char *pExtraFieldPtr;
+ char *pTemp;
+ ush usTemp;
+ ush efsize = 0;
+ ush esize;
+ ush oldefsize;
+ extent len;
+ int used_zip64 = 0;
+
+ /* get length of ef based on which fields exceed limits */
+ /* AppNote says:
+ * The order of the fields in the ZIP64 extended
+ * information record is fixed, but the fields will
+ * only appear if the corresponding Local or Central
+ * directory record field is set to 0xFFFF or 0xFFFFFFFF.
+ */
+ efsize = ZIP_EF_HEADER_SIZE; /* type + size */
+ if (pZipListEntry->len > ZIP_UWORD32_MAX || force_zip64 == 1) {
+ /* compressed size */
+ efsize += 8;
+ used_zip64 = 1;
+ }
+ if (pZipListEntry->siz > ZIP_UWORD32_MAX) {
+ /* uncompressed size */
+ efsize += 8;
+ used_zip64 = 1;
+ }
+ if (pZipListEntry->off > ZIP_UWORD32_MAX) {
+ /* offset */
+ efsize += 8;
+ used_zip64 = 1;
+ }
+ if (pZipListEntry->dsk > ZIP_UWORD16_MAX) {
+ /* disk number */
+ efsize += 4;
+ used_zip64 = 1;
+ }
+
+ if (used_zip64 && force_zip64 == 0) {
+ zipwarn("Large entry support disabled using -fz- but needed", "");
+ return ZE_BIG;
+ }
+
+ /* malloc zip64 extra field? */
+ if( pZipListEntry->cextra == NULL )
+ {
+ if (efsize == ZIP_EF_HEADER_SIZE) {
+ return ZE_OK;
+ }
+ if ((pExtraFieldPtr = pZipListEntry->cextra = (char *) malloc(efsize)) == NULL) {
+ return ZE_MEM;
+ }
+ pZipListEntry->cext = efsize;
+ }
+ else
+ {
+ /* check if we have a "large file" extra field ... */
+ pExtraFieldPtr = get_extra_field(ZIP64_EF_TAG, pZipListEntry->cextra, pZipListEntry->cext);
+ if( pExtraFieldPtr == NULL )
+ {
+ /* ... we don't, so re-malloc enough memory for the old extra data plus
+ * the size of the zip64 extra field
+ */
+ if ((pExtraFieldPtr = (char *) malloc(efsize + pZipListEntry->cext)) == NULL) {
+ return ZE_MEM;
+ }
+ /* move the old extra field */
+ memmove(pExtraFieldPtr, pZipListEntry->cextra, pZipListEntry->cext);
+ free(pZipListEntry->cextra);
+ pZipListEntry->cextra = pExtraFieldPtr;
+ pExtraFieldPtr += pZipListEntry->cext;
+ pZipListEntry->cext += efsize;
+ }
+ else
+ {
+ /* ... we have. sort out the existing zip64 extra field and remove it from
+ * pZipListEntry->cextra, re-malloc enough memory for the old extra data
+ * left plus the size of the zip64 extra field
+ */
+ usTemp = SH(pExtraFieldPtr + 2);
+ /* if pZipListEntry->cextra == pExtraFieldPtr and pZipListEntry->cext == usTemp + efsize
+ * we should have only one extra field, and this is a zip64 extra field. as some
+ * zip tools seem to require fixed zip64 extra fields we have to check if
+ * usTemp + ZIP_EF_HEADER_SIZE is equal to ZIP64_LARGE_FILE_HEAD_SIZE. if it
+ * isn't, we free the old extra field and allocate memory for a new one
+ */
+ if( pZipListEntry->cext == (extent)(usTemp + ZIP_EF_HEADER_SIZE) )
+ {
+ /* just Zip64 extra field in extra field */
+ if( pZipListEntry->cext != efsize )
+ {
+ /* wrong size */
+ if ((pExtraFieldPtr = (char *) malloc(efsize)) == NULL) {
+ return ZE_MEM;
+ }
+ free(pZipListEntry->cextra);
+ pZipListEntry->cextra = pExtraFieldPtr;
+ pZipListEntry->cext = efsize;
+ }
+ }
+ else
+ {
+ /* get the old Zip64 extra field out and add new */
+ oldefsize = usTemp + ZIP_EF_HEADER_SIZE;
+ if ((pTemp = (char *) malloc(pZipListEntry->cext - oldefsize + efsize)) == NULL) {
+ return ZE_MEM;
+ }
+ len = (extent)(pExtraFieldPtr - pZipListEntry->cextra);
+ memcpy(pTemp, pZipListEntry->cextra, len);
+ memcpy(pTemp + len, pExtraFieldPtr + oldefsize,
+ pZipListEntry->cext - oldefsize - len);
+ pZipListEntry->cext -= oldefsize;
+ pExtraFieldPtr = pTemp + pZipListEntry->cext;
+ pZipListEntry->cext += efsize;
+ free(pZipListEntry->cextra);
+ pZipListEntry->cextra = pTemp;
+ }
+ }
+ }
+
+ /* set zip64 extra field members */
+ write_ushort_to_mem(ZIP64_EF_TAG, pExtraFieldPtr);
+ write_ushort_to_mem((ush) (efsize - ZIP_EF_HEADER_SIZE), pExtraFieldPtr + 2);
+ esize = ZIP_EF_HEADER_SIZE;
+ if (pZipListEntry->len > ZIP_UWORD32_MAX || force_zip64 == 1) {
+ write_int64_to_mem(pZipListEntry->len, pExtraFieldPtr + esize);
+ esize += 8;
+ }
+ if (pZipListEntry->siz > ZIP_UWORD32_MAX) {
+ write_int64_to_mem(pZipListEntry->siz, pExtraFieldPtr + esize);
+ esize += 8;
+ }
+ if (pZipListEntry->off > ZIP_UWORD32_MAX) {
+ write_int64_to_mem(pZipListEntry->off, pExtraFieldPtr + esize);
+ esize += 8;
+ }
+ if (pZipListEntry->dsk > ZIP_UWORD16_MAX) {
+ write_ulong_to_mem(pZipListEntry->dsk, pExtraFieldPtr + esize);
+ }
+
+ /* un' wech */
+ return ZE_OK;
+}
+
+#if 0
+/* Remove extra field in local extra field
+ * Return 1 if found, else 0
+ * 12/28/05
+ */
+local int remove_local_extra_field(pZEntry, tag)
+ struct zlist far *pZEntry;
+ ulg tag;
+{
+ char *pExtra;
+ char *pOldExtra;
+ char *pOldTemp;
+ char *pTemp;
+ ush newEFSize;
+ ush usTemp;
+ ush blocksize;
+
+ /* check if we have the extra field ... */
+ pOldExtra = get_extra_field( (ush)tag, pZEntry->extra, pZEntry->ext );
+ if (pOldExtra)
+ {
+ /* We have. Get rid of it. */
+ blocksize = SH( pOldExtra + 2 );
+ newEFSize = pZEntry->ext - blocksize;
+ pExtra = (char *) malloc( newEFSize );
+ if( pExtra == NULL )
+ ziperr(ZE_MEM, "Remove Local Extra Field");
+ /* move all before EF */
+ usTemp = (extent) (pOldExtra - pZEntry->extra);
+ pTemp = pExtra;
+ memcpy( pTemp, pZEntry->extra, usTemp );
+ /* move all after old Zip64 EF */
+ pTemp = pExtra + usTemp;
+ pOldTemp = pOldExtra + blocksize;
+ usTemp = pZEntry->ext - usTemp - blocksize;
+ memcpy( pTemp, pOldTemp, usTemp);
+ /* replace extra fields */
+ pZEntry->ext = newEFSize;
+ free(pZEntry->extra);
+ pZEntry->extra = pExtra;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* Remove extra field in central extra field
+ * Return 1 if found, else 0
+ * 12/28/05
+ */
+local int remove_central_extra_field(pZEntry, tag)
+ struct zlist far *pZEntry;
+ ulg tag;
+{
+ char *pExtra;
+ char *pOldExtra;
+ char *pOldTemp;
+ char *pTemp;
+ ush newEFSize;
+ ush usTemp;
+ ush blocksize;
+
+ /* check if we have the extra field ... */
+ pOldExtra = get_extra_field( (ush)tag, pZEntry->cextra, pZEntry->cext );
+ if (pOldExtra)
+ {
+ /* We have. Get rid of it. */
+ blocksize = SH( pOldExtra + 2 );
+ newEFSize = pZEntry->cext - blocksize;
+ pExtra = (char *) malloc( newEFSize );
+ if( pExtra == NULL )
+ ziperr(ZE_MEM, "Remove Local Extra Field");
+ /* move all before EF */
+ usTemp = (extent) (pOldExtra - pZEntry->cextra);
+ pTemp = pExtra;
+ memcpy( pTemp, pZEntry->cextra, usTemp );
+ /* move all after old Zip64 EF */
+ pTemp = pExtra + usTemp;
+ pOldTemp = pOldExtra + blocksize;
+ usTemp = pZEntry->cext - usTemp - blocksize;
+ memcpy( pTemp, pOldTemp, usTemp);
+ /* replace extra fields */
+ pZEntry->cext = newEFSize;
+ free(pZEntry->cextra);
+ pZEntry->cextra = pExtra;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+#endif
+
+/* Add Zip64 extra field to local header
+ * 10/5/03 EG
+ */
+local int add_local_zip64_extra_field(pZEntry)
+ struct zlist far *pZEntry;
+{
+ char *pZ64Extra;
+ char *pOldZ64Extra;
+ char *pOldTemp;
+ char *pTemp;
+ ush newEFSize;
+ ush usTemp;
+ ush blocksize;
+ ush Z64LocalLen = ZIP_EF_HEADER_SIZE + /* tag + EF Data Len */
+ 8 + /* original uncompressed length of file */
+ 8; /* compressed size of file */
+
+ /* malloc zip64 extra field? */
+ /* after the below pZ64Extra should point to start of Zip64 extra field */
+ if (pZEntry->ext == 0 || pZEntry->extra == NULL)
+ {
+ /* get new extra field */
+ pZ64Extra = pZEntry->extra = (char *) malloc(Z64LocalLen);
+ if (pZEntry->extra == NULL) {
+ ziperr( ZE_MEM, "Zip64 local extra field" );
+ }
+ pZEntry->ext = Z64LocalLen;
+ }
+ else
+ {
+ /* check if we have a Zip64 extra field ... */
+ pOldZ64Extra = get_extra_field( ZIP64_EF_TAG, pZEntry->extra, pZEntry->ext );
+ if (pOldZ64Extra == NULL)
+ {
+ /* ... we don't, so re-malloc enough memory for the old extra data plus */
+ /* the size of the zip64 extra field */
+ pZ64Extra = (char *) malloc( Z64LocalLen + pZEntry->ext );
+ if (pZ64Extra == NULL)
+ ziperr( ZE_MEM, "Zip64 Extra Field" );
+ /* move old extra field and update pointer and length */
+ memmove( pZ64Extra, pZEntry->extra, pZEntry->ext);
+ free( pZEntry->extra );
+ pZEntry->extra = pZ64Extra;
+ pZ64Extra += pZEntry->ext;
+ pZEntry->ext += Z64LocalLen;
+ }
+ else
+ {
+ /* ... we have. Sort out the existing zip64 extra field and remove it
+ * from pZEntry->extra, re-malloc enough memory for the old extra data
+ * left plus the size of the zip64 extra field */
+ blocksize = SH( pOldZ64Extra + 2 );
+ /* If the right length then go with it, else get rid of it and add a new extra field
+ * to existing block. */
+ if (blocksize == Z64LocalLen - ZIP_EF_HEADER_SIZE)
+ {
+ /* looks good */
+ pZ64Extra = pOldZ64Extra;
+ }
+ else
+ {
+ newEFSize = pZEntry->ext - (blocksize + ZIP_EF_HEADER_SIZE) + Z64LocalLen;
+ pZ64Extra = (char *) malloc( newEFSize );
+ if( pZ64Extra == NULL )
+ ziperr(ZE_MEM, "Zip64 Extra Field");
+ /* move all before Zip64 EF */
+ usTemp = (extent) (pOldZ64Extra - pZEntry->extra);
+ pTemp = pZ64Extra;
+ memcpy( pTemp, pZEntry->extra, usTemp );
+ /* move all after old Zip64 EF */
+ pTemp = pZ64Extra + usTemp;
+ pOldTemp = pOldZ64Extra + ZIP_EF_HEADER_SIZE + blocksize;
+ usTemp = pZEntry->ext - usTemp - blocksize;
+ memcpy( pTemp, pOldTemp, usTemp);
+ /* replace extra fields */
+ pZEntry->ext = newEFSize;
+ free(pZEntry->extra);
+ pZEntry->extra = pZ64Extra;
+ pZ64Extra = pTemp + usTemp;
+ }
+ }
+ }
+ /* set/update zip64 extra field members */
+ write_ushort_to_mem(ZIP64_EF_TAG, pZ64Extra);
+ write_ushort_to_mem((ush) (Z64LocalLen - ZIP_EF_HEADER_SIZE), pZ64Extra + 2);
+ write_int64_to_mem(pZEntry->len, pZ64Extra + 2 + 2);
+ write_int64_to_mem(pZEntry->siz, pZ64Extra + 2 + 2 + 8);
+
+ return ZE_OK;
+}
+
+# endif /* ZIP64_SUPPORT */
+
+#ifdef UNICODE_SUPPORT
+/* Add UTF-8 path extra field
+ * 10/11/05
+ */
+local int add_Unicode_Path_local_extra_field(pZEntry)
+ struct zlist far *pZEntry;
+{
+ char *pUExtra;
+ char *pOldUExtra;
+ char *pOldTemp;
+ char *pTemp;
+#ifdef WIN32_OEM
+ char *inameLocal;
+#endif
+ ush newEFSize;
+ ush usTemp;
+ ush ULen = strlen(pZEntry->uname);
+ ush blocksize;
+ ulg chksum = CRCVAL_INITIAL;
+ ush ULocalLen = ZIP_EF_HEADER_SIZE + /* tag + EF Data Len */
+ 1 + /* version */
+ 4 + /* iname chksum */
+ ULen; /* UTF-8 path */
+
+ /* malloc Unicode Path extra field? */
+ /* after the below pUExtra should point to start of Unicode Path extra field */
+ if (pZEntry->ext == 0 || pZEntry->extra == NULL)
+ {
+ /* get new extra field */
+ pUExtra = pZEntry->extra = (char *) malloc(ULocalLen);
+ if (pZEntry->extra == NULL) {
+ ziperr( ZE_MEM, "UTF-8 Path local extra field" );
+ }
+ pZEntry->ext = ULocalLen;
+ }
+ else
+ {
+ /* check if we have a Unicode Path extra field ... */
+ pOldUExtra = get_extra_field( UTF8_PATH_EF_TAG, pZEntry->extra, pZEntry->ext );
+ if (pOldUExtra == NULL)
+ {
+ /* ... we don't, so re-malloc enough memory for the old extra data plus */
+ /* the size of the UTF-8 Path extra field */
+ pUExtra = (char *) malloc( ULocalLen + pZEntry->ext );
+ if (pUExtra == NULL)
+ ziperr( ZE_MEM, "UTF-8 Path Extra Field" );
+ /* move old extra field and update pointer and length */
+ memmove( pUExtra, pZEntry->extra, pZEntry->ext);
+ free( pZEntry->extra );
+ pZEntry->extra = pUExtra;
+ pUExtra += pZEntry->ext;
+ pZEntry->ext += ULocalLen;
+ }
+ else
+ {
+ /* ... we have. Sort out the existing UTF-8 Path extra field and remove it
+ * from pZEntry->extra, re-malloc enough memory for the old extra data
+ * left plus the size of the UTF-8 Path extra field */
+ blocksize = SH( pOldUExtra + 2 );
+ /* If the right length then go with it, else get rid of it and add a new extra field
+ * to existing block. */
+ if (blocksize == ULocalLen - ZIP_EF_HEADER_SIZE)
+ {
+ /* looks good */
+ pUExtra = pOldUExtra;
+ }
+ else
+ {
+ newEFSize = pZEntry->ext - (blocksize + ZIP_EF_HEADER_SIZE) + ULocalLen;
+ pUExtra = (char *) malloc( newEFSize );
+ if( pUExtra == NULL )
+ ziperr(ZE_MEM, "UTF-8 Path Extra Field");
+ /* move all before UTF-8 Path EF */
+ usTemp = (extent) (pOldUExtra - pZEntry->extra);
+ pTemp = pUExtra;
+ memcpy( pTemp, pZEntry->extra, usTemp );
+ /* move all after old UTF-8 Path EF */
+ pTemp = pUExtra + usTemp;
+ pOldTemp = pOldUExtra + ZIP_EF_HEADER_SIZE + blocksize;
+ usTemp = pZEntry->ext - usTemp - blocksize;
+ memcpy( pTemp, pOldTemp, usTemp);
+ /* replace extra fields */
+ pZEntry->ext = newEFSize;
+ free(pZEntry->extra);
+ pZEntry->extra = pUExtra;
+ pUExtra = pTemp + usTemp;
+ }
+ }
+ }
+
+ /*
+ * Compute the Adler-16 checksum of iname
+ */
+/*
+ chksum = adler16(ADLERVAL_INITIAL,
+ (uch *)(pZEntry->iname), strlen(pZEntry->iname));
+*/
+
+#ifdef WIN32_OEM
+ if ((inameLocal = malloc(strlen(pZEntry->iname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "write Unicode");
+ }
+ /* if oem translation done convert back for checksum */
+ if ((pZEntry->vem & 0xff00) == 0) {
+ /* get original */
+ INTERN_TO_OEM(pZEntry->iname, inameLocal);
+ } else {
+ strcpy(inameLocal, pZEntry->iname);
+ }
+#else
+# define inameLocal (pZEntry->iname)
+#endif
+
+ chksum = crc32(chksum, (uch *)(inameLocal), strlen(inameLocal));
+
+#ifdef WIN32_OEM
+ free(inameLocal);
+#else
+# undef inameLocal
+#endif
+
+ /* set/update UTF-8 Path extra field members */
+ /* tag header */
+ write_ushort_to_mem(UTF8_PATH_EF_TAG, pUExtra);
+ /* data size */
+ write_ushort_to_mem((ush) (ULocalLen - ZIP_EF_HEADER_SIZE), pUExtra + 2);
+ /* version */
+ *(pUExtra + 2 + 2) = 1;
+ /* iname chksum */
+ write_ulong_to_mem(chksum, pUExtra + 2 + 2 + 1);
+ /* UTF-8 path */
+ write_string_to_mem(pZEntry->uname, pUExtra + 2 + 2 + 1 + 4);
+
+ return ZE_OK;
+}
+
+local int add_Unicode_Path_cen_extra_field(pZEntry)
+ struct zlist far *pZEntry;
+{
+ char *pUExtra;
+ char *pOldUExtra;
+ char *pOldTemp;
+ char *pTemp;
+#ifdef WIN32_OEM
+ char *inameLocal;
+#endif
+ ush newEFSize;
+ ush usTemp;
+ ush ULen = strlen(pZEntry->uname);
+ ush blocksize;
+ ulg chksum = CRCVAL_INITIAL;
+ ush UCenLen = ZIP_EF_HEADER_SIZE + /* tag + EF Data Len */
+ 1 + /* version */
+ 4 + /* checksum */
+ ULen; /* UTF-8 path */
+
+ /* malloc Unicode Path extra field? */
+ /* after the below pUExtra should point to start of Unicode Path extra field */
+ if (pZEntry->cext == 0 || pZEntry->cextra == NULL)
+ {
+ /* get new extra field */
+ pUExtra = pZEntry->cextra = (char *) malloc(UCenLen);
+ if (pZEntry->cextra == NULL) {
+ ziperr( ZE_MEM, "UTF-8 Path cen extra field" );
+ }
+ pZEntry->cext = UCenLen;
+ }
+ else
+ {
+ /* check if we have a Unicode Path extra field ... */
+ pOldUExtra = get_extra_field( UTF8_PATH_EF_TAG, pZEntry->cextra, pZEntry->cext );
+ if (pOldUExtra == NULL)
+ {
+ /* ... we don't, so re-malloc enough memory for the old extra data plus */
+ /* the size of the UTF-8 Path extra field */
+ pUExtra = (char *) malloc( UCenLen + pZEntry->cext );
+ if (pUExtra == NULL)
+ ziperr( ZE_MEM, "UTF-8 Path Extra Field" );
+ /* move old extra field and update pointer and length */
+ memmove( pUExtra, pZEntry->cextra, pZEntry->cext);
+ free( pZEntry->cextra );
+ pZEntry->cextra = pUExtra;
+ pUExtra += pZEntry->cext;
+ pZEntry->cext += UCenLen;
+ }
+ else
+ {
+ /* ... we have. Sort out the existing UTF-8 Path extra field and remove it
+ * from pZEntry->extra, re-malloc enough memory for the old extra data
+ * left plus the size of the UTF-8 Path extra field */
+ blocksize = SH( pOldUExtra + 2 );
+ /* If the right length then go with it, else get rid of it and add a new extra field
+ * to existing block. */
+ if (blocksize == UCenLen - ZIP_EF_HEADER_SIZE)
+ {
+ /* looks good */
+ pUExtra = pOldUExtra;
+ }
+ else
+ {
+ newEFSize = pZEntry->cext - (blocksize + ZIP_EF_HEADER_SIZE) + UCenLen;
+ pUExtra = (char *) malloc( newEFSize );
+ if( pUExtra == NULL )
+ ziperr(ZE_MEM, "UTF-8 Path Extra Field");
+ /* move all before UTF-8 Path EF */
+ usTemp = (extent) (pOldUExtra - pZEntry->cextra);
+ pTemp = pUExtra;
+ memcpy( pTemp, pZEntry->cextra, usTemp );
+ /* move all after old UTF-8 Path EF */
+ pTemp = pUExtra + usTemp;
+ pOldTemp = pOldUExtra + ZIP_EF_HEADER_SIZE + blocksize;
+ usTemp = pZEntry->cext - usTemp - blocksize;
+ memcpy( pTemp, pOldTemp, usTemp);
+ /* replace extra fields */
+ pZEntry->cext = newEFSize;
+ free(pZEntry->cextra);
+ pZEntry->cextra = pUExtra;
+ pUExtra = pTemp + usTemp;
+ }
+ }
+ }
+
+ /*
+ * Compute the CRC-32 checksum of iname
+ */
+#ifdef WIN32_OEM
+ if ((inameLocal = malloc(strlen(pZEntry->iname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "write Unicode");
+ }
+ /* if oem translation done convert back for checksum */
+ if ((pZEntry->vem & 0xff00) == 0) {
+ /* get original */
+ INTERN_TO_OEM(pZEntry->iname, inameLocal);
+ } else {
+ strcpy(inameLocal, pZEntry->iname);
+ }
+#else
+# define inameLocal (pZEntry->iname)
+#endif
+
+ chksum = crc32(chksum, (uch *)(inameLocal), strlen(inameLocal));
+
+#ifdef WIN32_OEM
+ free(inameLocal);
+#else
+# undef inameLocal
+#endif
+
+ /*
+ * Compute the Adler-16 checksum of iname
+ */
+/*
+ chksum = adler16(ADLERVAL_INITIAL,
+ (uch *)(pZEntry->iname), strlen(pZEntry->iname));
+*/
+
+ /* set/update UTF-8 Path extra field members */
+ /* tag header */
+ write_ushort_to_mem(UTF8_PATH_EF_TAG, pUExtra);
+ /* data size */
+ write_ushort_to_mem((ush) (UCenLen - ZIP_EF_HEADER_SIZE), pUExtra + 2);
+ /* version */
+ *(pUExtra + 2 + 2) = 1;
+ /* iname checksum */
+ write_ulong_to_mem(chksum, pUExtra + 2 + 2 + 1);
+ /* UTF-8 path */
+ write_string_to_mem(pZEntry->uname, pUExtra + 2 + 2 + 1 + 4);
+
+ return ZE_OK;
+}
+#endif /* def UNICODE_SUPPORT */
+
+
+zoff_t ffile_size OF((FILE *));
+
+
+/* 2004-12-06 SMS.
+ * ffile_size() returns reliable file size or EOF.
+ * May be used to detect large files in a small-file program.
+ */
+zoff_t ffile_size( file)
+FILE *file;
+{
+ int sts;
+ size_t siz;
+ zoff_t ofs;
+ char waste[ 4];
+
+ /* Seek to actual EOF. */
+ sts = zfseeko( file, 0, SEEK_END);
+ if (sts != 0)
+ {
+ /* fseeko() failed. (Unlikely.) */
+ ofs = EOF;
+ }
+ else
+ {
+ /* Get apparent offset at EOF. */
+ ofs = zftello( file);
+ if (ofs < 0)
+ {
+ /* Offset negative (overflow). File too big. */
+ ofs = EOF;
+ }
+ else
+ {
+ /* Seek to apparent EOF offset.
+ Won't be at actual EOF if offset was truncated.
+ */
+ sts = zfseeko( file, ofs, SEEK_SET);
+ if (sts != 0)
+ {
+ /* fseeko() failed. (Unlikely.) */
+ ofs = EOF;
+ }
+ else
+ {
+ /* Read a byte at apparent EOF. Should set EOF flag. */
+ siz = fread( waste, 1, 1, file);
+ if (feof( file) == 0)
+ {
+ /* Not at EOF, but should be. File too big. */
+ ofs = EOF;
+ }
+ }
+ }
+ }
+ /* Seek to BOF.
+ *
+ * 2007-05-23 SMS.
+ * Note that a problem in a prehistoric VAX C run-time library
+ * requires that rewind() be used instead of fseek(), or else
+ * the EOF flag is not cleared properly.
+ */
+ /* As WIN32 has this same problem (EOF not being cleared) when
+ * NO_ZIP64_SUPPORT is set but LARGE_FILE_SUPPORT is set on a
+ * small file, seems no reason not to always use rewind().
+ * 8/5/07 EG
+ */
+#if 0
+#ifdef VAXC
+ sts = rewind( file);
+#else /* def VAXC */
+ sts = zfseeko( file, 0, SEEK_SET);
+#endif /* def VAXC [else] */
+#endif
+ rewind(file);
+
+ return ofs;
+}
+
+
+#ifndef UTIL
+
+local void zipoddities(z)
+struct zlist far *z;
+{
+ if ((z->vem >> 8) >= NUM_HOSTS)
+ {
+ sprintf(errbuf, "made by version %d.%d on system type %d: ",
+ (ush)(z->vem & 0xff) / (ush)10, (ush)(z->vem & 0xff) % (ush)10,
+ z->vem >> 8);
+ zipwarn(errbuf, z->oname);
+ }
+ if (z->ver != 10 && z->ver != 11 && z->ver != 20)
+ {
+ sprintf(errbuf, "needs unzip %d.%d on system type %d: ",
+ (ush)(z->ver & 0xff) / (ush)10,
+ (ush)(z->ver & 0xff) % (ush)10, z->ver >> 8);
+ zipwarn(errbuf, z->oname);
+ }
+
+ if ((fix == 2) && (z->flg != z->lflg))
+ /* The comparision between central and local version of the
+ "general purpose bit flag" cannot be used from scanzipf_regnew(),
+ because in the "regular" zipfile processing, the local header reads
+ have been postponed until the actual entry processing takes place.
+ They have not yet been read when "zipoddities()" is called.
+ This change was neccessary to support multivolume archives.
+ */
+ {
+ sprintf(errbuf, "local flags = 0x%04x, central = 0x%04x: ",
+ z->lflg, z->flg);
+ zipwarn(errbuf, z->oname);
+ }
+ else if (z->flg & ~0xf && (z->flg & ~0xf0) != UTF8_BIT)
+ /* Only bit in high byte we support is the new UTF-8 bit */
+ {
+ sprintf(errbuf, "undefined bits used in flags = 0x%04x: ", z->flg);
+ zipwarn(errbuf, z->oname);
+ }
+ if (z->how > LAST_KNOWN_COMPMETHOD) {
+ sprintf(errbuf, "unknown compression method %u: ", z->how);
+ zipwarn(errbuf, z->oname);
+ }
+ if (z->dsk)
+ {
+ sprintf(errbuf, "starts on disk %lu: ", z->dsk);
+ zipwarn(errbuf, z->oname);
+ }
+ if (z->att!=ASCII && z->att!=BINARY && z->att!=__EBCDIC)
+ {
+ sprintf(errbuf, "unknown internal attributes = 0x%04x: ", z->att);
+ zipwarn(errbuf, z->oname);
+ }
+# if 0
+/* This test is ridiculous, it produces an error message for almost every */
+/* platform of origin other than MS-DOS, Unix, VMS, and Acorn! Perhaps */
+/* we could test "if (z->dosflag && z->atx & ~0xffL)", but what for? */
+ if (((n = z->vem >> 8) != 3) && n != 2 && n != 13 && z->atx & ~0xffL)
+ {
+ sprintf(errbuf, "unknown external attributes = 0x%08lx: ", z->atx);
+ zipwarn(errbuf, z->oname);
+ }
+# endif
+
+ /* This test is just annoying, as Zip itself does not write the same
+ extra fields to both the local and central headers. It's much more
+ complicated than this test implies. 3/17/05 */
+#if 0
+ if (z->ext || z->cext)
+ {
+# if 0
+ if (z->ext && z->cext && z->extra != z->cextra)
+ {
+ sprintf(errbuf,
+ "local extra (%ld bytes) != central extra (%ld bytes): ",
+ (ulg)z->ext, (ulg)z->cext);
+ if (noisy) fprintf(mesg, "\tzip info: %s%s\n", errbuf, z->oname);
+ }
+# if (!defined(RISCOS) && !defined(CMS_MVS))
+ /* in noisy mode, extra field sizes are always reported */
+ else if (noisy)
+# else /* RISCOS || CMS_MVS */
+/* avoid warnings for zipfiles created on the same type of OS system! */
+/* or, was this warning really intended (eg. OS/2)? */
+ /* Only give info if extra bytes were added by another system */
+ else if (noisy && ((z->vem >> 8) != (OS_CODE >> 8)))
+# endif /* ?(RISCOS || CMS_MVS) */
+# endif /* 0 */
+ {
+ fprintf(mesg, "zip info: %s has %ld bytes of %sextra data\n",
+ z->oname, z->ext ? (ulg)z->ext : (ulg)z->cext,
+ z->ext ? (z->cext ? "" : "local ") : "central ");
+ }
+ }
+#endif
+}
+
+
+#if 0 /* scanzipf_fix() no longer used */
+/*
+ * scanzipf_fix is called with zip -F or zip -FF
+ * read the file from front to back and pick up the pieces
+ * NOTE: there are still checks missing to see if the header
+ * that was found is *VALID*
+ *
+ * Still much work to do so can handle more cases. 1/18/04 EG
+ */
+local int scanzipf_fix(f)
+ FILE *f; /* zip file */
+/*
+ The name of the zip file is pointed to by the global "zipfile". The globals
+ zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+ Return an error code in the ZE_ class.
+*/
+{
+ ulg a = 0L; /* attributes returned by filetime() */
+ char b[CENHEAD]; /* buffer for central headers */
+ ush flg; /* general purpose bit flag */
+ int m; /* mismatch flag */
+ extent n; /* length of name */
+ uzoff_t p; /* current file offset */
+ uzoff_t s; /* size of data, start of central */
+ struct zlist far * far *x; /* pointer last entry's link */
+ struct zlist far *z; /* current zip entry structure */
+
+#ifndef ZIP64_SUPPORT
+
+/* 2004-12-06 SMS.
+ * Check for too-big file before doing any serious work.
+ */
+ if (ffile_size( f) == EOF)
+ return ZE_ZIP64;
+
+#endif /* ndef ZIP64_SUPPORT */
+
+
+ /* Get any file attribute valid for this OS, to set in the central
+ * directory when fixing the archive:
+ */
+# ifndef UTIL
+ filetime(zipfile, &a, (zoff_t*)&s, NULL);
+# endif
+ x = &zfiles; /* first link */
+ p = 0; /* starting file offset */
+# ifdef HANDLE_AMIGA_SFX
+ amiga_sfx_offset = 0L;
+# endif
+
+ /* Find start of zip structures */
+ for (;;) {
+ /* look for signature */
+ while ((m = getc(f)) != EOF && m != 0x50) /* 0x50 == 'P' */
+ {
+# ifdef HANDLE_AMIGA_SFX
+ if (p == 0 && m == 0)
+ amiga_sfx_offset = 1L;
+ else if (amiga_sfx_offset) {
+ if ((p == 1 && m != 0) || (p == 2 && m != 3)
+ || (p == 3 && (uch) m != 0xF3))
+ amiga_sfx_offset = 0L;
+ }
+# endif /* HANDLE_AMIGA_SFX */
+ p++;
+ }
+ /* found a P */
+ b[0] = (char) m;
+ /* local - 11/2/03 EG */
+ if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG)
+ break;
+ /* why search for ENDSIG if doing only local - 11/2/03 EG
+ if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == ENDSIG)
+ break;
+ */
+ /* back up */
+ if (zfseeko(f, -3L, SEEK_CUR))
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ /* move 1 byte forward */
+ p++;
+ }
+ zipbeg = p;
+# ifdef HANDLE_AMIGA_SFX
+ if (amiga_sfx_offset && zipbeg >= 12 && (zipbeg & 3) == 0
+ && fseek(f, -12L, SEEK_CUR) == 0 && fread(b, 12, 1, f) == 1
+ && LG(b + 4) == 0xF1030000 /* 1009 in Motorola byte order */)
+ amiga_sfx_offset = zipbeg - 4;
+ else
+ amiga_sfx_offset = 0L;
+# endif /* HANDLE_AMIGA_SFX */
+
+ /* Read local headers */
+ while (LG(b) == LOCSIG)
+ {
+ if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL ||
+ zcount + 1 < zcount)
+ return ZE_MEM;
+ if (fread(b, LOCHEAD, 1, f) != 1) {
+ farfree((zvoid far *)z);
+ break;
+ }
+
+ z->ver = SH(LOCVER + b);
+ z->vem = (ush)(dosify ? 20 : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
+ z->dosflag = dosify;
+ flg = z->flg = z->lflg = SH(LOCFLG + b);
+ z->how = SH(LOCHOW + b);
+ z->tim = LG(LOCTIM + b); /* time and date into one long */
+ z->crc = LG(LOCCRC + b);
+ z->siz = LG(LOCSIZ + b);
+ z->len = LG(LOCLEN + b);
+ n = z->nam = SH(LOCNAM + b);
+ z->cext = z->ext = SH(LOCEXT + b);
+
+ z->com = 0;
+ z->dsk = 0;
+ z->att = 0;
+ z->atx = dosify ? a & 0xff : a; /* Attributes from filetime() */
+ z->mark = 0;
+ z->trash = 0;
+
+ /* attention: this one breaks the VC optimizer (Release Build) */
+ /* may be fixed - 11/1/03 EG */
+ s = fix > 1 ? 0L : z->siz; /* discard compressed size with -FF */
+
+ /* Initialize all fields pointing to malloced data to NULL */
+ z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+ z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+ z->uname = z->zuname = z->ouname = NULL;
+#endif
+
+ /* Link into list */
+ *x = z;
+ z->nxt = NULL;
+ x = &z->nxt;
+
+ /* Read file name and extra field and skip data */
+ if (n == 0)
+ {
+ sprintf(errbuf, "%lu", (ulg)zcount + 1);
+ zipwarn("zero-length name for entry #", errbuf);
+# ifndef DEBUG
+ return ZE_FORM;
+# endif
+ }
+ if ((z->iname = malloc(n+1)) == NULL ||
+ (z->ext && (z->extra = malloc(z->ext)) == NULL))
+ return ZE_MEM;
+ if (fread(z->iname, n, 1, f) != 1 ||
+ (z->ext && fread(z->extra, z->ext, 1, f) != 1))
+ return ferror(f) ? ZE_READ : ZE_EOF;
+
+# ifdef ZIP64_SUPPORT
+ /* adjust/update siz,len and off (to come: dsk) entries */
+ /* PKZIP does not care of the version set in a CDH: if */
+ /* there is a zip64 extra field assigned to a CDH PKZIP */
+ /* uses it, we should do so, too. */
+ zip64_entry = adjust_zip_local_entry(z);
+ /* z->siz may be updated */
+ s = fix > 1 ? 0L : z->siz; /* discard compressed size with -FF */
+# endif
+
+ if (s && zfseeko(f, (zoff_t)s, SEEK_CUR))
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ /* If there is an extended local header, s is either 0 or
+ * the correct compressed size.
+ */
+ z->iname[n] = '\0'; /* terminate name */
+ z->zname = in2ex(z->iname); /* convert to external name */
+ if (z->zname == NULL)
+ return ZE_MEM;
+ z->name = z->zname;
+ z->cextra = z->extra;
+ if (noisy) fprintf(mesg, "zip: reading %s\n", z->zname);
+
+ /* Save offset, update for next header */
+ z->off = p;
+ p += 4 + LOCHEAD + n + z->ext + s;
+ zcount++;
+
+ /* Skip extended local header if there is one */
+ if ((flg & 8) != 0) {
+ /* Skip the compressed data if compressed size is unknown.
+ * For safety, we should use the central directory.
+ */
+ if (s == 0) {
+ for (;;) {
+ while ((m = getc(f)) != EOF && m != 0x50) ; /* 0x50 == 'P' */
+ b[0] = (char) m;
+ if (fread(b+1, 15, 1, f) != 1 || LG(b) == EXTLOCSIG)
+ break;
+ if (zfseeko(f, -15L, SEEK_CUR))
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ }
+# ifdef ZIP64_SUPPORT
+ if (zip64_entry) { /* from extra field */
+ /* all are 8 bytes */
+ s = LG(4 + ZIP64_EXTSIZ + b);
+ } else {
+ s = LG(4 + EXTSIZ + b);
+ }
+# else
+ s = LG(4 + EXTSIZ + b);
+# endif
+ p += s;
+ if ((uzoff_t) zftello(f) != p+16L) {
+ zipwarn("bad extended local header for ", z->zname);
+ return ZE_FORM;
+ }
+ } else {
+ /* compressed size non-zero, assume that it is valid: */
+ Assert(p == zftello(f), "bad compressed size with extended header");
+
+ if (zfseeko(f, p, SEEK_SET) || fread(b, 16, 1, f) != 1)
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ if (LG(b) != EXTLOCSIG) {
+ zipwarn("extended local header not found for ", z->zname);
+ return ZE_FORM;
+ }
+ }
+ /* overwrite the unknown values of the local header: */
+
+ /* already in host format */
+# ifdef ZIP64_SUPPORT
+ z->crc = LG(4 + ZIP64_EXTCRC + b);
+ z->siz = s;
+ z->len = LG(4 + ZIP64_EXTLEN + b);
+# else
+ z->crc = LG(4 + EXTCRC + b);
+ z->siz = s;
+ z->len = LG(4 + EXTLEN + b);
+# endif
+
+ p += 16L;
+ }
+ else if (fix > 1) {
+ /* Don't trust the compressed size */
+ for (;;) {
+ while ((m = getc(f)) != EOF && m != 0x50) p++; /* 0x50 == 'P' */
+ b[0] = (char) m;
+ if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == CENSIG)
+ break;
+ if (zfseeko(f, -3L, SEEK_CUR))
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ p++;
+ }
+ s = p - (z->off + 4 + LOCHEAD + n + z->ext);
+ if (s != z->siz) {
+ fprintf(mesg, " compressed size %s, actual size %s for %s\n",
+ zip_fzofft(z->siz, NULL, "u"), zip_fzofft(s, NULL, "u"),
+ z->zname);
+ z->siz = s;
+ }
+ /* next LOCSIG already read at this point, don't read it again: */
+ continue;
+ }
+
+ /* Read next signature */
+ if (fread(b, 4, 1, f) != 1)
+ break;
+ }
+
+ s = p; /* save start of central */
+
+ if (LG(b) != CENSIG && noisy) {
+ fprintf(mesg, "zip warning: %s %s truncated.\n", zipfile,
+ fix > 1 ? "has been" : "would be");
+
+ if (fix == 1) {
+ fprintf(mesg,
+ "Retry with option -qF to truncate, with -FF to attempt full recovery\n");
+ ZIPERR(ZE_FORM, NULL);
+ }
+ }
+
+ cenbeg = s;
+
+ if (zipbeg && noisy)
+ fprintf(mesg, "%s: adjusting offsets for a preamble of %s bytes\n",
+ zipfile, zip_fzofft(zipbeg, NULL, "u"));
+ return ZE_OK;
+} /* end of function scanzipf_fix() */
+#endif /* never, scanzipf_fix() no longer used */
+
+#endif /* !UTIL */
+
+/*
+ * read_local
+ *
+ * Read the local header assumed at in_file file pointer.
+ * localz is the returned local header, z is the central directory entry.
+ *
+ * This is used by crypt.c.
+ *
+ * Return ZE code
+ */
+int readlocal(localz, z)
+ struct zlist far **localz;
+ struct zlist far *z;
+{
+ char buf[LOCHEAD + 1];
+ struct zlist far *locz;
+
+#ifndef UTIL
+ ulg start_disk = 0;
+ uzoff_t start_offset = 0;
+ char *split_path;
+
+ start_disk = z->dsk;
+ start_offset = z->off;
+
+ /* don't assume reading the right disk */
+
+ if (start_disk != current_in_disk) {
+ if (in_file) {
+ fclose(in_file);
+ in_file = NULL;
+ }
+ }
+
+ current_in_disk = start_disk;
+
+ /* disks are archive.z01, archive.z02, ..., archive.zip */
+ split_path = get_in_split_path(in_path, current_in_disk);
+
+ if (in_file == NULL) {
+ while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+ /* could not open split */
+
+ /* Ask for directory with split. Updates in_path */
+ if (ask_for_split_read_path(start_disk) != ZE_OK) {
+ return ZE_ABORT;
+ }
+ free(split_path);
+ split_path = get_in_split_path(in_path, start_disk);
+ }
+ }
+#endif
+
+ /* For utilities assume archive is on one disk for now */
+
+ if (zfseeko(in_file, z->off, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("reading archive fseek: ", strerror(errno));
+ return ZE_READ;
+ }
+ if (!at_signature(in_file, "PK\03\04")) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("Did not find entry for ", z->iname);
+ return ZE_FORM;
+ }
+
+ /* read local header */
+ if (fread(buf, LOCHEAD, 1, in_file) != 1) {
+ int f = ferror(in_file);
+ zipwarn("reading local entry: ", strerror(errno));
+ fclose(in_file);
+ return f ? ZE_READ : ZE_EOF;
+ }
+
+ /* Local Header
+ local file header signature 4 bytes (0x04034b50)
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+
+ file name (variable size)
+ extra field (variable size)
+ */
+
+ if ((locz = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+ zipwarn("reading entry", "");
+ fclose(in_file);
+ return ZE_MEM;
+ }
+
+ locz->ver = SH(LOCVER + buf);
+ locz->lflg = SH(LOCFLG + buf);
+ locz->how = SH(LOCHOW + buf);
+ locz->tim = LG(LOCTIM + buf); /* time and date into one long */
+ locz->crc = LG(LOCCRC + buf);
+ locz->nam = SH(LOCNAM + buf);
+ locz->ext = SH(LOCEXT + buf);
+
+ /* Initialize all fields pointing to malloced data to NULL */
+ locz->zname = locz->name = locz->iname = locz->extra = NULL;
+ locz->oname = NULL;
+#ifdef UNICODE_SUPPORT
+ locz->uname = NULL;
+ locz->zuname = NULL;
+ locz->ouname = NULL;
+#endif
+
+ /* Read file name, extra field and comment field */
+ if ((locz->iname = malloc(locz->nam+1)) == NULL ||
+ (locz->ext && (locz->extra = malloc(locz->ext)) == NULL))
+ return ZE_MEM;
+ if (fread(locz->iname, locz->nam, 1, in_file) != 1 ||
+ (locz->ext && fread(locz->extra, locz->ext, 1, in_file) != 1))
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ locz->iname[z->nam] = '\0'; /* terminate name */
+#ifdef UNICODE_SUPPORT
+ if (unicode_mismatch != 3)
+ read_Unicode_Path_local_entry(locz);
+#endif
+#ifdef WIN32
+ {
+ /* translate archive name from OEM if came from OEM-charset environment */
+ unsigned hostver = (z->vem & 0xff);
+ Ext_ASCII_TO_Native(locz->iname, (z->vem >> 8), hostver,
+ ((z->atx & 0xffff0000L) != 0), TRUE);
+ }
+#endif
+ if ((locz->name = malloc(locz->nam+1)) == NULL)
+ return ZE_MEM;
+ strcpy(locz->name, locz->iname);
+
+#ifdef ZIP64_SUPPORT
+ zip64_entry = adjust_zip_local_entry(locz);
+#endif
+
+ /* Compare localz to z */
+ if (locz->ver != z->ver) {
+ sprintf(errbuf, "Local Version Needed (%d) does not match CD (%d): ", locz->ver, z->ver);
+ zipwarn(errbuf, z->iname);
+ }
+ if (locz->lflg != z->flg) {
+ zipwarn("Local Entry Flag does not match CD: ", z->iname);
+ }
+ if (locz->crc != z->crc) {
+ zipwarn("Local Entry CRC does not match CD: ", z->iname);
+ }
+
+ /* as copying get uncompressed and compressed sizes from central directory */
+ locz->len = z->len;
+ locz->siz = z->siz;
+
+ *localz = locz;
+
+ return ZE_OK;
+} /* end function readlocal() */
+
+#if 0 /* following functions are not (no longer) used. */
+/*
+ * scanzipf_reg starts searching for the End Signature at the end of the file
+ * The End Signature points to the Central Directory Signature which points
+ * to the Local Directory Signature
+ * XXX probably some more consistency checks are needed
+ */
+local int scanzipf_reg(f)
+ FILE *f; /* zip file */
+/*
+ The name of the zip file is pointed to by the global "zipfile". The globals
+ zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+ Return an error code in the ZE_ class.
+*/
+{
+ char b[CENHEAD]; /* buffer for central headers */
+ extent n; /* length of name */
+ struct zlist far * far *x; /* pointer last entry's link */
+ struct zlist far *z; /* current zip entry structure */
+ char *t; /* temporary pointer */
+ char far *u; /* temporary variable */
+ int found;
+ char *buf; /* temp buffer for reading zipfile */
+# ifdef ZIP64_SUPPORT
+ ulg u4; /* unsigned 4 byte variable */
+ char bf[8];
+ uzoff_t u8; /* unsigned 8 byte variable */
+ uzoff_t censiz; /* size of central directory */
+ uzoff_t z64eocd; /* Zip64 End Of Central Directory record byte offset */
+# else
+ ush flg; /* general purpose bit flag */
+ int m; /* mismatch flag */
+# endif
+ zoff_t deltaoff = 0;
+
+
+#ifndef ZIP64_SUPPORT
+
+ /* 2004-12-06 SMS.
+ * Check for too-big file before doing any serious work.
+ */
+ if (ffile_size( f) == EOF)
+ return ZE_ZIP64;
+
+#endif /* ndef ZIP64_SUPPORT */
+
+
+ buf = malloc(4096 + 4);
+ if (buf == NULL)
+ return ZE_MEM;
+
+#ifdef HANDLE_AMIGA_SFX
+ amiga_sfx_offset = (fread(buf, 1, 4, f) == 4 && LG(buf) == 0xF3030000);
+ /* == 1 if this file is an Amiga executable (presumably UnZipSFX) */
+#endif
+ /* detect spanning signature */
+ zfseeko(f, 0, SEEK_SET);
+ read_split_archive = (fread(buf, 1, 4, f) == 4 && LG(buf) == 0x08074b50L);
+ found = 0;
+ t = &buf[4096];
+ t[1] = '\0';
+ t[2] = '\0';
+ t[3] = '\0';
+ /* back up as much as 4k from end */
+ /* zip64 support 08/31/2003 R.Nausedat */
+ if (zfseeko(f, -4096L, SEEK_END) == 0) {
+ zipbeg = (uzoff_t) (zftello(f) + 4096L);
+ /* back up 4k blocks and look for End Of CD signature */
+ while (!found && zipbeg >= 4096) {
+ zipbeg -= 4096L;
+ buf[4096] = t[1];
+ buf[4097] = t[2];
+ buf[4098] = t[3];
+/*
+ * XXX error check ??
+ */
+ fread(buf, 1, 4096, f);
+ zfseeko(f, -8192L, SEEK_CUR);
+ t = &buf[4095];
+/*
+ * XXX far pointer arithmetic in DOS
+ */
+ while (t >= buf) {
+ /* Check for ENDSIG ("PK\5\6" in ASCII) */
+ if (LG(t) == ENDSIG) {
+ found = 1;
+/*
+ * XXX error check ??
+ * XXX far pointer arithmetic in DOS
+ */
+ zipbeg += (uzoff_t) (t - buf);
+ zfseeko(f, (zoff_t) zipbeg + 4L, SEEK_SET);
+ break;
+ }
+ --t;
+ }
+ }
+ }
+ else
+ /* file less than 4k bytes */
+ zipbeg = 4096L;
+/*
+ * XXX warn: garbage at the end of the file ignored
+ */
+ if (!found && zipbeg > 0) {
+ size_t s;
+
+ zfseeko(f, 0L, SEEK_SET);
+ clearerr(f);
+ s = fread(buf, 1, (size_t) zipbeg, f);
+ /* add 0 bytes at end */
+ buf[s] = t[1];
+ buf[s + 1] = t[2];
+ buf[s + 2] = t[3];
+ t = &buf[s - 1];
+/*
+ * XXX far pointer comparison in DOS
+ */
+ while (t >= buf) {
+ /* Check for ENDSIG ("PK\5\6" in ASCII) */
+ if (LG(t) == ENDSIG) {
+ found = 1;
+/*
+ * XXX far pointer arithmetic in DOS
+ */
+ zipbeg = (ulg) (t - buf);
+ zfseeko(f, (zoff_t) zipbeg + 4L, SEEK_SET);
+ break;
+ }
+ --t;
+ }
+ }
+ free(buf);
+ if (!found) {
+ zipwarn("missing end signature--probably not a zip file (did you", "");
+ zipwarn("remember to use binary mode when you transferred it?)", "");
+ return ZE_FORM;
+ }
+
+/*
+ * Check for a Zip64 EOCD Locator signature - 12/10/04 EG
+ */
+#ifndef ZIP64_SUPPORT
+ /* If Zip64 not enabled check if archive being read is Zip64 */
+ /* back up 24 bytes (size of Z64 EOCDL and ENDSIG) */
+ if (zfseeko(f, -24, SEEK_CUR) != 0) {
+ perror("fseek");
+ return ZE_FORM; /* XXX */
+ }
+ /* read Z64 EOCDL if there */
+ if (fread(b, 20, 1, f) != 1) {
+ return ZE_READ;
+ }
+ /* first 4 bytes are the signature if there */
+ if (LG(b) == ZIP64_EOCDL_SIG) {
+ zipwarn("found Zip64 signature - this may be a Zip64 archive", "");
+ zipwarn("PKZIP 4.5 or later needed - set ZIP64_SUPPORT in Zip 3", "");
+ return ZE_ZIP64;
+ }
+
+ /* now should be back at the EOCD signature */
+ if (fread(b, 4, 1, f) != 1) {
+ zipwarn("unable to read after relative seek", "");
+ return ZE_READ;
+ }
+ if (LG(b) != ENDSIG) {
+ zipwarn("unable to relative seek in archive", "");
+ return ZE_FORM;
+ }
+#if 0
+ if (fseek(f, -4, SEEK_CUR) != 0) {
+ perror("fseek");
+ return ZE_FORM; /* XXX */
+ }
+#endif
+#endif
+
+ /* Read end header */
+ if (fread(b, ENDHEAD, 1, f) != 1)
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ if (SH(ENDDSK + b) || SH(ENDBEG + b) ||
+ SH(ENDSUB + b) != SH(ENDTOT + b))
+ zipwarn("multiple disk information ignored", "");
+ zcomlen = SH(ENDCOM + b);
+ if (zcomlen)
+ {
+ if ((zcomment = malloc(zcomlen)) == NULL)
+ return ZE_MEM;
+ if (fread(zcomment, zcomlen, 1, f) != 1)
+ {
+ free((zvoid *)zcomment);
+ zcomment = NULL;
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ }
+#ifdef EBCDIC
+ if (zcomment)
+ memtoebc(zcomment, zcomment, zcomlen);
+#endif /* EBCDIC */
+ }
+#ifdef ZIP64_SUPPORT
+ /* account for Zip64 EOCD Record and Zip64 EOCD Locator */
+
+ /* Z64 EOCDL should be just before EOCD (unless this is an empty archive) */
+ cenbeg = zipbeg - ZIP64_EOCDL_OFS_SIZE;
+ /* check for empty archive */
+ /* changed cenbeg to uzoff_t so instead of cenbeg >= 0 use new check - 5/23/05 EG */
+ if (zipbeg >= ZIP64_EOCDL_OFS_SIZE) {
+ /* look for signature */
+ if (zfseeko(f, cenbeg, SEEK_SET)) {
+ zipwarn("end of file seeking Z64EOCDL", "");
+ return ZE_FORM;
+ }
+ if (fread(bf, 4, 1, f) != 1) {
+ ziperr(ZE_FORM, "read error");
+ }
+ u4 = LG(bf);
+ if (u4 == ZIP64_EOCDL_SIG) {
+ /* found Zip64 EOCD Locator */
+ /* check for disk information */
+ zfseeko(f, cenbeg + ZIP64_EOCDL_OFS_TOTALDISKS, SEEK_SET);
+ if (fread(bf, 4, 1, f) != 1) {
+ ziperr(ZE_FORM, "read error");
+ }
+ u4 = LG(bf);
+ if (u4 != 1) {
+ ziperr(ZE_FORM, "multiple disk archives not yet supported");
+ }
+
+ /* look for Zip64 EOCD Record */
+ zfseeko(f, cenbeg + ZIP64_EOCDL_OFS_EOCD_START, SEEK_SET);
+ if (fread(bf, 8, 1, f) != 1) {
+ ziperr(ZE_FORM, "read error");
+ }
+ z64eocd = LLG(bf);
+ if (zfseeko(f, z64eocd, SEEK_SET)) {
+ ziperr(ZE_FORM, "error searching for Z64 EOCD Record");
+ }
+ if (fread(bf, 4, 1, f) != 1) {
+ ziperr(ZE_FORM, "read error");
+ }
+ u4 = LG(bf);
+ if (u4 != ZIP64_EOCD_SIG) {
+ ziperr(ZE_FORM, "Z64 EOCD not found but Z64 EOCD Locator exists");
+ }
+ /* get size of CD */
+ zfseeko(f, z64eocd + ZIP64_EOCD_OFS_SIZE, SEEK_SET);
+ if (fread(bf, 8, 1, f) != 1) {
+ ziperr(ZE_FORM, "read error");
+ }
+ censiz = LLG(bf);
+ /* get start of CD */
+ zfseeko(f, z64eocd + ZIP64_EOCD_OFS_CD_START, SEEK_SET);
+ if (fread(bf, 8, 1, f) == (size_t) -1) {
+ ziperr(ZE_FORM, "read error");
+ }
+ cenbeg = LLG(bf);
+ u8 = z64eocd - cenbeg;
+ deltaoff = adjust ? u8 - censiz : 0L;
+ } else {
+ /* assume no Locator and no Zip64 EOCD Record */
+ censiz = LG(ENDSIZ + b);
+ cenbeg = LG(b + ENDOFF);
+ u8 = zipbeg - censiz;
+ deltaoff = adjust ? u8 - censiz : 0L;
+ }
+ }
+#else /* !ZIP64_SUPPORT */
+/*
+ * XXX assumes central header immediately precedes end header
+ */
+ /* start of central directory */
+ cenbeg = zipbeg - LG(ENDSIZ + b);
+/*
+printf("start of central directory cenbeg %ld\n", cenbeg);
+*/
+
+ /* offset to first entry of archive */
+ deltaoff = adjust ? cenbeg - LG(b + ENDOFF) : 0L;
+#endif /* ?ZIP64_SUPPORT */
+
+ if (zipbeg < ZIP64_EOCDL_OFS_SIZE) {
+ /* zip file seems empty */
+ return ZE_OK;
+ }
+
+ if (zfseeko(f, cenbeg, SEEK_SET) != 0) {
+ perror("fseek");
+ return ZE_FORM; /* XXX */
+ }
+
+ x = &zfiles; /* first link */
+
+ if (fread(b, 4, 1, f) != 1)
+ return ferror(f) ? ZE_READ : ZE_EOF;
+
+ while (LG(b) == CENSIG) {
+ /* Read central header. The portion of the central header that should
+ be in common with local header is read raw, for later comparison.
+ (this requires that the offset of ext in the zlist structure
+ be greater than or equal to LOCHEAD) */
+ if (fread(b, CENHEAD, 1, f) != 1)
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
+ return ZE_MEM;
+ z->vem = SH(CENVEM + b);
+ for (u = (char far *)(&(z->ver)), n = 0; n < (CENNAM-CENVER); n++)
+ u[n] = b[CENVER + n];
+ z->nam = SH(CENNAM + b); /* used before comparing cen vs. loc */
+ z->cext = SH(CENEXT + b); /* may be different from z->ext */
+ z->com = SH(CENCOM + b);
+ z->dsk = SH(CENDSK + b);
+ z->att = SH(CENATT + b);
+ z->atx = LG(CENATX + b);
+ z->off = LG(CENOFF + b) + deltaoff;
+ z->dosflag = (z->vem & 0xff00) == 0;
+
+ /* Initialize all fields pointing to malloced data to NULL */
+ z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+ z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+ z->uname = NULL; /* UTF-8 path */
+ z->zuname = NULL; /* Escaped local version of uname */
+ z->ouname = NULL; /* Display version of zuname */
+#endif
+
+ /* Link into list */
+ *x = z;
+ z->nxt = NULL;
+ x = &z->nxt;
+
+ /* Read file name, extra field and comment field */
+ if (z->nam == 0)
+ {
+ sprintf(errbuf, "%lu", (ulg)zcount + 1);
+ zipwarn("zero-length name for entry #", errbuf);
+#ifndef DEBUG
+ farfree((zvoid far *)z);
+ return ZE_FORM;
+#endif
+ }
+ if ((z->iname = malloc(z->nam+1)) == NULL ||
+ (z->cext && (z->cextra = malloc(z->cext)) == NULL) ||
+ (z->com && (z->comment = malloc(z->com)) == NULL))
+ return ZE_MEM;
+ if (fread(z->iname, z->nam, 1, f) != 1 ||
+ (z->cext && fread(z->cextra, z->cext, 1, f) != 1) ||
+ (z->com && fread(z->comment, z->com, 1, f) != 1))
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ z->iname[z->nam] = '\0'; /* terminate name */
+
+#ifdef EBCDIC
+ if (z->com)
+ memtoebc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+
+#ifdef ZIP64_SUPPORT
+ /* zip64 support 08/31/2003 R.Nausedat */
+ /* here, we have to read the len, siz etc values from the CD */
+ /* entry as we might have to adjust them regarding their */
+ /* correspronding zip64 extra fields. */
+ /* also, we cannot compare the values from the CD entries with */
+ /* the values from the LH as they might be different. */
+ z->len = LG(CENLEN + b);
+ z->siz = LG(CENSIZ + b);
+ z->crc = LG(CENCRC + b);
+ z->tim = LG(CENTIM + b); /* time and date into one long */
+ z->how = SH(CENHOW + b);
+ z->flg = SH(CENFLG + b);
+ z->ver = SH(CENVER + b);
+ /* adjust/update siz,len and off (to come: dsk) entries */
+ /* PKZIP does not care of the version set in a CDH: if */
+ /* there is a zip64 extra field assigned to a CDH PKZIP */
+ /* uses it, we should do so, too. */
+ adjust_zip_central_entry(z);
+#endif /* ZIP64_SUPPORT */
+
+ /* Update zipbeg offset, prepare for next header */
+ if (z->off < zipbeg)
+ zipbeg = z->off;
+ zcount++;
+ /* Read next signature */
+ if (fread(b, 4, 1, f) != 1)
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ }
+
+ /* Point to start of header list and read local headers */
+ z = zfiles;
+ while (z != NULL) {
+ /* Read next signature */
+ if (zfseeko(f, z->off, SEEK_SET) != 0 || fread(b, 4, 1, f) != 1)
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ if (LG(b) == LOCSIG) {
+ if (fread(b, LOCHEAD, 1, f) != 1)
+ return ferror(f) ? ZE_READ : ZE_EOF;
+
+ z->lflg = SH(LOCFLG + b);
+ n = SH(LOCNAM + b);
+ z->ext = SH(LOCEXT + b);
+
+ /* Compare name and extra fields */
+ if (n != z->nam)
+ {
+#ifdef EBCDIC
+ strtoebc(z->iname, z->iname);
+#endif
+ zipwarn("name lengths in local and central differ for ", z->iname);
+ return ZE_FORM;
+ }
+ if ((t = malloc(z->nam)) == NULL)
+ return ZE_MEM;
+ if (fread(t, z->nam, 1, f) != 1)
+ {
+ free((zvoid *)t);
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ }
+ if (memcmp(t, z->iname, z->nam))
+ {
+ free((zvoid *)t);
+#ifdef EBCDIC
+ strtoebc(z->iname, z->iname);
+#endif
+ zipwarn("names in local and central differ for ", z->iname);
+ return ZE_FORM;
+ }
+ free((zvoid *)t);
+ if (z->ext)
+ {
+ if ((z->extra = malloc(z->ext)) == NULL)
+ return ZE_MEM;
+ if (fread(z->extra, z->ext, 1, f) != 1)
+ {
+ free((zvoid *)(z->extra));
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ }
+ if (z->ext == z->cext && memcmp(z->extra, z->cextra, z->ext) == 0)
+ {
+ free((zvoid *)(z->extra));
+ z->extra = z->cextra;
+ }
+ }
+
+#ifdef ZIP64_SUPPORT /* zip64 support 09/02/2003 R.Nausedat */
+ /*
+ for now the below is left out if ZIP64_SUPPORT is defined as the fields
+ len, siz and off in struct zlist are type of int64 if ZIP64_SUPPORT
+ is defined. In either way, the values read from the central directory
+ should be valid. comments are welcome
+ */
+#else /* !ZIP64_SUPPORT */
+ /* Check extended local header if there is one */
+ /* bit 3 */
+ if ((z->lflg & 8) != 0)
+ {
+ char buf2[16];
+ ulg s; /* size of compressed data */
+
+ s = LG(LOCSIZ + b);
+ if (s == 0)
+ s = LG((CENSIZ-CENVER) + (char far *)(&(z->ver)));
+ if (zfseeko(f, (z->off + (4+LOCHEAD) + z->nam + z->ext + s), SEEK_SET)
+ || (fread(buf2, 16, 1, f) != 1))
+ return ferror(f) ? ZE_READ : ZE_EOF;
+ if (LG(buf2) != EXTLOCSIG)
+ {
+# ifdef EBCDIC
+ strtoebc(z->iname, z->iname);
+# endif
+ zipwarn("extended local header not found for ", z->iname);
+ return ZE_FORM;
+ }
+ /* overwrite the unknown values of the local header: */
+ for (n = 0; n < 12; n++)
+ b[LOCCRC+n] = buf2[4+n];
+ }
+
+ /* Compare local header with that part of central header (except
+ for the reserved bits in the general purpose flags and except
+ for the already checked entry name length */
+ /* If I have read this right we are stepping through the z struct
+ here as a byte array. Need to fix this. 5/25/2005 EG */
+ u = (char far *)(&(z->ver));
+ flg = SH((CENFLG-CENVER) + u); /* Save central flags word */
+ u[CENFLG-CENVER+1] &= 0x1f; /* Mask reserved flag bits */
+ b[LOCFLG+1] &= 0x1f;
+ for (m = 0, n = 0; n < LOCNAM; n++) {
+ if (b[n] != u[n])
+ {
+ if (!m)
+ {
+ zipwarn("local and central headers differ for ", z->iname);
+ m = 1;
+ }
+ if (noisy)
+ {
+ sprintf(errbuf, " offset %u--local = %02x, central = %02x",
+ (unsigned)n, (uch)b[n], (uch)u[n]);
+ zipwarn(errbuf, "");
+ }
+ }
+ }
+ if (m && !adjust)
+ return ZE_FORM;
+
+ /* Complete the setup of the zlist entry by translating the remaining
+ * central header fields in memory, starting with the fields with
+ * highest offset. This order of the conversion commands takes into
+ * account potential buffer overlaps caused by structure padding.
+ */
+ z->len = LG((CENLEN-CENVER) + u);
+ z->siz = LG((CENSIZ-CENVER) + u);
+ z->crc = LG((CENCRC-CENVER) + u);
+ z->tim = LG((CENTIM-CENVER) + u); /* time and date into one long */
+ z->how = SH((CENHOW-CENVER) + u);
+ z->flg = flg; /* may be different from z->lflg */
+ z->ver = SH((CENVER-CENVER) + u);
+#endif /* ?ZIP64_SUPPORT */
+
+ /* Clear actions */
+ z->mark = 0;
+ z->trash = 0;
+#ifdef UNICODE_SUPPORT
+ if (unicode_mismatch != 3) {
+ read_Unicode_Path_entry(z);
+ if (z->uname) {
+ /* match based on converted Unicode name */
+ z->name = utf8_to_local_string(z->uname);
+# ifdef EBCDIC
+ /* z->zname is used for printing and must be coded in native charset */
+ strtoebc(z->zname, z->name);
+# else
+ if ((z->zname = malloc(strlen(z->name) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "scanzipf_reg");
+ }
+ strcpy(z->zname, z->name);
+# endif
+ z->oname = local_to_display_string(z->zname);
+ } else {
+ /* no UTF-8 path */
+ if ((z->name = malloc(strlen(z->iname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "scanzipf_reg");
+ }
+ strcpy(z->name, z->iname);
+ if ((z->zname = malloc(strlen(z->iname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "scanzipf_reg");
+ }
+ strcpy(z->zname, z->iname);
+ z->oname = local_to_display_string(z->iname);
+ }
+ }
+#else /* !UNICODE_SUPPORT */
+# ifdef UTIL
+/* We only need z->iname in the utils */
+ z->name = z->iname;
+# ifdef EBCDIC
+/* z->zname is used for printing and must be coded in native charset */
+ if ((z->zname = malloc(z->nam+1)) == NULL)
+ return ZE_MEM;
+ strtoebc(z->zname, z->iname);
+# else
+ z->zname = z->iname;
+# endif
+# else /* !UTIL */
+ z->zname = in2ex(z->iname); /* convert to external name */
+ if (z->zname == NULL)
+ return ZE_MEM;
+ z->name = z->zname;
+# endif /* ?UTIL */
+ if ((z->oname = malloc(strlen(z->zname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "scanzipf_reg");
+ }
+ strcpy(z->oname, z->zname);
+#endif /* ?UNICODE_SUPPORT */
+ }
+ else {
+#ifdef EBCDIC
+ strtoebc(z->iname, z->iname);
+#endif
+ zipwarn("local header not found for ", z->iname);
+ return ZE_FORM;
+ }
+#ifndef UTIL
+ if (verbose && fix == 0)
+ zipoddities(z);
+#endif
+ z = z->nxt;
+ }
+
+ if (zipbeg && noisy)
+ fprintf(mesg, "%s: %s a preamble of %s bytes\n",
+ zipfile, adjust ? "adjusting offsets for" : "found",
+ zip_fzofft(zipbeg, NULL, "u"));
+#ifdef HANDLE_AMIGA_SFX
+ if (zipbeg < 12 || (zipbeg & 3) != 0 /* must be longword aligned */)
+ amiga_sfx_offset = 0;
+ else if (amiga_sfx_offset) {
+ char buf2[16];
+ if (!fseek(f, zipbeg - 12, SEEK_SET) && fread(buf2, 12, 1, f) == 1) {
+ if (LG(buf2 + 4) == 0xF1030000 /* 1009 in Motorola byte order */)
+ /* could also check if LG(buf2) == 0xF2030000... no for now */
+ amiga_sfx_offset = zipbeg - 4;
+ else
+ amiga_sfx_offset = 0L;
+ }
+ }
+#endif /* HANDLE_AMIGA_SFX */
+ return ZE_OK;
+} /* end of function scanzipf_reg() */
+#endif /* never */
+
+
+
+
+/* find_next_signature
+ *
+ * Scan the file forward and look for the next PK signature.
+ *
+ * Return 1 if find one and leave file pointer pointing to next char
+ * after signature and set sigbuf to signature.
+ *
+ * Return 0 if not. Will be at EOF on return unless error.
+ *
+ */
+
+local char sigbuf[4]; /* signature found */
+
+#if 0 /* currently unused */
+/* copy signature */
+char *copy_sig(copyto, copyfrom)
+ char *copyto;
+ char *copyfrom;
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ copyto[i] = copyfrom[i];
+ }
+ return copyto;
+}
+#endif /* currently unused */
+
+
+local int find_next_signature(f)
+ FILE *f;
+{
+ int m;
+ /*
+ zoff_t here;
+ */
+
+ /* look for P K ? ? signature */
+
+ m = getc(f);
+
+ /*
+ here = zftello(f);
+ */
+
+ while (m != EOF)
+ {
+ if (m == 0x50 /*'P' except EBCDIC*/) {
+ /* found a P */
+ sigbuf[0] = (char) m;
+
+ if ((m = getc(f)) == EOF)
+ break;
+ if (m != 0x4b /*'K' except EBCDIC*/) {
+ /* not a signature */
+ ungetc(m, f);
+ } else {
+ /* found P K */
+ sigbuf[1] = (char) m;
+
+ if ((m = getc(f)) == EOF)
+ break;
+ if (m == 0x50 /*'P' except EBCDIC*/) {
+ /* not a signature but maybe start of new one */
+ ungetc(m, f);
+ continue;
+ } else if (m >= 16) {
+ /* last 2 chars expect < 16 for signature */
+ continue;
+ }
+ sigbuf[2] = (char) m;
+
+ if ((m = getc(f)) == EOF)
+ break;
+ if (m == 0x50 /*'P' except EBCDIC*/) {
+ /* not a signature but maybe start of new one */
+ ungetc(m, f);
+ continue;
+ } else if (m >= 16) {
+ /* last 2 chars expect < 16 */
+ continue;
+ }
+ sigbuf[3] = (char) m;
+
+ /* found possible signature */
+ return 1;
+ }
+ }
+ m = getc(f);
+ }
+ if (ferror(f)) {
+ return 0;
+ }
+
+ /* found nothing */
+ return 0;
+}
+
+/* find_signature
+ *
+ * Find signature.
+ *
+ * Return 1 if found and leave file pointing to next character
+ * after signature. Set sigbuf with signature.
+ *
+ * Return 0 if not found.
+ */
+
+local int find_signature(f, signature)
+ FILE *f;
+ ZCONST char *signature;
+{
+ int i;
+ char sig[4];
+ /*
+ zoff_t here = zftello(f);
+ */
+
+ for (i = 0; i < 4; i++)
+ sig[i] = signature[i];
+
+ /* for EBCDIC */
+ if (sig[0] == 'P')
+ sig[0] = 0x50;
+ if (sig[1] == 'K')
+ sig[1] = 0x4b;
+
+ while (!feof(f)) {
+ if (!find_next_signature(f)) {
+ return 0;
+ } else {
+ for (i = 0; i < 4; i++) {
+ if (sig[i] != sigbuf[i]) {
+ /* not a match */
+ break;
+ }
+ }
+ if (i == 4) {
+ /* found it */
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* is_signature
+ *
+ * Compare signatures
+ *
+ * Return 1 if the signatures match.
+ */
+
+local int is_signature(sig1, sig2)
+ ZCONST char *sig1;
+ ZCONST char *sig2;
+{
+ int i;
+ char tsig1[4];
+ char tsig2[4];
+
+ for (i = 0; i < 4; i++) {
+ tsig1[i] = sig1[i];
+ tsig2[i] = sig2[i];
+ }
+
+ /* for EBCDIC */
+ if (tsig1[0] == 'P')
+ tsig1[0] = 0x50;
+ if (tsig1[1] == 'K')
+ tsig1[1] = 0x4b;
+
+ if (tsig2[0] == 'P')
+ tsig2[0] = 0x50;
+ if (tsig2[1] == 'K')
+ tsig2[1] = 0x4b;
+
+ for (i = 0; i < 4; i++) {
+ if (tsig1[i] != tsig2[i]) {
+ /* not a match */
+ break;
+ }
+ }
+ if (i == 4) {
+ /* found it */
+ return 1;
+ }
+ return 0;
+}
+
+
+/* at_signature
+ *
+ * Is at signature in file
+ *
+ * Return 1 if at the signature and leave file pointing to next character
+ * after signature.
+ *
+ * Return 0 if not.
+ */
+
+local int at_signature(f, signature)
+ FILE *f;
+ ZCONST char *signature;
+{
+ int i;
+ extent m;
+ char sig[4];
+ char b[4];
+
+ for (i = 0; i < 4; i++)
+ sig[i] = signature[i];
+
+ /* for EBCDIC */
+ if (sig[0] == 'P')
+ sig[0] = 0x50;
+ if (sig[1] == 'K')
+ sig[1] = 0x4b;
+
+ m = fread(b, 1, 4, f);
+ if (m != 4) {
+ return 0;
+ } else {
+ for (i = 0; i < 4; i++) {
+ if (sig[i] != b[i]) {
+ /* not a match */
+ break;
+ }
+ }
+ if (i == 4) {
+ /* found it */
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+#ifndef UTIL
+
+local int scanzipf_fixnew()
+/*
+ Scan an assumed broke archive from the beginning, salvaging what can.
+
+ Generally scanzipf_regnew() is used for reading archives normally and
+ for fixing archives with a readable central directory using -F. This
+ scan is used by -FF and is for an archive that is unreadable by
+ scanzipf_regnew().
+
+ Start with the first file of the archive, either .z01 or .zip, and
+ look for local entries. Read local entries found and create zlist
+ entries for them. If we find central directory entries, read them
+ and update the zlist created while reading local entries.
+
+ The input path for the .zip file is in in_path. If this is a multiple disk
+ archive get the paths for splits from in_path as we go. If a split is not in
+ the same directory as the last split we ask the user where it is and update
+ in_path.
+ */
+/*
+ This is old:
+
+ The name of the zip file is pointed to by the global "zipfile". The globals
+ zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+ Return an error code in the ZE_ class.
+*/
+{
+ /* This function only reads the standard End-of-CentralDir record and the
+ standard CentralDir-Entry records directly. To conserve stack space,
+ only a buffer of minimal size is declared.
+ */
+# if CENHEAD > ENDHEAD
+# define FIXSCAN_BUFSIZE CENHEAD
+# else
+# define FIXSCAN_BUFSIZE ENDHEAD
+# endif
+
+ char scbuf[FIXSCAN_BUFSIZE]; /* buffer big enough for headers */
+ char *split_path;
+ ulg eocdr_disk;
+ uzoff_t eocdr_offset;
+
+ uzoff_t current_offset = 0; /* offset before */
+ uzoff_t offset = 0; /* location after return from seek */
+
+ int skip_disk = 0; /* 1 if user asks to skip current disk */
+ int skipped_disk = 0; /* 1 if skipped start disk and start offset is useless */
+
+ int r = 0; /* zipcopy return */
+ uzoff_t s; /* size of data, start of central */
+ struct zlist far * far *x; /* pointer last entry's link */
+ struct zlist far *z; /* current zip entry structure */
+ int plen;
+ char *in_path_ext;
+ int in_central_directory = 0; /* found a central directory record */
+ struct zlist far *cz;
+ uzoff_t cd_total_entries = 0; /* number of entries according to EOCDR */
+ ulg in_cd_start_disk; /* central directory start disk */
+ uzoff_t in_cd_start_offset; /* offset of start of cd on cd start disk */
+
+
+ total_disks = 1000000;
+
+ /* open the zipfile */
+ /* This must be .zip file, even if it doesn't exist */
+
+ /* see if zipfile name ends in .zip */
+ plen = strlen(in_path);
+
+#ifdef VMS
+ /* On VMS, adjust plen (and in_path_ext) to avoid the file version. */
+ plen -= strlen(vms_file_version(in_path));
+#endif /* def VMS */
+ in_path_ext = zipfile + plen - 4;
+
+ if (plen >= 4 &&
+ in_path_ext[0] == '.' &&
+ toupper(in_path_ext[1]) == 'Z' &&
+ in_path_ext[2] >= '0' && in_path_ext[2] <= '9' &&
+ in_path_ext[3] >= '0' && in_path_ext[3] <= '9' &&
+ (plen == 4 || (in_path_ext[4] >= '0' && in_path_ext[4] <= '9'))) {
+ /* This may be a split but not the end split */
+ strcpy(errbuf, "if archive to fix is split archive, need to provide\n");
+ strcat(errbuf, " path of the last split with .zip extension,\n");
+ strcat(errbuf, " even if it doesn't exist (zip will ask for splits)");
+ zipwarn(errbuf, "");
+ return ZE_FORM;
+ }
+
+ if ((in_file = zfopen(in_path, FOPR)) == NULL) {
+ zipwarn("could not open input archive: ", in_path);
+ }
+ else
+ {
+
+#ifndef ZIP64_SUPPORT
+ /* 2004-12-06 SMS.
+ * Check for too-big file before doing any serious work.
+ */
+ if (ffile_size( in_file) == EOF) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("input file requires Zip64 support: ", in_path);
+ return ZE_ZIP64;
+ }
+#endif /* ndef ZIP64_SUPPORT */
+
+ /* look for End Of Central Directory Record */
+
+ /* back up 64k (the max size of the EOCDR) from end */
+ if (zfseeko(in_file, -0x40000L, SEEK_END) != 0) {
+ /* assume file is less than 64 KB so backup to beginning */
+ if (zfseeko(in_file, 0L, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to seek in input file ", in_path);
+ return ZE_READ;
+ }
+ }
+
+
+ /* find EOCD Record signature */
+ if (!find_signature(in_file, "PK\05\06")) {
+ /* No End Of Central Directory Record */
+ strcpy(errbuf, "Missing end (EOCDR) signature - either this archive\n");
+ strcat(errbuf, " is not readable or the end is damaged");
+ zipwarn(errbuf, "");
+ }
+ else
+ {
+ /* at start of data after EOCDR signature */
+ eocdr_offset = (uzoff_t) zftello(in_file);
+
+ /* OK, it is possible this is not the last EOCDR signature (might be
+ EOCDR signature from a stored archive in the last 64 KB) and so not
+ the one we want.
+
+ The below assumes the signature does not appear in the assumed
+ ASCII text .ZIP file comment. Even if something like UTF-8
+ is stored in the comment, it's unlikely the binary \05 and \06
+ will be in the comment text.
+ */
+ while (find_signature(in_file, "PK\05\06")) {
+ eocdr_offset = (uzoff_t) zftello(in_file);
+ }
+
+ /* found EOCDR */
+ /* format is
+ end of central dir signature 4 bytes (0x06054b50)
+ number of this disk 2 bytes
+ number of the disk with the
+ start of the central directory 2 bytes
+ total number of entries in the
+ central directory on this disk 2 bytes
+ total number of entries in
+ the central directory 2 bytes
+ size of the central directory 4 bytes
+ offset of start of central
+ directory with respect to
+ the starting disk number 4 bytes
+ .ZIP file comment length 2 bytes
+ .ZIP file comment (variable size)
+ */
+
+ if (zfseeko(in_file, eocdr_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to seek in input file ", in_path);
+ return ZE_READ;
+ }
+
+ /* read the EOCDR */
+ s = fread(scbuf, 1, ENDHEAD, in_file);
+
+ /* make sure we read enough bytes */
+ if (s < ENDHEAD) {
+ sprintf(errbuf, "End record (EOCDR) only %s bytes - assume truncated",
+ zip_fzofft(s, NULL, "u"));
+ zipwarn(errbuf, "");
+ }
+ else
+ {
+ /* the first field should be number of this (the last) disk */
+ eocdr_disk = (ulg)SH(scbuf);
+ total_disks = eocdr_disk + 1;
+
+ /* assume this is this disk - if Zip64 it may not be as the
+ disk number may be bigger than this field can hold
+ */
+ current_in_disk = total_disks - 1;
+
+ /* Central Directory disk, offset, and total entries */
+ in_cd_start_disk = (ulg)SH(scbuf + 2);
+ in_cd_start_offset = (uzoff_t)LG(scbuf + 12);
+ cd_total_entries = (uzoff_t)SH(scbuf + 6);
+
+ /* the in_cd_start_disk should always be less than the total_disks,
+ unless the -1 flags are being used */
+ if (total_disks < 0x10000 && in_cd_start_disk > total_disks) {
+ zipwarn("End record (EOCDR) has bad disk numbers - ignoring EOCDR", "");
+ total_disks = 0;
+ }
+ else
+ {
+ /* length of zipfile comment */
+ zcomlen = SH(scbuf + ENDCOM);
+ if (zcomlen)
+ {
+ if ((zcomment = malloc(zcomlen + 1)) == NULL)
+ return ZE_MEM;
+ if (fread(zcomment, zcomlen, 1, in_file) != 1)
+ {
+ free((zvoid *)zcomment);
+ zcomment = NULL;
+ zipwarn("zipfile comment truncated - ignoring", "");
+ } else {
+ zcomment[zcomlen] = '\0';
+ }
+#ifdef EBCDIC
+ if (zcomment)
+ memtoebc(zcomment, zcomment, zcomlen);
+#endif /* EBCDIC */
+ }
+ }
+ if (total_disks != 1)
+ sprintf(errbuf, " Found end record (EOCDR) - says expect %lu splits", total_disks);
+ else
+ sprintf(errbuf, " Found end record (EOCDR) - says expect single disk archive");
+ zipmessage(errbuf, "");
+ if (zcomment)
+ zipmessage(" Found archive comment", "");
+ } /* good EOCDR */
+
+ } /* found EOCDR */
+
+ /* if total disks is other than 1 then this is not start disk */
+ /* if the EOCDR is bad, total_disks is 0 */
+
+ /* if total_disks = 0, then guess if this is a single-disk archive
+ by seeing if starts with local header */
+
+ if (total_disks == 0) {
+ int issig;
+ /* seek to top */
+ if (zfseeko(in_file, 0, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to seek in input file ", in_path);
+ return ZE_READ;
+ }
+ /* get next signature */
+ issig = find_next_signature(in_file);
+ if (issig) {
+ current_in_offset = zftello(in_file);
+ if (current_in_offset == 4 && is_signature(sigbuf, "PK\03\03")) {
+ /* could be multi-disk aborted signature at top */
+ /* skip */
+ issig = find_next_signature(in_file);
+ } else if (current_in_offset <= 4 && is_signature(sigbuf, "PK\03\03")) {
+ /* multi-disk spanning signature */
+ total_disks = 99999;
+ }
+ }
+ if (issig && total_disks == 0) {
+ current_in_offset = zftello(in_file);
+
+ if (current_in_offset == 8 && is_signature(sigbuf, "PK\03\04")) {
+
+ /* Local Header Record at top */
+
+ printf("Is this a single-disk archive? (y/n): ");
+ fflush(stdout);
+
+ if (fgets(errbuf, 100, stdin) != NULL) {
+ if (errbuf[0] == 'y' || errbuf[0] == 'Y') {
+ total_disks = 1;
+ zipmessage(" Assuming single-disk archive", "");
+ }
+ }
+ }
+ }
+ }
+ if (!noisy)
+ /* if quiet assume single-disk archive */
+ total_disks = 1;
+
+ if (total_disks == 1000000) {
+ /* still don't know, so ask */
+ printf("Is this a single-disk archive? (y/n): ");
+ fflush(stdout);
+
+ if (fgets(errbuf, 100, stdin) != NULL) {
+ if (errbuf[0] == 'y' || errbuf[0] == 'Y') {
+ total_disks = 1;
+ zipmessage(" Assuming single-disk archive", "");
+ }
+ }
+ }
+ if (total_disks == 1000000) {
+ /* assume max */
+ total_disks = 100000;
+ }
+
+ } /* .zip file exists */
+
+ /* Skip reading the Zip64 EOCDL, Zip64 EOCDR, or central directory */
+
+ /* Now read the archive starting with first disk. Find local headers,
+ create entry in zlist, then copy entry to new archive */
+
+ /* Multi-volume file names end in .z01, .z02, ..., .z10, .zip for 11 disk archive */
+
+ /* Unless quiet, always close the in_path disk and ask user for first disk,
+ unless there is an End Of Central Directory record and that says there is
+ only one disk.
+ If quiet, assume the file pointed to is a single file archive to fix. */
+ if (noisy && in_file) {
+ fclose(in_file);
+ in_file = NULL;
+ }
+
+ /* Read the archive disks - no idea how many disks there are
+ since we can't trust the EOCDR and other end records
+ */
+ zipmessage("Scanning for entries...", "");
+
+ for (current_in_disk = 0; current_in_disk < total_disks; current_in_disk++) {
+ /* get the path for this disk */
+ split_path = get_in_split_path(in_path, current_in_disk);
+
+ /* if in_file is not NULL then in_file is already open */
+ if (in_file == NULL) {
+ /* open the split */
+ while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+ int result;
+ /* could not open split */
+
+ /* Ask for directory with split. Updates global variable in_path */
+ result = ask_for_split_read_path(current_in_disk);
+ if (result == ZE_ABORT) {
+ zipwarn("could not find split: ", split_path);
+ return ZE_ABORT;
+ } else if (result == ZE_EOF) {
+ zipmessage_nl("", 1);
+ zipwarn("user ended reading - closing archive", "");
+ return ZE_EOF;
+ } else if (result == ZE_FORM) {
+ /* user asked to skip this disk */
+ zipmessage_nl("", 1);
+ sprintf(errbuf, "skipping disk %lu ...\n", current_in_disk);
+ zipwarn(errbuf, "");
+ skip_disk = 1;
+ break;
+ }
+
+ split_path = get_in_split_path(in_path, current_in_disk);
+ }
+ if (skip_disk) {
+ /* skip this current disk - this works because central directory entries
+ can't be split across splits */
+ skip_disk = 0;
+ skipped_disk = 1;
+ continue;
+ }
+ }
+
+ if (skipped_disk) {
+ /* Not much to do here as between entries. Entries are copied
+ in zipcopy() and that has to handle missing disks while
+ reading data for an entry.
+ */
+ }
+
+ /* Main loop */
+ /* Look for next signature and process it */
+ while (find_next_signature(in_file)) {
+ current_in_offset = zftello(in_file);
+
+ if (is_signature(sigbuf, "PK\05\06")) {
+
+ /* End Of Central Directory Record */
+
+ sprintf(errbuf, "EOCDR found (%2lu %6s)...",
+ current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ zipmessage_nl(errbuf, 1);
+
+
+ } else if (is_signature(sigbuf, "PK\06\06")) {
+
+ /* Zip64 End Of Central Directory Record */
+
+ sprintf(errbuf, "Zip64 EOCDR found (%2lu %6s)...",
+ current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ zipmessage_nl(errbuf, 1);
+
+
+ } else if (is_signature(sigbuf, "PK\06\07")) {
+
+ /* Zip64 End Of Central Directory Locator */
+
+ sprintf(errbuf, "Zip64 EOCDL found (%2lu %6s)...",
+ current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ zipmessage_nl(errbuf, 1);
+
+
+ } else if (is_signature(sigbuf, "PK\03\04")) {
+
+ /* Local Header Record */
+
+
+ if (verbose) {
+ sprintf(errbuf, " Local (%2lu %6s):",
+ current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ zipmessage_nl(errbuf, 0);
+ }
+
+ /* Create zlist entry. Most will be filled in by zipcopy(). */
+
+ if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+ zipwarn("reading central directory", "");
+ return ZE_MEM;
+ }
+
+ z->vem = 0;
+ z->ver = 0;
+ z->flg = 0;
+ z->how = 0;
+ z->tim = 0; /* time and date into one long */
+ z->crc = 0;
+ z->siz = 0;
+ z->len = 0;
+ z->nam = 0; /* used before comparing cen vs. loc */
+ z->cext = 0; /* may be different from z->ext */
+ z->com = 0;
+ z->dsk = 0;
+ z->att = 0;
+ z->atx = 0;
+ z->off = 0;
+ z->dosflag = 0;
+
+ /* Initialize all fields pointing to malloced data to NULL */
+ z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+ z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+ z->uname = z->zuname = z->ouname = NULL;
+#endif
+
+ /* Attempt to copy entry */
+
+ r = zipcopy(z);
+
+ if (in_central_directory) {
+ sprintf(errbuf, "Entry after central directory found (%2lu %6s)...",
+ current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ zipmessage_nl(errbuf, 1);
+ in_central_directory = 0;
+ }
+
+ if (r == ZE_EOF)
+ /* user said no more splits */
+ break;
+ else if (r == ZE_OK) {
+ zcount++;
+ files_total++;
+ bytes_total += z->siz;
+
+ /* Link into list */
+ if (zfiles == NULL)
+ /* first link */
+ x = &zfiles;
+ /* Link into list */
+ *x = z;
+ z->nxt = NULL;
+ x = &z->nxt;
+ }
+
+ } else if (is_signature(sigbuf, "PK\01\02")) {
+
+ /* Central directory header */
+
+
+ /* sort the zlist */
+ if (in_central_directory == 0) {
+ zipmessage("Central Directory found...", "");
+ /* If one or more files, sort by name */
+ if (zcount)
+ {
+ struct zlist far * far *x; /* pointer into zsort array */
+ struct zlist far *z; /* pointer into zfiles linked list */
+ int i = 0;
+ extent zl_size = zcount * sizeof(struct zlist far *);
+
+ if (zl_size / sizeof(struct zlist far *) != zcount ||
+ (x = zsort = (struct zlist far **)malloc(zl_size)) == NULL)
+ return ZE_MEM;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ x[i++] = z;
+ qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp);
+
+ /* Skip Unicode searching */
+ }
+ }
+
+ if (verbose) {
+ sprintf(errbuf, " Cen (%2lu %6s): ",
+ current_in_disk + 1, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ zipmessage_nl(errbuf, 0);
+ }
+
+ in_central_directory = 1;
+
+ /* Read central directory entry */
+
+ /* central directory signature */
+
+ /* The format of a central directory record
+ central file header signature 4 bytes (0x02014b50)
+ version made by 2 bytes
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+ file comment length 2 bytes
+ disk number start 2 bytes
+ internal file attributes 2 bytes
+ external file attributes 4 bytes
+ relative offset of local header 4 bytes
+
+ file name (variable size)
+ extra field (variable size)
+ file comment (variable size)
+ */
+
+ if (fread(scbuf, CENHEAD, 1, in_file) != 1) {
+ zipwarn("reading central directory: ", strerror(errno));
+ zipwarn("bad archive - error reading central directory", "");
+ zipwarn("skipping this entry...", "");
+ continue;
+ }
+
+ if ((cz = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+ zipwarn("reading central directory", "");
+ return ZE_MEM;
+ }
+
+ cz->vem = SH(CENVEM + scbuf);
+ cz->ver = SH(CENVER + scbuf);
+ cz->flg = SH(CENFLG + scbuf);
+ cz->how = SH(CENHOW + scbuf);
+ cz->tim = LG(CENTIM + scbuf); /* time and date into one long */
+ cz->crc = LG(CENCRC + scbuf);
+ cz->siz = LG(CENSIZ + scbuf);
+ cz->len = LG(CENLEN + scbuf);
+ cz->nam = SH(CENNAM + scbuf); /* used before comparing cen vs. loc */
+ cz->cext = SH(CENEXT + scbuf); /* may be different from z->ext */
+ cz->com = SH(CENCOM + scbuf);
+ cz->dsk = SH(CENDSK + scbuf);
+ cz->att = SH(CENATT + scbuf);
+ cz->atx = LG(CENATX + scbuf);
+ cz->off = LG(CENOFF + scbuf);
+ cz->dosflag = (cz->vem & 0xff00) == 0;
+
+ /* Initialize all fields pointing to malloced data to NULL */
+ cz->zname = cz->name = cz->iname = cz->extra = cz->cextra = NULL;
+ cz->comment = cz->oname = NULL;
+#ifdef UNICODE_SUPPORT
+ cz->uname = cz->zuname = cz->ouname = NULL;
+#endif
+
+ /* Read file name, extra field and comment field */
+ if (cz->nam == 0)
+ {
+ sprintf(errbuf, "%lu", (ulg)zcount + 1);
+ zipwarn("zero-length name for entry #", errbuf);
+ zipwarn("skipping this entry...", "");
+ continue;
+ }
+ if ((cz->iname = malloc(cz->nam+1)) == NULL ||
+ (cz->cext && (cz->cextra = malloc(cz->cext + 1)) == NULL) ||
+ (cz->com && (cz->comment = malloc(cz->com + 1)) == NULL))
+ return ZE_MEM;
+ if (fread(cz->iname, cz->nam, 1, in_file) != 1 ||
+ (cz->cext && fread(cz->cextra, cz->cext, 1, in_file) != 1) ||
+ (cz->com && fread(cz->comment, cz->com, 1, in_file) != 1)) {
+ zipwarn("error reading entry: ", strerror(errno));
+ zipwarn("skipping this entry...", "");
+ continue;
+ }
+ cz->iname[cz->nam] = '\0'; /* terminate name */
+
+ /* Look up this name in zlist from local entries */
+ z = zsearch(cz->iname);
+
+
+ if (z && z->tim == cz->tim) {
+
+ /* Apparently as iname and date and time match this central
+ directory entry goes with this zlist entry */
+
+ if (verbose) {
+ /* cen dir name matches a local name */
+ sprintf(errbuf, "updating: %s", cz->iname);
+ zipmessage_nl(errbuf, 0);
+ }
+
+ if (z->crc != cz->crc) {
+ sprintf(errbuf, "local (%lu) and cen (%lu) crc mismatch", z->crc, cz->crc);
+ zipwarn(errbuf, "");
+ }
+
+ z->vem = cz->vem;
+ /* z->ver = cz->ver; */
+ /* z->flg = cz->flg; */
+ /* z->how = cz->how; */
+ /* z->tim = cz->tim; */ /* time and date into one long */
+ /* z->crc = cz->crc; */
+ /* z->siz = cz->siz; */
+ /* z->len = cz->len; */
+ /* z->nam = cz->nam; */ /* used before comparing cen vs. loc */
+ z->cext = cz->cext; /* may be different from z->ext */
+ z->com = cz->com;
+ z->cextra = cz->cextra;
+ z->comment = cz->comment;
+ /* z->dsk = cz->dsk; */
+ z->att = cz->att;
+ z->atx = cz->atx;
+ /* z->off = cz->off; */
+ z->dosflag = cz->dosflag;
+
+#ifdef UNICODE_SUPPORT
+ if (unicode_mismatch != 3 && z->uname == NULL) {
+ if (z->flg & UTF8_BIT) {
+ /* path is UTF-8 */
+ if ((z->uname = malloc(strlen(z->iname) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "reading archive");
+ }
+ strcpy(z->uname, z->iname);
+ } else {
+ /* check for UTF-8 path extra field */
+ read_Unicode_Path_entry(z);
+ }
+ }
+#endif
+
+#ifdef WIN32
+ /* Input path may be OEM */
+ {
+ unsigned hostver = (z->vem & 0xff);
+ Ext_ASCII_TO_Native(z->iname, (z->vem >> 8), hostver,
+ ((z->atx & 0xffff0000L) != 0), FALSE);
+ }
+#endif
+
+#ifdef EBCDIC
+ if (z->com)
+ memtoebc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+#ifdef WIN32
+ /* Comment may be OEM */
+ {
+ unsigned hostver = (z->vem & 0xff);
+ Ext_ASCII_TO_Native(z->comment, (z->vem >> 8), hostver,
+ ((z->atx & 0xffff0000L) != 0), FALSE);
+ }
+#endif
+
+#ifdef ZIP64_SUPPORT
+ /* zip64 support 08/31/2003 R.Nausedat */
+ /* here, we have to read the len, siz etc values from the CD */
+ /* entry as we might have to adjust them regarding their */
+ /* correspronding zip64 extra fields. */
+ /* also, we cannot compare the values from the CD entries with */
+ /* the values from the LH as they might be different. */
+
+ /* adjust/update siz,len and off (to come: dsk) entries */
+ /* PKZIP does not care of the version set in a CDH: if */
+ /* there is a zip64 extra field assigned to a CDH PKZIP */
+ /* uses it, we should do so, too. */
+ /*
+ adjust_zip_central_entry(z);
+ */
+#endif
+
+ /* Update zipbeg beginning of archive offset, prepare for next header */
+/*
+ if (z->dsk == 0 && (!zipbegset || z->off < zipbeg)) {
+ zipbeg = z->off;
+ zipbegset = 1;
+ }
+ zcount++;
+ */
+
+#ifndef UTIL
+ if (verbose)
+ zipoddities(z);
+#endif
+
+ current_offset = zftello(y);
+
+ if (zfseeko(y, z->off, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("writing archive seek: ", strerror(errno));
+ return ZE_WRITE;
+ }
+
+ if (putlocal(z, PUTLOCAL_REWRITE) != ZE_OK)
+ zipwarn("Error rewriting local header", "");
+
+ if (zfseeko(y, current_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("write archive seek: ", strerror(errno));
+ return ZE_WRITE;
+ }
+ offset = zftello(y);
+ if (current_offset != offset) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("seek after local: ", strerror(errno));
+ return ZE_WRITE;
+ }
+
+ if (verbose)
+ zipmessage_nl("", 1);
+
+ } else {
+ /* cen dir name does not match local name */
+ sprintf(errbuf, "no local entry: %s", cz->iname);
+ zipmessage_nl(errbuf, 1);
+ }
+
+ } else if (zfiles == NULL && is_signature(sigbuf, "PK\07\010")) {
+
+ /* assume spanning signature at top of archive */
+ if (total_disks == 1) {
+ zipmessage(" Found spanning marker, but did not expect split (multi-disk) archive...", "");
+
+ } else if (total_disks > 1) {
+ zipmessage(" Found spanning marker - expected as this is split (multi-disk) archive...", "");
+
+ } else {
+ zipmessage(" Found spanning marker - could be split archive...", "");
+
+ }
+
+ } else {
+
+ /* this signature shouldn't be here */
+ int c;
+ char errbuftemp[40];
+
+ strcpy(errbuf, "unexpected signature ");
+ for (c = 0; c < 4; c++) {
+ sprintf(errbuftemp, "%02x ", sigbuf[c]);
+ strcat(errbuf, errbuftemp);
+ }
+ sprintf(errbuftemp, "on disk %lu at %s\n", current_in_disk,
+ zip_fzofft(current_in_offset - 4, NULL, "u"));
+ strcat(errbuf, errbuftemp);
+ zipwarn(errbuf, "");
+ zipwarn("skipping this signature...", "");
+ }
+
+
+ } /* while reading file */
+
+ /* close disk and do next disk */
+ if (in_file)
+ fclose(in_file);
+ in_file = NULL;
+ free(split_path);
+
+ if (r == ZE_EOF)
+ /* user says no more splits */
+ break;
+
+ } /* for each disk */
+
+ return ZE_OK;
+
+} /* end of function scanzipf_fixnew() */
+
+#endif /* !UTIL */
+
+
+
+
+
+
+/* ---------------------- */
+/* New regular scan */
+
+/*
+ * scanzipf_regnew is similar to the orignal scanzipf_reg in that it
+ * reads the end of the archive and goes from there. Unlike that
+ * scan this one stops after reading the central directory and does
+ * not read the local headers. After the directory scan for new
+ * files is done in zip.c the zlist created here is used to read
+ * the old archive entries there. The local headers are read using
+ * readlocal() in zipcopy().
+ *
+ * This scan assumes the zip file is well structured. If not it may
+ * fail and the new scanzipf_fixnew should be used.
+ *
+ * 2006-2-4, 2007-12-10 EG
+ */
+
+local int scanzipf_regnew()
+/*
+ The input path for the .zip file is in in_path. If a split archive,
+ the path for each split is created from the current disk number
+ and in_path. If a split is not in the same directory as the last
+ split we ask the user where it is and update in_path.
+ */
+/*
+ This is old but more or less still applies:
+
+ The name of the zip file is pointed to by the global "zipfile". The globals
+ zipbeg, cenbeg, zfiles, zcount, zcomlen, zcomment, and zsort are filled in.
+ Return an error code in the ZE_ class.
+*/
+{
+ /* In this function, a local buffer is used to read in the following Zip
+ structures:
+ End-of-CentralDir record (EOCDR) (ENDHEAD)
+ Zip64-End-of-CentralDir-Record locator (Zip64 EOCDL) (EC64LOC)
+ Zip64-End-of-CentralDir record (Zip64 EOCDR) (EC64REC)
+ CentralDir-Entry record (CENHEAD)
+ To conserve valuable stack space, this buffer is sized to the largest
+ of these structures.
+ */
+# if CENHEAD > ENDHEAD
+# define SCAN_BUFSIZE CENHEAD /* CENHEAD should be the larger struct */
+# else
+# define SCAN_BUFSIZE ENDHEAD
+# endif
+
+#ifdef ZIP64_SUPPORT
+# if EC64REC > SCAN_BUFSIZE
+# undef SCAN_BUFSIZE
+# define SCAN_BUFSIZE EC64REC /* EC64 record should be largest struct */
+# endif
+# if EC64LOC > SCAN_BUFSIZE
+# undef SCAN_BUFSIZE
+# define SCAN_BUFSIZE EC64LOC
+# endif
+#endif
+
+ char scbuf[SCAN_BUFSIZE]; /* buffer just enough for all header types */
+ char *split_path;
+ ulg eocdr_disk;
+ uzoff_t eocdr_offset;
+# ifdef ZIP64_SUPPORT
+ ulg z64eocdr_disk;
+ uzoff_t z64eocdr_offset;
+ uzoff_t z64eocdr_size;
+ ush version_made;
+ ush version_needed = 0;
+ zoff_t zip64_eocdr_start;
+ zoff_t z64eocdl_offset;
+# endif /* def ZIP64_SUPPORT */
+ uzoff_t cd_total_entries; /* num of entries as read from (Zip64) EOCDR */
+ ulg in_cd_start_disk; /* central directory start disk */
+ uzoff_t in_cd_start_offset; /* offset of start of cd on cd start disk */
+ uzoff_t adjust_offset = 0; /* bytes before first entry (size of sfx prefix) */
+ uzoff_t cd_total_size = 0; /* total size of cd */
+
+
+ int first_CD = 1; /* looking for first CD entry */
+ int zipbegset = 0;
+
+ int skip_disk = 0; /* 1 if user asks to skip current disk */
+ int skipped_disk = 0; /* 1 if skipped start disk and start offset is useless */
+
+ uzoff_t s; /* size of data, start of central */
+ struct zlist far * far *x; /* pointer last entry's link */
+ struct zlist far *z; /* current zip entry structure */
+
+
+ /* open the zipfile */
+ if ((in_file = zfopen(in_path, FOPR)) == NULL) {
+ zipwarn("could not open input archive", in_path);
+ return ZE_OPEN;
+ }
+
+#ifndef ZIP64_SUPPORT
+ /* 2004-12-06 SMS.
+ * Check for too-big file before doing any serious work.
+ */
+ if (ffile_size( in_file) == EOF) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("input file requires Zip64 support: ", in_path);
+ return ZE_ZIP64;
+ }
+#endif /* ndef ZIP64_SUPPORT */
+
+ /* look for End Of Central Directory Record */
+
+ /* In a valid Zip archive, the EOCDR can be at most (64k-1 + ENDHEAD + 4)
+ bytes (=65557 bytes) from the end of the file.
+ We back up 128k, to allow some junk being appended to a Zip file.
+ */
+ if ((zfseeko(in_file, -0x20000L, SEEK_END) != 0) ||
+ /* Some fseek() implementations (e.g. MSC 8.0 16-bit) fail to signal
+ an error when seeking before the beginning of the file.
+ As work-around, we check the position returned by zftello()
+ for the error value -1.
+ */
+ (zftello(in_file) == (zoff_t)-1L)) {
+ /* file is less than 128 KB so back up to beginning */
+ if (zfseeko(in_file, 0L, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to seek in input file ", in_path);
+ return ZE_READ;
+ }
+ }
+
+ /* find EOCD Record signature */
+ if (!find_signature(in_file, "PK\05\06")) {
+ /* No End Of Central Directory Record */
+ fclose(in_file);
+ in_file = NULL;
+ if (fix == 1) {
+ zipwarn("bad archive - missing end signature", "");
+ zipwarn("(If downloaded, was binary mode used? If not, the", "");
+ zipwarn(" archive may be scrambled and not recoverable)", "");
+ zipwarn("Can't use -F to fix (try -FF)", "");
+ } else{
+ zipwarn("missing end signature--probably not a zip file (did you", "");
+ zipwarn("remember to use binary mode when you transferred it?)", "");
+ zipwarn("(if you are trying to read a damaged archive try -F)", "");
+ }
+ return ZE_FORM;
+ }
+
+ /* at start of data after EOCDR signature */
+ eocdr_offset = (uzoff_t) zftello(in_file);
+
+ /* OK, it is possible this is not the last EOCDR signature (might be
+ EOCDR signature from a stored archive in the last 128 KB) and so not
+ the one we want.
+
+ The below assumes the signature does not appear in the assumed ASCII text
+ .ZIP file comment.
+ */
+ while (find_signature(in_file, "PK\05\06")) {
+ /* previous one was not the one */
+ eocdr_offset = (uzoff_t) zftello(in_file);
+ }
+
+ /* found EOCDR */
+ /* format is
+ end of central dir signature 4 bytes (0x06054b50)
+ number of this disk 2 bytes
+ number of the disk with the
+ start of the central directory 2 bytes
+ total number of entries in the
+ central directory on this disk 2 bytes
+ total number of entries in
+ the central directory 2 bytes
+ size of the central directory 4 bytes
+ offset of start of central
+ directory with respect to
+ the starting disk number 4 bytes
+ .ZIP file comment length 2 bytes
+ .ZIP file comment (variable size)
+ */
+
+ if (zfseeko(in_file, eocdr_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to seek in input file ", in_path);
+ return ZE_READ;
+ }
+
+ /* read the EOCDR */
+ s = fread(scbuf, 1, ENDHEAD, in_file);
+
+ /* the first field should be number of this (the last) disk */
+ eocdr_disk = (ulg)SH(scbuf);
+ total_disks = eocdr_disk + 1;
+
+ /* Assume EOCDR disk is this disk. If a lot of disks, the Zip64 field
+ may be needed and this EOCDR field could be set to the Zip64 flag
+ value as the disk number may be bigger than this field can hold.
+ */
+ current_in_disk = total_disks - 1;
+
+ /* Central Directory disk, offset, and total entries */
+ in_cd_start_disk = (ulg)SH(scbuf + ENDBEG);
+ in_cd_start_offset = (uzoff_t)LG(scbuf + ENDOFF);
+ cd_total_entries = (uzoff_t)SH(scbuf + ENDTOT);
+ cd_total_size = (uzoff_t)LG(scbuf + ENDSIZ);
+
+ /* length of zipfile comment */
+ zcomlen = SH(scbuf + ENDCOM);
+ if (zcomlen)
+ {
+ if ((zcomment = malloc(zcomlen + 1)) == NULL)
+ return ZE_MEM;
+ if (fread(zcomment, zcomlen, 1, in_file) != 1)
+ {
+ free((zvoid *)zcomment);
+ zcomment = NULL;
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ zcomment[zcomlen] = '\0';
+#ifdef EBCDIC
+ if (zcomment)
+ memtoebc(zcomment, zcomment, zcomlen);
+#endif /* EBCDIC */
+ }
+
+ if (cd_total_entries == 0) {
+ /* empty archive */
+
+ fclose(in_file);
+ in_file = NULL;
+ return ZE_OK;
+ }
+
+ /* if total disks is other than 1 then multi-disk archive */
+ if (total_disks != 1) {
+ /* zipfile name must end in .zip for split archives */
+ int plen = strlen(in_path);
+ char *in_path_ext;
+
+ if (adjust) {
+ zipwarn("Adjusting split archives not yet supported", "");
+ return ZE_FORM;
+ }
+
+#ifdef VMS
+ /* On VMS, adjust plen (and in_path_ext) to avoid the file version. */
+ plen -= strlen(vms_file_version(in_path));
+#endif /* def VMS */
+ in_path_ext = zipfile + plen - 4;
+
+ if (plen < 4 ||
+ in_path_ext[0] != '.' ||
+ toupper(in_path_ext[1]) != 'Z' ||
+ toupper(in_path_ext[2]) != 'I' ||
+ toupper(in_path_ext[3]) != 'P') {
+ zipwarn("archive name must end in .zip for splits", "");
+ fclose(in_file);
+ in_file = NULL;
+ return ZE_PARMS;
+ }
+ }
+
+ /* if input or output are split archives, must be different archives */
+ if ((total_disks != 1 || split_method) && !show_files &&
+ strcmp(in_path, out_path) == 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("cannot update a split archive (use --out option)", "");
+ return ZE_PARMS;
+ }
+
+ /* if fixing archive, input and output must be different archives */
+ if (fix == 1 && strcmp(in_path, out_path) == 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("must use --out when fixing an archive", "");
+ return ZE_PARMS;
+ }
+
+
+ /* Get sfx offset if adjusting. Above we made sure not split archive. */
+ /* Also check for an offset if fix and single disk archive. */
+ if ((fix == 1 && total_disks == 1) || adjust) {
+ zoff_t cd_start;
+# ifdef ZIP64_SUPPORT
+ zoff_t zip64_eocdr_start;
+# endif
+
+ /* First attempt. If the CD start offset and size are valid in the EOCDR
+ (meaning they are not the Zip64 flag values that say the actual values
+ are in the Zip64 EOCDR), we can use them to get the offset */
+ if (in_cd_start_offset != 0xFFFFFFFF && cd_total_size != 0xFFFFFFFF) {
+ /* Search for start of central directory */
+ /* There still might be a Zip64 EOCDR. This assumes if there is
+ a Zip64 EOCDR, it's version 1 and 52 bytes */
+ cd_start = eocdr_offset - cd_total_size - 24 - 56;
+ if (zfseeko(in_file, cd_start, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ if (fix == 1) {
+ zipwarn("could not seek back to start of central directory: ", strerror(errno));
+ zipwarn("(try -FF)", "");
+ } else {
+ zipwarn("reading archive fseek: ", strerror(errno));
+ }
+ return ZE_FORM;
+ }
+ if (find_signature(in_file, "PK\01\02")) {
+ /* Should now be after first central directory header signature in archive */
+ adjust_offset = zftello(in_file) - 4 - in_cd_start_offset;
+ } else {
+ zipwarn("central dir not where expected - could not adjust offsets", "");
+ zipwarn("(try -FF)", "");
+ return ZE_FORM;
+ }
+ } else {
+
+ /* Second attempt. We need the Zip64 EOCDL to get the offset */
+
+ /*
+ * Check for a Zip64 EOCD Locator signature
+ */
+
+ /* Format of Z64EOCD Locator is
+ zip64 end of central dir locator
+ signature 4 bytes (0x07064b50)
+ number of the disk with the
+ start of the zip64 end of
+ central directory 4 bytes
+ relative offset of the zip64
+ end of central directory record 8 bytes
+ total number of disks 4 bytes
+ */
+
+ /* back up 20 bytes from EOCDR to Z64 EOCDL */
+ if (zfseeko(in_file, eocdr_offset - 24, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ if (fix == 1) {
+ zipwarn("could not seek back to Zip64 EOCDL: ", strerror(errno));
+ zipwarn("(try -FF)", "");
+ } else {
+ zipwarn("reading archive fseek: ", strerror(errno));
+ }
+ return ZE_FORM;
+ }
+ if (at_signature(in_file, "PK\06\07"))
+#ifndef ZIP64_SUPPORT
+ {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("found Zip64 signature - this may be a Zip64 archive", "");
+ zipwarn("Need PKZIP 4.5 or later compatible zip", "");
+ zipwarn("Set ZIP64_SUPPORT in Zip 3", "");
+ return ZE_ZIP64;
+ }
+#else /* ZIP64_SUPPORT */
+ {
+ z64eocdl_offset = zftello(in_file) - 4;
+
+ /* read Z64 EOCDL */
+ if (fread(scbuf, EC64LOC, 1, in_file) != 1) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("reading archive: ", strerror(errno));
+ return ZE_READ;
+ }
+ /* now should be back at the EOCD signature */
+ if (!at_signature(in_file, "PK\05\06")) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to read EOCD after seek: ", in_path);
+ return ZE_READ;
+ }
+
+ /* read disk and offset to Zip64 EOCDR and total disks */
+ z64eocdr_disk = LG(scbuf);
+ z64eocdr_offset = LLG(scbuf + 4);
+ total_disks = LG(scbuf + 12);
+
+ /* For now no split archives */
+ if (total_disks != 1) {
+ zipwarn("Adjusting split archives not supported: ", in_path);
+ zipwarn("(try -FF)", "");
+ return ZE_FORM;
+ }
+
+ /* go to the Zip64 EOCDR */
+ if (zfseeko(in_file, z64eocdr_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("reading archive fseek: ", strerror(errno));
+ return ZE_FORM;
+ }
+ /* Should be at Zip64 EOCDR signature */
+ if (at_signature(in_file, "PK\06\06")) {
+ /* apparently no offset */
+
+ } else {
+ /* Wasn't there, so calculate based on Zip64 EOCDL offset */
+
+ zip64_eocdr_start = z64eocdl_offset - 24 - 56;
+ if (zfseeko(in_file, zip64_eocdr_start, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ if (fix == 1) {
+ zipwarn("could not seek back to Zip64 EOCDR: ", strerror(errno));
+ zipwarn("(try -FF)", "");
+ } else {
+ zipwarn("reading archive fseek: ", strerror(errno));
+ }
+ return ZE_FORM;
+ }
+ if (find_next_signature(in_file) && is_signature(sigbuf, "PK\06\06")) {
+ /* Should now be after Zip64 EOCDR signature in archive */
+ adjust_offset = zftello(in_file) - 4 - z64eocdr_offset;
+ } else {
+ zipwarn("Could not determine offset of entries", "");
+ zipwarn("(try -FF)", "");
+ return ZE_FORM;
+ }
+ }
+ }
+#endif
+ }
+ if (noisy) {
+ if (adjust_offset) {
+ sprintf(errbuf, "Zip entry offsets appear off by %s bytes - correcting...",
+ zip_fzofft(adjust_offset, NULL, NULL));
+ } else {
+ sprintf(errbuf, "Zip entry offsets do not need adjusting");
+ }
+ zipmessage(errbuf, "");
+ }
+ }
+
+
+ /*
+ * Check for a Zip64 EOCD Locator signature
+ */
+
+ /* Format of Z64EOCD Locator is
+ zip64 end of central dir locator
+ signature 4 bytes (0x07064b50)
+ number of the disk with the
+ start of the zip64 end of
+ central directory 4 bytes
+ relative offset of the zip64
+ end of central directory record 8 bytes
+ total number of disks 4 bytes
+ */
+
+ /* back up 20 bytes from EOCDR to Z64 EOCDL */
+ if (zfseeko(in_file, eocdr_offset - 24, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ if (fix == 1) {
+ zipwarn("bad archive - could not seek back to Zip64 EOCDL: ", strerror(errno));
+ zipwarn("(try -FF)", "");
+ } else {
+ zipwarn("reading archive fseek: ", strerror(errno));
+ }
+ return ZE_FORM;
+ }
+ if (at_signature(in_file, "PK\06\07"))
+#ifndef ZIP64_SUPPORT
+ {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("found Zip64 signature - this may be a Zip64 archive", "");
+ zipwarn("Need PKZIP 4.5 or later compatible zip", "");
+ zipwarn("Set ZIP64_SUPPORT in Zip 3", "");
+ return ZE_ZIP64;
+ }
+#else /* ZIP64_SUPPORT */
+ {
+ z64eocdl_offset = zftello(in_file) - 4;
+ /* read Z64 EOCDL */
+ if (fread(scbuf, EC64LOC, 1, in_file) != 1) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("reading archive: ", strerror(errno));
+ return ZE_READ;
+ }
+ /* now should be back at the EOCD signature */
+ if (!at_signature(in_file, "PK\05\06")) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to read EOCD after seek: ", in_path);
+ return ZE_READ;
+ }
+
+ /* read disk and offset to Zip64 EOCDR and total disks */
+ z64eocdr_disk = LG(scbuf);
+ z64eocdr_offset = LLG(scbuf + 4) + adjust_offset;
+ total_disks = LG(scbuf + 12);
+
+ /* set the current disk */
+ current_in_disk = total_disks - 1;
+
+ /* Now need to read the Zip64 EOCD Record to get version needed
+ to extract */
+
+ if (z64eocdr_disk != total_disks - 1) {
+ /* Zip64 EOCDR not on this disk */
+
+ /* done with this disk (since apparently there are no CD entries
+ on it) */
+ fclose(in_file);
+ in_file = NULL;
+
+ /* get the path for the disk with the Zip64 EOCDR */
+ split_path = get_in_split_path(in_path, z64eocdr_disk);
+
+ while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+ /* could not open split */
+
+ /* Ask where this split is. This call also updates global in_path. */
+ if (ask_for_split_read_path(z64eocdr_disk) != ZE_OK) {
+ return ZE_ABORT;
+ }
+ free(split_path);
+ split_path = get_in_split_path(in_path, z64eocdr_disk);
+ }
+ free(split_path);
+ }
+
+ current_in_disk = z64eocdr_disk;
+
+ /* go to the Zip64 EOCDR */
+ if (zfseeko(in_file, z64eocdr_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("reading archive fseek: ", strerror(errno));
+ return ZE_FORM;
+ }
+ /* Should be at Zip64 EOCDR signature */
+ if (!at_signature(in_file, "PK\06\06")) {
+ /* Wasn't there, so calculate based on Zip64 EOCDL offset */
+ zip64_eocdr_start = z64eocdl_offset - 24 - 56;
+ if (zfseeko(in_file, zip64_eocdr_start, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ if (fix == 1) {
+ zipwarn("bad archive - could not seek back to Zip64 EOCDR: ", strerror(errno));
+ zipwarn("(try -FF)", "");
+ } else {
+ zipwarn("reading archive fseek: ", strerror(errno));
+ }
+ return ZE_FORM;
+ }
+ if (find_next_signature(in_file) && is_signature(sigbuf, "PK\06\06")) {
+ /* Should now be after Zip64 EOCDR signature in archive */
+ adjust_offset = zftello(in_file) - 4 - z64eocdr_offset;
+ zipwarn("Zip64 EOCDR not found where expected - compensating", "");
+ zipwarn("(try -A to adjust offsets)", "");
+ } else {
+ fclose(in_file);
+ in_file = NULL;
+ if (fix == 1) {
+ zipwarn("bad archive - Zip64 EOCDR not found in split: ", in_path);
+ zipwarn("(try -FF)", "");
+ } else {
+ zipwarn("Zip64 End Of Central Directory Record not found: ", in_path);
+ }
+ return ZE_FORM;
+ }
+ }
+
+ /*
+ * Read the Z64 End Of Central Directory Record
+ */
+
+ /* The format of the Z64 EOCDR is
+ zip64 end of central dir
+ signature 4 bytes (0x06064b50)
+ size of zip64 end of central
+ directory record 8 bytes
+ version made by 2 bytes
+ version needed to extract 2 bytes
+ number of this disk 4 bytes
+ number of the disk with the
+ start of the central directory 4 bytes
+ total number of entries in the
+ central directory on this disk 8 bytes
+ total number of entries in the
+ central directory 8 bytes
+ size of the central directory 8 bytes
+ offset of start of central
+ directory with respect to
+ the starting disk number 8 bytes
+ (version 2 of the Zip64 EOCDR has more after this)
+ zip64 extensible data sector (variable size)
+ */
+
+ /* read the first 52 bytes of the Zip64 EOCDR (we don't support
+ version 2, which supports PKZip licensed features)
+ */
+ s = fread(scbuf, 1, EC64REC, in_file);
+ if (s < EC64REC) {
+ if (fix == 1) {
+ zipwarn("bad archive - Zip64 EOCDR bad or truncated", "");
+ zipwarn("(try -FF)", "");
+ } else {
+ zipwarn("Zip64 EOCD Record bad or truncated", "");
+ }
+ fclose(in_file);
+ in_file = NULL;
+ return ZE_FORM;
+ }
+ z64eocdr_size = LLG(scbuf);
+ version_made = SH(scbuf + 8);
+ version_needed = SH(scbuf + 10);
+ in_cd_start_disk = LG(scbuf + 16);
+ cd_total_entries = LLG(scbuf + 28);
+ in_cd_start_offset = LLG(scbuf + 44) + adjust_offset;
+
+ if (version_needed > 46) {
+ int major = version_needed / 10;
+ int minor = version_needed - (major * 10);
+ sprintf(errbuf, "This archive requires version %d.%d", major, minor);
+ zipwarn(errbuf, "");
+ zipwarn("Zip currently only supports up to version 4.6 archives", "");
+ zipwarn("(up to 4.5 if bzip2 is not compiled in)", "");
+ if (fix == 1)
+ zipwarn("If -F fails try -FF to try to salvage something", "");
+ else if (fix == 2)
+ zipwarn("Attempting to salvage what can", "");
+ else {
+ zipwarn("Try -F to attempt to read anyway", "");
+ fclose(in_file);
+ in_file = NULL;
+ return ZE_FORM;
+ }
+ }
+ }
+#endif /* ?ZIP64_SUPPORT */
+
+ /* Now read the central directory and create the zlist */
+
+ /* Multi-volume file names end in .z01, .z02, ..., .z10, .zip for 11 disk archive */
+
+ in_cd_start_offset += adjust_offset;
+ cenbeg = in_cd_start_offset;
+ zipbegset = 0;
+ zipbeg = 0;
+ first_CD = 1;
+
+ /* if the central directory starts on other than this disk, close this disk */
+ if (current_in_disk != in_cd_start_disk) {
+ /* close current disk */
+ fclose(in_file);
+ in_file = NULL;
+ }
+
+ /* Read the disks with the central directory in order - usually the
+ central directory fits on the last disk, but it doesn't have to.
+ */
+ for (current_in_disk = in_cd_start_disk;
+ current_in_disk < total_disks;
+ current_in_disk++) {
+ /* get the path for this disk */
+ if (current_in_disk == total_disks - 1) {
+ /* last disk is archive.zip */
+ if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+ zipwarn("reading archive: ", in_path);
+ return ZE_MEM;
+ }
+ strcpy(split_path, in_path);
+ } else {
+ /* other disks are archive.z01, archive.z02, ... */
+ split_path = get_in_split_path(in_path, current_in_disk);
+ }
+
+ /* if in_file is not NULL then in_file is already open */
+ if (in_file == NULL) {
+ /* open the split */
+ while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+ int result;
+ /* could not open split */
+
+ /* Ask for directory with split. Updates global variable in_path */
+ result = ask_for_split_read_path(current_in_disk);
+ if (result == ZE_ABORT) {
+ zipwarn("could not find split: ", split_path);
+ return ZE_ABORT;
+ } else if (result == ZE_FORM) {
+ /* user asked to skip this disk */
+ sprintf(errbuf, "skipping disk %lu ...\n", current_in_disk);
+ zipwarn(errbuf, "");
+ skip_disk = 1;
+ break;
+ }
+
+ if (current_in_disk == total_disks - 1) {
+ /* last disk is archive.zip */
+ if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
+ zipwarn("reading archive: ", in_path);
+ return ZE_MEM;
+ }
+ strcpy(split_path, in_path);
+ } else {
+ /* other disks are archive.z01, archive.z02, ... */
+ split_path = get_in_split_path(zipfile, current_in_disk);
+ }
+ }
+ if (skip_disk) {
+ /* skip this current disk - this works because central directory entries
+ can't be split across splits */
+ skip_disk = 0;
+ skipped_disk = 1;
+ continue;
+ }
+ }
+
+ if (skipped_disk) {
+ /* skipped start CD disk so start searching for CD signature at start of disk */
+ first_CD = 0;
+ } else {
+ /* seek to the first CD entry */
+ if (first_CD) {
+ if (zfseeko(in_file, in_cd_start_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("unable to seek in input file ", split_path);
+ return ZE_READ;
+ }
+ first_CD = 0;
+ x = &zfiles; /* first link */
+ }
+ }
+
+ /* Main loop */
+ /* Look for next signature and process it */
+ while (find_next_signature(in_file)) {
+ current_in_offset = zftello(in_file);
+
+ if (is_signature(sigbuf, "PK\05\06")) {
+ /* End Of Central Directory Record */
+ /*
+ fprintf(mesg, "EOCDR signature at %d / %I64d\n",
+ current_in_disk, current_in_offset - 4);
+ */
+ break;
+
+ } else if (is_signature(sigbuf, "PK\06\06")) {
+ /* Zip64 End Of Central Directory Record */
+ /*
+ fprintf(mesg, "Zip64 EOCDR signature at %d / %I64d\n",
+ current_in_disk, current_in_offset - 4);
+ */
+ break;
+
+ } else if (!is_signature(sigbuf, "PK\01\02")) {
+ /* Not Central Directory Record */
+
+ /* this signature shouldn't be here */
+ if (fix == 1) {
+ int c;
+ char errbuftemp[40];
+
+ strcpy(errbuf, "bad archive - unexpected signature ");
+ for (c = 0; c < 4; c++) {
+ sprintf(errbuftemp, "%02x ", sigbuf[c]);
+ strcat(errbuf, errbuftemp);
+ }
+ sprintf(errbuftemp, "on disk %lu at %s\n", current_in_disk,
+ zip_fzofft(current_in_offset - 4, NULL, "u"));
+ strcat(errbuf, errbuftemp);
+ zipwarn(errbuf, "");
+ zipwarn("skipping this signature...", "");
+ continue;
+ } else {
+ sprintf(errbuf, "unexpected signature on disk %lu at %s\n",
+ current_in_disk, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ zipwarn(errbuf, "");
+ zipwarn("archive not in correct format: ", split_path);
+ zipwarn("(try -F to attempt recovery)", "");
+ fclose(in_file);
+ in_file = NULL;
+ return ZE_FORM;
+ }
+ }
+
+ /* central directory signature */
+ if (verbose && fix == 1) {
+ fprintf(mesg, "central directory header signature on disk %lu at %s\n",
+ current_in_disk, zip_fzofft(current_in_offset - 4, NULL, "u"));
+ }
+
+ /* The format of a central directory record
+ central file header signature 4 bytes (0x02014b50)
+ version made by 2 bytes
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+ file comment length 2 bytes
+ disk number start 2 bytes
+ internal file attributes 2 bytes
+ external file attributes 4 bytes
+ relative offset of local header 4 bytes
+
+ file name (variable size)
+ extra field (variable size)
+ file comment (variable size)
+ */
+
+ if (fread(scbuf, CENHEAD, 1, in_file) != 1) {
+ zipwarn("reading central directory: ", strerror(errno));
+ if (fix == 1) {
+ zipwarn("bad archive - error reading central directory", "");
+ zipwarn("skipping this entry...", "");
+ continue;
+ } else {
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ }
+
+ if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+ zipwarn("reading central directory", "");
+ return ZE_MEM;
+ }
+
+ z->vem = SH(CENVEM + scbuf);
+ z->ver = SH(CENVER + scbuf);
+ z->flg = SH(CENFLG + scbuf);
+ z->how = SH(CENHOW + scbuf);
+ z->tim = LG(CENTIM + scbuf); /* time and date into one long */
+ z->crc = LG(CENCRC + scbuf);
+ z->siz = LG(CENSIZ + scbuf);
+ z->len = LG(CENLEN + scbuf);
+ z->nam = SH(CENNAM + scbuf); /* used before comparing cen vs. loc */
+ z->cext = SH(CENEXT + scbuf); /* may be different from z->ext */
+ z->com = SH(CENCOM + scbuf);
+ z->dsk = SH(CENDSK + scbuf);
+ z->att = SH(CENATT + scbuf);
+ z->atx = LG(CENATX + scbuf);
+ z->off = LG(CENOFF + scbuf); /* adjust_offset is added below */
+ z->dosflag = (z->vem & 0xff00) == 0;
+
+ /* Initialize all fields pointing to malloced data to NULL */
+ z->zname = z->name = z->iname = z->extra = z->cextra = z->comment = NULL;
+ z->oname = NULL;
+#ifdef UNICODE_SUPPORT
+ z->uname = z->zuname = z->ouname = NULL;
+#endif
+
+ /* Read file name, extra field and comment field */
+ if (z->nam == 0)
+ {
+ sprintf(errbuf, "%lu", (ulg)zcount + 1);
+ zipwarn("zero-length name for entry #", errbuf);
+ if (fix == 1) {
+ zipwarn("skipping this entry...", "");
+ continue;
+ }
+#ifndef DEBUG
+ return ZE_FORM;
+#endif
+ }
+ if ((z->iname = malloc(z->nam+1)) == NULL ||
+ (z->cext && (z->cextra = malloc(z->cext)) == NULL) ||
+ (z->com && (z->comment = malloc(z->com)) == NULL))
+ return ZE_MEM;
+ if (fread(z->iname, z->nam, 1, in_file) != 1 ||
+ (z->cext && fread(z->cextra, z->cext, 1, in_file) != 1) ||
+ (z->com && fread(z->comment, z->com, 1, in_file) != 1)) {
+ if (fix == 1) {
+ zipwarn("error reading entry: ", strerror(errno));
+ zipwarn("skipping this entry...", "");
+ continue;
+ }
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ }
+ z->iname[z->nam] = '\0'; /* terminate name */
+#ifdef UNICODE_SUPPORT
+ if (unicode_mismatch != 3) {
+ if (z->flg & UTF8_BIT) {
+ char *iname;
+ /* path is UTF-8 */
+ if ((z->uname = malloc(strlen(z->iname) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(z->uname, z->iname);
+ /* Create a local name. If UTF-8 system this should also be UTF-8 */
+ iname = utf8_to_local_string(z->uname);
+ if (iname) {
+ free(z->iname);
+ z->iname = iname;
+ }
+ else
+ zipwarn("illegal UTF-8 name: ", z->uname);
+ } else {
+ /* check for UTF-8 path extra field */
+ read_Unicode_Path_entry(z);
+ }
+ }
+#endif
+
+#ifdef WIN32
+ /* Input path may be OEM */
+ {
+ unsigned hostver = (z->vem & 0xff);
+ Ext_ASCII_TO_Native(z->iname, (z->vem >> 8), hostver,
+ ((z->atx & 0xffff0000L) != 0), FALSE);
+ }
+#endif
+
+#ifdef EBCDIC
+ if (z->com)
+ memtoebc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+#ifdef WIN32
+ /* Comment may be OEM */
+ {
+ unsigned hostver = (z->vem & 0xff);
+ Ext_ASCII_TO_Native(z->comment, (z->vem >> 8), hostver,
+ ((z->atx & 0xffff0000L) != 0), FALSE);
+ }
+#endif
+
+#ifdef ZIP64_SUPPORT
+ /* zip64 support 08/31/2003 R.Nausedat */
+ /* here, we have to read the len, siz etc values from the CD */
+ /* entry as we might have to adjust them regarding their */
+ /* correspronding zip64 extra fields. */
+ /* also, we cannot compare the values from the CD entries with */
+ /* the values from the LH as they might be different. */
+
+ /* adjust/update siz,len and off (to come: dsk) entries */
+ /* PKZIP does not care of the version set in a CDH: if */
+ /* there is a zip64 extra field assigned to a CDH PKZIP */
+ /* uses it, we should do so, too. */
+ adjust_zip_central_entry(z);
+#endif
+ /* if adjusting for sfx prefix, add the offset */
+ if ((fix ==1 && total_disks == 1) || adjust) z->off += adjust_offset;
+
+ /* Update zipbeg beginning of archive offset, prepare for next header */
+ if (z->dsk == 0 && (!zipbegset || z->off < zipbeg)) {
+ zipbeg = z->off;
+ zipbegset = 1;
+ }
+ zcount++;
+
+ /* Clear actions */
+ z->mark = 0;
+ z->trash = 0;
+#if defined(UNICODE_SUPPORT) && !defined(UTIL)
+ z->zname = in2ex(z->iname); /* convert to external name */
+ if (z->zname == NULL)
+ return ZE_MEM;
+ if ((z->name = malloc(strlen(z->zname) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(z->name, z->zname);
+ z->oname = local_to_display_string(z->iname);
+
+# ifdef WIN32
+ z->namew = NULL;
+ z->inamew = NULL;
+ z->znamew = NULL;
+# endif
+
+ if (unicode_mismatch != 3) {
+ if (z->uname) {
+ /* create zuname which is alternate zname for matching based on
+ converted Unicode name */
+ char *name;
+
+ /* Convert UTF-8 to current local character set */
+ name = utf8_to_local_string(z->uname);
+
+ if (name == NULL) {
+ /*
+ zipwarn("illegal UTF-8 name: ", z->uname);
+ */
+ /* not able to convert name, so use iname */
+ if ((name = malloc(strlen(z->iname) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(name, z->iname);
+ }
+
+# ifdef EBCDIC
+ /* z->zname is used for printing and must be coded in native charset */
+ strtoebc(z->zuname, name);
+# else /* !EBCDIC */
+ if ((z->zuname = malloc(strlen(name) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(z->zuname, name);
+ /* For output to terminal */
+ if (unicode_escape_all) {
+ char *ouname;
+ /* Escape anything not 7-bit ASCII */
+ ouname = utf8_to_escape_string(z->uname);
+ if (ouname)
+ z->ouname = ouname;
+ else {
+ if ((z->ouname = malloc(strlen(name) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(z->ouname, name);
+ }
+ } else {
+ if ((z->ouname = malloc(strlen(name) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(z->ouname, name);
+ }
+# ifdef WIN32
+
+ if (!no_win32_wide) {
+ z->inamew = utf8_to_wchar_string(z->uname);
+ z->znamew = in2exw(z->inamew); /* convert to external name */
+ if (z->znamew == NULL)
+ return ZE_MEM;
+ }
+
+ local_to_oem_string(z->ouname, z->ouname);
+ /* For matching. There seems to be something lost
+ in the translation from displaying a name in a
+ console window using zip -su on Win32 and using
+ that name in a command line to match what's in
+ the archive. This is klugy though.
+ */
+ if ((z->wuname = malloc(strlen(z->ouname) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(z->wuname, z->ouname);
+ oem_to_local_string(z->wuname, z->wuname);
+# endif /* WIN32 */
+# endif /* ?EBCDIC */
+ } else {
+ /* no uname */
+# ifdef WIN32
+ if (!no_win32_wide) {
+ z->inamew = local_to_wchar_string(z->iname);
+ z->znamew = in2exw(z->inamew); /* convert to external name */
+ if (z->znamew == NULL)
+ return ZE_MEM;
+ }
+# endif
+ }
+ }
+#else /* !(UNICODE_SUPPORT && !UTIL) */
+# ifdef UTIL
+/* We only need z->iname in the utils */
+ z->name = z->iname;
+# ifdef EBCDIC
+/* z->zname is used for printing and must be coded in native charset */
+ if ((z->zname = malloc(z->nam+1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strtoebc(z->zname, z->iname);
+# else
+ z->zname = z->iname;
+# endif
+# else /* !UTIL */
+ z->zname = in2ex(z->iname); /* convert to external name */
+ if (z->zname == NULL)
+ return ZE_MEM;
+ z->name = z->zname;
+# endif /* ?UTIL */
+ if ((z->oname = malloc(strlen(z->zname) + 1)) == NULL) {
+ zipwarn("could not allocate memory: scanzipf_reg", "");
+ return ZE_MEM;
+ }
+ strcpy(z->oname, z->zname);
+#endif /* ?(UNICODE_SUPPORT && !UTIL) */
+
+#ifndef UTIL
+ if (verbose && fix == 0)
+ zipoddities(z);
+#endif
+
+ /* Link into list */
+ *x = z;
+ z->nxt = NULL;
+ x = &z->nxt;
+
+ } /* while reading file */
+
+ /* close disk and do next disk */
+ fclose(in_file);
+ in_file = NULL;
+ free(split_path);
+
+ if (!is_signature(sigbuf, "PK\01\02")) {
+ /* if the last signature is not a CD signature and we get here then
+ hit either the Zip64 EOCDR or the EOCDR and done */
+ break;
+ }
+
+ } /* for each disk */
+
+ if (zcount != cd_total_entries) {
+ sprintf(errbuf, "expected %s entries but found %s",
+ zip_fzofft(cd_total_entries, NULL, "u"),
+ zip_fzofft(zcount, NULL, "u"));
+ zipwarn(errbuf, "");
+ return ZE_FORM;
+ }
+
+ return ZE_OK;
+
+} /* end of function scanzipf_regnew() */
+
+
+
+
+
+
+
+
+/* ---------------------- */
+
+
+
+
+/*
+ * readzipfile initializes the global variables that hold the zipfile
+ * directory info and opens the zipfile. For the actual zipfile scan,
+ * the subroutine scanzipf_reg() or scanzipf_fix() is called,
+ * depending on the mode of operation (regular processing, or zipfix mode).
+ */
+int readzipfile()
+/*
+ The name of the zip file is pointed to by the global "zipfile".
+ The globals zipbeg, zfiles, zcount, and zcomlen are initialized.
+ Return an error code in the ZE_ class.
+*/
+{
+ FILE *f; /* zip file */
+ int retval; /* return code */
+ int readable; /* 1 if zipfile exists and is readable */
+
+ /* Initialize zip file info */
+ zipbeg = 0;
+ zfiles = NULL; /* Points to first header */
+ zcount = 0; /* number of files */
+ zcomlen = 0; /* zip file comment length */
+ retval = ZE_OK;
+ f = NULL; /* shut up some compilers */
+ zipfile_exists = 0;
+
+ /* If zip file exists, read headers and check structure */
+#ifdef VMS
+ if (zipfile == NULL || !(*zipfile) || !strcmp(zipfile, "-"))
+ return ZE_OK;
+ {
+ int rtype;
+
+ if ((VMSmunch(zipfile, GET_RTYPE, (char *)&rtype) == RMS$_NORMAL) &&
+ (rtype == FAT$C_VARIABLE)) {
+ fprintf(mesg,
+ "\n Error: zipfile is in variable-length record format. Please\n\
+ run \"bilf b %s\" to convert the zipfile to fixed-length\n\
+ record format.\n\n", zipfile);
+ return ZE_FORM;
+ }
+ }
+ readable = ((f = zfopen(zipfile, FOPR)) != NULL);
+#else /* !VMS */
+ readable = (zipfile != NULL && *zipfile && strcmp(zipfile, "-"));
+ if (readable) {
+ readable = ((f = zfopen(zipfile, FOPR)) != NULL);
+ }
+#endif /* ?VMS */
+
+ /* skip check if streaming */
+ if (!readable) {
+ if (!zip_to_stdout && fix != 2 && strcmp(in_path, out_path)) {
+ /* If -O used then in_path must exist */
+ if (fix == 1)
+ zipwarn("No .zip file found\n ",
+ "(If all you have are splits (.z01, .z02, ...) and no .zip, try -FF)");
+ ZIPERR(ZE_OPEN, zipfile);
+ }
+ } else {
+ zipfile_exists = 1;
+ }
+
+#ifdef MVS
+ /* Very nasty special case for MVS. Just because the zipfile has been
+ * opened for reading does not mean that we can actually read the data.
+ * Typical JCL to create a zipfile is
+ *
+ * //ZIPFILE DD DISP=(NEW,CATLG),DSN=prefix.ZIP,
+ * // SPACE=(CYL,(10,10))
+ *
+ * That creates a VTOC entry with an end of file marker (DS1LSTAR) of zero.
+ * Alas the VTOC end of file marker is only used when the file is opened in
+ * append mode. When a file is opened in read mode, the "other" end of file
+ * marker is used, a zero length data block signals end of file when reading.
+ * With a brand new file which has not been written to yet, it is undefined
+ * what you read off the disk. In fact you read whatever data was in the same
+ * disk tracks before the zipfile was allocated. You would be amazed at the
+ * number of application programmers who still do not understand this. Makes
+ * for interesting and semi-random errors, GIGO.
+ *
+ * Newer versions of SMS will automatically write a zero length block when a
+ * file is allocated. However not all sites run SMS or they run older levels
+ * so we cannot rely on that. The only safe thing to do is close the file,
+ * open in append mode (we already know that the file exists), close it again,
+ * reopen in read mode and try to read a data block. Opening and closing in
+ * append mode will write a zero length block where DS1LSTAR points, making
+ * sure that the VTOC and internal end of file markers are in sync. Then it
+ * is safe to read data. If we cannot read one byte of data after all that,
+ * it is a brand new zipfile and must not be read.
+ */
+ if (readable)
+ {
+ char c;
+ fclose(f);
+ /* append mode */
+ if ((f = zfopen(zipfile, "ab")) == NULL) {
+ ZIPERR(ZE_OPEN, zipfile);
+ }
+ fclose(f);
+ /* read mode again */
+ if ((f = zfopen(zipfile, FOPR)) == NULL) {
+ ZIPERR(ZE_OPEN, zipfile);
+ }
+ if (fread(&c, 1, 1, f) != 1) {
+ /* no actual data */
+ readable = 0;
+ fclose(f);
+ }
+ else{
+ fseek(f, 0, SEEK_SET); /* at least one byte in zipfile, back to the start */
+ }
+ }
+#endif /* MVS */
+
+ /* ------------------------ */
+ /* new file read */
+
+
+
+#ifndef UTIL
+ if (fix == 2) {
+ scanzipf_fixnew();
+ }
+ else
+#endif
+ if (readable)
+ {
+ /* close file as the new scan opens the splits as needed */
+ fclose(f);
+# ifndef UTIL
+ retval = (fix == 2 && !adjust) ? scanzipf_fixnew() : scanzipf_regnew();
+# else
+ retval = scanzipf_regnew();
+# endif
+ }
+
+ if (fix != 2 && readable)
+ {
+ /* If one or more files, sort by name */
+ if (zcount)
+ {
+ struct zlist far * far *x; /* pointer into zsort array */
+ struct zlist far *z; /* pointer into zfiles linked list */
+ extent zl_size = zcount * sizeof(struct zlist far *);
+
+ if (zl_size / sizeof(struct zlist far *) != zcount ||
+ (x = zsort = (struct zlist far **)malloc(zl_size)) == NULL)
+ return ZE_MEM;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ *x++ = z;
+ qsort((char *)zsort, zcount, sizeof(struct zlist far *), zqcmp);
+
+#ifdef UNICODE_SUPPORT
+ /* sort by zuname (local conversion of UTF-8 name) */
+ if (zl_size / sizeof(struct zlist far *) != zcount ||
+ (x = zusort = (struct zlist far **)malloc(zl_size)) == NULL)
+ return ZE_MEM;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ *x++ = z;
+ qsort((char *)zusort, zcount, sizeof(struct zlist far *), zuqcmp);
+#endif
+ }
+ }
+
+ /* ------------------------ */
+
+ return retval;
+} /* end of function readzipfile() */
+
+
+int putlocal(z, rewrite)
+ struct zlist far *z; /* zip entry to write local header for */
+ int rewrite; /* did seek to rewrite */
+/* Write a local header described by *z to file *f. Return an error code
+ in the ZE_ class. */
+{
+ /* If any of compressed size (siz), uncompressed size (len), offset(off), or
+ disk number (dsk) is larger than can fit in the below standard fields then a
+ Zip64 flag value is stored and a Zip64 extra field is created.
+ Only siz and len are in the local header while all can be in the central
+ directory header.
+
+ For the local header if the extra field is created must store both
+ uncompressed and compressed sizes.
+
+ This assumes that for large entries the compressed size won't need a
+ Zip64 extra field if the uncompressed size did not. This assumption should
+ only fail for a large file of nearly totally uncompressable data.
+
+ If streaming stdin in and use_descriptors is set then always create a Zip64
+ extra field flagging the data descriptor as being in Zip64 format. This is
+ needed as don't know if need Zip64 or not when need to set Zip64 flag in
+ local header.
+
+ If rewrite is set then don't count bytes written for splits
+ */
+ char *block = NULL; /* mem block to write to */
+ extent offset = 0; /* offset into block */
+ extent blocksize = 0; /* size of block */
+#ifdef UNICODE_SUPPORT
+ ush nam = z->nam; /* size of name to write to header */
+ int use_uname = 0; /* write uname to header */
+#endif
+#ifdef ZIP64_SUPPORT
+ int streaming_in = 0; /* streaming stdin */
+ int was_zip64 = 0;
+
+ /* If input is stdin then streaming stdin. No problem with that.
+
+ The problem is updating the local header data in the output once the sizes
+ and crc are known. If the output is not seekable, then need data descriptors
+ and also need to assume Zip64 will be needed as don't know yet. Even if the
+ output is seekable, if the input is streamed need to write the Zip64 extra field
+ before writing the data or there won't be room for it later if we need it.
+ */
+ streaming_in = (strcmp(z->name, "-") == 0);
+
+ if (!rewrite) {
+ zip64_entry = 0;
+ /* initial local header */
+ if (z->siz > ZIP_UWORD32_MAX || z->len > ZIP_UWORD32_MAX ||
+ force_zip64 == 1 || (force_zip64 != 0 && streaming_in))
+ {
+ /* assume Zip64 */
+ if (force_zip64 == 0) {
+ zipwarn("Entry too big:", z->oname);
+ ZIPERR(ZE_BIG, "Large entry support disabled with -fz- but needed");
+ }
+ zip64_entry = 1; /* header of this entry has a field needing Zip64 */
+ if (z->ver < ZIP64_MIN_VER)
+ z->ver = ZIP64_MIN_VER;
+ was_zip64 = 1;
+ }
+ } else {
+ /* rewrite */
+ was_zip64 = zip64_entry;
+ zip64_entry = 0;
+ if (z->siz > ZIP_UWORD32_MAX || z->len > ZIP_UWORD32_MAX ||
+ force_zip64 == 1 || (force_zip64 != 0 && streaming_in))
+ {
+ /* Zip64 entry */
+ zip64_entry = 1;
+ }
+ if (force_zip64 == 0 && zip64_entry) {
+ /* tried to force into standard entry but needed Zip64 entry */
+ zipwarn("Entry too big:", z->oname);
+ ZIPERR(ZE_BIG, "Large entry support disabled with -fz- but entry needs");
+ }
+ /* Normally for a large archive if the input file is less than 4 GB then
+ the compressed or stored version should be less than 4 GB. If this
+ assumption is wrong this catches it. This is a problem even if not
+ streaming as the Zip64 extra field was not written and now there's no
+ room for it. */
+ if (was_zip64 == 0 && zip64_entry == 1) {
+ /* guessed wrong and need Zip64 */
+ zipwarn("Entry too big:", z->oname);
+ if (force_zip64 == 0) {
+ ZIPERR(ZE_BIG, "Compressed/stored entry unexpectedly large - do not use -fz-");
+ } else {
+ ZIPERR(ZE_BIG, "Poor compression resulted in unexpectedly large entry - try -fz");
+ }
+ }
+ if (zip64_entry) {
+ /* Zip64 entry still */
+ /* this archive needs Zip64 (version 4.5 unzipper) */
+ zip64_archive = 1;
+ if (z->ver < ZIP64_MIN_VER)
+ z->ver = ZIP64_MIN_VER;
+ } else {
+ /* it turns out we do not need Zip64 */
+ zip64_entry = 0;
+ }
+ if (was_zip64 && zip64_entry != 1) {
+ z->ver = 20;
+ }
+ }
+
+
+#endif /* ZIP64_SUPPORT */
+
+ /* Instead of writing to the file as we go, to do splits we have to write it
+ to memory and see if it will fit before writing the entire local header.
+ If the local header doesn't fit we need to save it for the next disk.
+ */
+
+#ifdef ZIP64_SUPPORT
+ if (zip64_entry || was_zip64)
+ /* update extra field */
+ add_local_zip64_extra_field( z );
+#endif /* ZIP64_SUPPORT */
+
+#ifdef UNICODE_SUPPORT
+# if 0
+ /* if UTF-8 bit is set on an existing entry, assume it should be */
+ /* clear the UTF-8 flag */
+ z->flg &= ~UTF8_BIT;
+ z->lflg &= ~UTF8_BIT;
+# endif
+
+ if (z->uname) {
+ /* need UTF-8 name */
+ if (utf8_force || using_utf8) {
+ z->lflg |= UTF8_BIT;
+ z->flg |= UTF8_BIT;
+ }
+ if (z->flg & UTF8_BIT) {
+ /* If this flag is set, then restore UTF-8 as path name */
+ use_uname = 1;
+ nam = strlen(z->uname);
+ } else {
+ /* use extra field */
+ add_Unicode_Path_local_extra_field(z);
+ }
+ } else {
+ /* clear UTF-8 bit as not needed */
+ z->flg &= ~UTF8_BIT;
+ z->lflg &= ~UTF8_BIT;
+ }
+#endif
+
+ append_ulong_to_mem(LOCSIG, &block, &offset, &blocksize); /* local file header signature */
+ append_ushort_to_mem(z->ver, &block, &offset, &blocksize); /* version needed to extract */
+ append_ushort_to_mem(z->lflg, &block, &offset, &blocksize); /* general purpose bit flag */
+ append_ushort_to_mem(z->how, &block, &offset, &blocksize); /* compression method */
+ append_ulong_to_mem(z->tim, &block, &offset, &blocksize); /* last mod file date time */
+ append_ulong_to_mem(z->crc, &block, &offset, &blocksize); /* crc-32 */
+#ifdef ZIP64_SUPPORT /* zip64 support 09/02/2003 R.Nausedat */
+ /* changes 10/5/03 EG */
+ if (zip64_entry) {
+ append_ulong_to_mem(0xFFFFFFFF, &block, &offset, &blocksize); /* compressed size */
+ append_ulong_to_mem(0xFFFFFFFF, &block, &offset, &blocksize); /* uncompressed size */
+ } else {
+ append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize);/* compressed size */
+ append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize);/* uncompressed size */
+ }
+#else
+ append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize); /* compressed size */
+ append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize); /* uncompressed size */
+#endif
+#ifdef UNICODE_SUPPORT
+ append_ushort_to_mem(nam, &block, &offset, &blocksize); /* file name length */
+#else
+ append_ushort_to_mem(z->nam, &block, &offset, &blocksize); /* file name length */
+#endif
+
+ append_ushort_to_mem(z->ext, &block, &offset, &blocksize); /* extra field length */
+
+#ifdef UNICODE_SUPPORT
+ if (use_uname) {
+ /* path is UTF-8 */
+ append_string_to_mem(z->uname, nam, &block, &offset, &blocksize);
+ } else
+#endif
+#ifdef WIN32_OEM
+ /* store name in OEM character set in archive */
+ if ((z->vem & 0xff00) == 0)
+ {
+ char *oem;
+
+ if ((oem = malloc(strlen(z->iname) + 1)) == NULL)
+ ZIPERR(ZE_MEM, "putlocal oem");
+ INTERN_TO_OEM(z->iname, oem);
+ append_string_to_mem(oem, z->nam, &block, &offset, &blocksize); /* file name */
+ free(oem);
+ } else {
+ append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize); /* file name */
+ }
+#else
+ append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize); /* file name */
+#endif
+ if (z->ext) {
+ append_string_to_mem(z->extra, z->ext, &block, &offset, &blocksize); /* extra field */
+ }
+
+ /* write the header */
+ if (rewrite == PUTLOCAL_REWRITE) {
+ /* use fwrite as seeked back and not extending the archive */
+ /* also if split_method 1 write to file with local header */
+ if (split_method == 1) {
+ if (fwrite(block, 1, offset, current_local_file) != offset) {
+ free(block);
+ return ZE_TEMP;
+ }
+ /* now can close the split if local header on previous split */
+ if (current_local_disk != current_disk) {
+ close_split(current_local_disk, current_local_file, current_local_tempname);
+ current_local_file = NULL;
+ free(current_local_tempname);
+ }
+ } else {
+ /* not doing splits */
+ if (fwrite(block, 1, offset, y) != offset) {
+ free(block);
+ return ZE_TEMP;
+ }
+ }
+ } else {
+ /* do same if archive not split or split_method 2 with descriptors */
+ /* use bfwrite which counts bytes for splits */
+ if (bfwrite(block, 1, offset, BFWRITE_LOCALHEADER) != offset) {
+ free(block);
+ return ZE_TEMP;
+ }
+ }
+ free(block);
+ return ZE_OK;
+}
+
+int putextended(z)
+ struct zlist far *z; /* zip entry to write local header for */
+ /* This is the data descriptor.
+ * Write an extended local header described by *z to file *f.
+ * Return an error code in the ZE_ class. */
+{
+ /* write to mem block then write to file 3/10/2005 */
+ char *block = NULL; /* mem block to write to */
+ extent offset = 0; /* offset into block */
+ extent blocksize = 0; /* size of block */
+
+ append_ulong_to_mem(EXTLOCSIG, &block, &offset, &blocksize); /* extended local signature */
+ append_ulong_to_mem(z->crc, &block, &offset, &blocksize); /* crc-32 */
+#ifdef ZIP64_SUPPORT
+ if (zip64_entry) {
+ /* use Zip64 entries */
+ append_int64_to_mem(z->siz, &block, &offset, &blocksize); /* compressed size */
+ append_int64_to_mem(z->len, &block, &offset, &blocksize); /* uncompressed size */
+ /* This is rather klugy as the AppNote handles this poorly. Typically
+ we don't know at this point if we are writing a Zip64 archive or not,
+ unless a file has needed Zip64. This is particularly annoying here
+ when deciding the size of the data descriptor (extended local header)
+ fields as the appnote says the uncompressed and compressed sizes
+ should be 8 bytes if the archive is Zip64 and 4 bytes if not.
+
+ One interpretation is the version of the archive is determined from
+ the Version Needed To Extract field in the Zip64 End Of Central Directory
+ record and so either an archive should start as Zip64 and write all data
+ descriptors with 8-byte fields or store everything until all the files
+ are processed and then write everything to the archive as changing the
+ sizes of the data descriptors is messy and just not feasible when
+ streaming to standard output. This is not easily workable and others
+ use the different interpretation below.
+
+ This was the old thought:
+ We always write a standard data descriptor. If the file has a large
+ uncompressed or compressed size we set the field to the max field
+ value, which we are defining as flagging the field as having a Zip64
+ value that doesn't fit. As the CRC happens before the variable size
+ fields the CRC is still valid and can be used to check the file. We
+ always use deflate if streaming so signatures should not appear in
+ the data and all local header signatures should be valid, allowing a
+ streaming unzip to find entries by local header signatures, if max size
+ values in the data descriptor sizes ignore them, and extract the file and
+ check it using the CRC. If not streaming the central directory is available
+ so just use those values which are correct.
+
+ After discussions with other groups this is the current thinking:
+
+ Apparent industry interpretation for data descriptors:
+ Data descriptor size is determined for each entry. If the local header
+ version needed to extract is 45 or higher then the entry can use Zip64
+ data descriptors but more checking is needed. If Zip64 extra field is
+ present then assume data descriptor is Zip64 and local version needed
+ to extract should be 45 or higher. If standard data descriptor then
+ local size fields are set to 0 and correct sizes are in standard data descriptor.
+ If Zip64 data descriptor then local sizes are set to -1, Zip64 extra field
+ sizes are set to 0, and the correct sizes are in the Zip64 data descriptor.
+
+ So do this:
+ If an entry is standard and the archive is updatable then seek back and
+ update the local header. No change.
+
+ If an entry is zip64 and the archive is updatable assume the Zip64 extra
+ field was created and update it. No change.
+
+ If data descriptors are needed then assume the archive is Zip64. This is
+ a change and means if ZIP64_SUPPORT is enabled that any non-updatable archive
+ will be in Zip64 format and use Zip64 data descriptors. This should be
+ compatible with other zippers that depend on the current (though not perfect)
+ AppNote description.
+
+ If anyone has some ideas on this I'd like to hear them.
+
+ 3/20/05 EG
+
+ Only assume need Zip64 if the input size is unknown. If the input size is
+ known we can assume Zip64 if the input is larger than 4 GB and assume not
+ otherwise. If the output is seekable we still need to create the Zip64
+ extra field if the input size is unknown so we can seek back and update it.
+ 12/28/05 EG
+ Updated 5/21/06 EG
+ */
+ } else {
+ /* for encryption */
+ append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize); /* compressed size */
+ append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize); /* uncompressed size */
+ }
+#else
+ append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize); /* compressed size */
+ append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize); /* uncompressed size */
+#endif
+ /* write the header */
+ if (bfwrite(block, 1, offset, BFWRITE_HEADER) != offset) {
+ free(block);
+ return ZE_TEMP;
+ }
+ free(block);
+ return ZE_OK;
+}
+
+int putcentral(z)
+ struct zlist far *z; /* zip entry to write central header for */
+/* Write a central header described by *z to file *f. Return an error code
+ in the ZE_ class. */
+/* output now uses bfwrite which writes global y */
+{
+ /* If any of compressed size (siz), uncompressed size (len), offset(off), or
+ disk number (dsk) is larger than can fit in the below standard fields then a
+ Zip64 flag value is stored and a Zip64 extra field is created.
+ Only siz and len are in the local header while all are in the central directory
+ header.
+
+ For the central directory header just store the fields required. All previous fields
+ must be stored though. So can store none (no extra field), just uncompressed size
+ (len), len then siz, len then siz then off, or len then siz then off then dsk, in
+ those orders. 10/6/03 EG
+ */
+
+ /* write to mem block then write to file 3/10/2005 EG */
+ char *block = NULL; /* mem block to write to */
+ extent offset = 0; /* offset into block */
+ extent blocksize = 0; /* size of block */
+ uzoff_t off = 0; /* offset to start of local header */
+ ush nam = z->nam; /* size of name to write to header */
+#ifdef UNICODE_SUPPORT
+ int use_uname = 0; /* write uname to header */
+#endif
+
+#ifdef ZIP64_SUPPORT /* zip64 support 09/02/2003 R.Nausedat */
+ int iRes;
+#endif
+
+#ifdef UNICODE_SUPPORT
+ if (z->uname) {
+ if (utf8_force) {
+ z->flg |= UTF8_BIT;
+ }
+ if (z->flg & UTF8_BIT) {
+ /* If this flag is set, then restore UTF-8 as path name */
+ use_uname = 1;
+ nam = strlen(z->uname);
+ } else {
+ add_Unicode_Path_cen_extra_field(z);
+ }
+ } else {
+ /* clear UTF-8 bit as not needed */
+ z->flg &= ~UTF8_BIT;
+ z->lflg &= ~UTF8_BIT;
+ }
+#endif
+
+ off = z->off;
+
+#ifdef ZIP64_SUPPORT /* zip64 support 09/02/2003 R.Nausedat */
+ if (z->siz > ZIP_UWORD32_MAX || z->len > ZIP_UWORD32_MAX ||
+ z->off > ZIP_UWORD32_MAX || z->dsk > ZIP_UWORD16_MAX || (force_zip64 == 1))
+ {
+ iRes = add_central_zip64_extra_field(z);
+ if( iRes != ZE_OK )
+ return iRes;
+ }
+
+ append_ulong_to_mem(CENSIG, &block, &offset, &blocksize); /* central file header signature */
+ append_ushort_to_mem(z->vem, &block, &offset, &blocksize); /* version made by */
+ append_ushort_to_mem(z->ver, &block, &offset, &blocksize); /* version needed to extract */
+ append_ushort_to_mem(z->flg, &block, &offset, &blocksize); /* general purpose bit flag */
+ append_ushort_to_mem(z->how, &block, &offset, &blocksize); /* compression method */
+ append_ulong_to_mem(z->tim, &block, &offset, &blocksize); /* last mod file date time */
+ append_ulong_to_mem(z->crc, &block, &offset, &blocksize); /* crc-32 */
+ if (z->siz > ZIP_UWORD32_MAX)
+ {
+ /* instead of z->siz */
+ append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize); /* compressed size */
+ }
+ else
+ {
+ append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize); /* compressed size */
+ }
+ /* if forcing Zip64 just force first ef field */
+ if (z->len > ZIP_UWORD32_MAX || (force_zip64 == 1))
+ {
+ /* instead of z->len */
+ append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize); /* uncompressed size */
+ }
+ else
+ {
+ append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize); /* uncompressed size */
+ }
+ append_ushort_to_mem(nam, &block, &offset, &blocksize); /* file name length */
+ append_ushort_to_mem(z->cext, &block, &offset, &blocksize); /* extra field length */
+ append_ushort_to_mem(z->com, &block, &offset, &blocksize); /* file comment length */
+
+ if (z->dsk > ZIP_UWORD16_MAX)
+ {
+ /* instead of z->dsk */
+ append_ushort_to_mem((ush)ZIP_UWORD16_MAX, &block, &offset, &blocksize); /* Zip64 flag */
+ }
+ else
+ {
+ append_ushort_to_mem((ush)z->dsk, &block, &offset, &blocksize); /* disk number start */
+ }
+ append_ushort_to_mem(z->att, &block, &offset, &blocksize); /* internal file attributes */
+ append_ulong_to_mem(z->atx, &block, &offset, &blocksize); /* external file attributes */
+ if (off > ZIP_UWORD32_MAX)
+ {
+ /* instead of z->off */
+ append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize); /* Zip64 flag */
+ }
+ else
+ {
+ append_ulong_to_mem((ulg)off, &block, &offset, &blocksize); /* offset of local header */
+ }
+
+#else /* !ZIP64_SUPPORT */
+
+ append_ulong_to_mem(CENSIG, &block, &offset, &blocksize); /* central file header signature */
+ append_ushort_to_mem(z->vem, &block, &offset, &blocksize); /* version made by */
+ append_ushort_to_mem(z->ver, &block, &offset, &blocksize); /* version needed to extract */
+ append_ushort_to_mem(z->flg, &block, &offset, &blocksize); /* general purpose bit flag */
+ append_ushort_to_mem(z->how, &block, &offset, &blocksize); /* compression method */
+ append_ulong_to_mem(z->tim, &block, &offset, &blocksize); /* last mod file date time */
+ append_ulong_to_mem(z->crc, &block, &offset, &blocksize); /* crc-32 */
+ append_ulong_to_mem((ulg)z->siz, &block, &offset, &blocksize); /* compressed size */
+ append_ulong_to_mem((ulg)z->len, &block, &offset, &blocksize); /* uncompressed size */
+ append_ushort_to_mem(nam, &block, &offset, &blocksize); /* file name length */
+ append_ushort_to_mem(z->cext, &block, &offset, &blocksize); /* extra field length */
+ append_ushort_to_mem(z->com, &block, &offset, &blocksize); /* file comment length */
+ append_ushort_to_mem((ush)z->dsk, &block, &offset, &blocksize); /* disk number start */
+ append_ushort_to_mem(z->att, &block, &offset, &blocksize); /* internal file attributes */
+ append_ulong_to_mem(z->atx, &block, &offset, &blocksize); /* external file attributes */
+ append_ulong_to_mem((ulg)off, &block, &offset, &blocksize); /* relative offset of local header */
+
+#endif /* ZIP64_SUPPORT */
+
+#ifdef EBCDIC
+ if (z->com)
+ memtoasc(z->comment, z->comment, z->com);
+#endif /* EBCDIC */
+
+#ifdef UNICODE_SUPPORT
+ if (use_uname) {
+ /* path is UTF-8 */
+ append_string_to_mem(z->uname, nam, &block, &offset, &blocksize);
+ } else
+#endif
+#ifdef WIN32_OEM
+ /* store name in OEM character set in archive */
+ if ((z->vem & 0xff00) == 0)
+ {
+ char *oem;
+
+ if ((oem = malloc(strlen(z->iname) + 1)) == NULL)
+ ZIPERR(ZE_MEM, "putcentral oem");
+ INTERN_TO_OEM(z->iname, oem);
+ append_string_to_mem(oem, z->nam, &block, &offset, &blocksize);
+ free(oem);
+ } else {
+ append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize);
+ }
+#else
+ append_string_to_mem(z->iname, z->nam, &block, &offset, &blocksize);
+#endif
+
+ if (z->cext) {
+ append_string_to_mem(z->cextra, z->cext, &block, &offset, &blocksize);
+ }
+ if (z->com) {
+#ifdef WIN32_OEM
+ /* store comment in OEM character set in archive */
+ if ((z->vem & 0xff00) == 0)
+ {
+ char *oem;
+
+ if ((oem = malloc(strlen(z->comment) + 1)) == NULL)
+ ZIPERR(ZE_MEM, "putcentral oem comment");
+ INTERN_TO_OEM(z->comment, oem);
+ append_string_to_mem(oem, z->com, &block, &offset, &blocksize);
+ free(oem);
+ } else {
+ append_string_to_mem(z->comment, z->com, &block, &offset, &blocksize);
+ }
+#else
+ append_string_to_mem(z->comment, z->com, &block, &offset, &blocksize);
+#endif
+ }
+
+ /* write the header */
+ if (bfwrite(block, 1, offset, BFWRITE_CENTRALHEADER) != offset) {
+ free(block);
+ return ZE_TEMP;
+ }
+ free(block);
+
+ return ZE_OK;
+}
+
+
+/* Write the end of central directory data to file y. Return an error code
+ in the ZE_ class. */
+
+int putend( OFT( uzoff_t) n,
+ OFT( uzoff_t) s,
+ OFT( uzoff_t) c,
+ OFT( extent) m,
+ OFT( char *) z
+ )
+#ifdef NO_PROTO
+ uzoff_t n; /* number of entries in central directory */
+ uzoff_t s; /* size of central directory */
+ uzoff_t c; /* offset of central directory */
+ extent m; /* length of zip file comment (0 if none) */
+ char *z; /* zip file comment if m != 0 */
+#endif /* def NO_PROTO */
+{
+#ifdef ZIP64_SUPPORT /* zip64 support 09/05/2003 R.Nausedat */
+ ush vem; /* version made by */
+ int iNeedZip64 = 0;
+
+ char *block = NULL; /* mem block to write to */
+ extent offset = 0; /* offset into block */
+ extent blocksize = 0; /* size of block */
+
+ /* we have to create a zip64 archive if we have more than 64k - 1 entries, */
+ /* if the CD is > 4 GB or if the offset to the CD > 4 GB. even if the CD start */
+ /* is < 4 GB and CD start + CD size > 4GB we do not need a zip64 archive since */
+ /* the offset entry in the CD tail is still valid. [note that there are other */
+ /* reasons for needing a Zip64 archive though, such as an uncompressed */
+ /* size > 4 GB for an entry but the entry compresses below 4 GB, so the archive */
+ /* is Zip64 but the CD does not need Zip64.] */
+ /* order of the zip/zip64 records in a zip64 archive: */
+ /* central directory */
+ /* zip64 end of central directory record */
+ /* zip64 end of central directory locator */
+ /* end of central directory record */
+
+ /* check zip64_archive instead of force_zip64 3/19/05 */
+
+ zip64_eocd_disk = current_disk;
+ zip64_eocd_offset = bytes_this_split;
+
+ if( n > ZIP_UWORD16_MAX || s > ZIP_UWORD32_MAX || c > ZIP_UWORD32_MAX ||
+ zip64_archive )
+ {
+ ++iNeedZip64;
+ /* write zip64 central dir tail: */
+ /* */
+ /* 4 bytes zip64 end of central dir signature (0x06064b50) */
+ append_ulong_to_mem((ulg)ZIP64_CENTRAL_DIR_TAIL_SIG, &block, &offset, &blocksize);
+ /* 8 bytes size of zip64 end of central directory record */
+ /* a fixed size unless the end zip64 extensible data sector is used. - 3/19/05 EG */
+ /* also note that AppNote 6.2 creates version 2 of this record for
+ central directory encryption - 3/19/05 EG */
+ append_int64_to_mem((zoff_t)ZIP64_CENTRAL_DIR_TAIL_SIZE, &block, &offset, &blocksize);
+
+ /* 2 bytes version made by */
+ vem = OS_CODE + Z_MAJORVER * 10 + Z_MINORVER;
+ append_ushort_to_mem(vem, &block, &offset, &blocksize);
+
+ /* APPNOTE says that zip64 archives should have at least version 4.5
+ in the "version needed to extract" field */
+ /* 2 bytes version needed to extract */
+ append_ushort_to_mem(ZIP64_MIN_VER, &block, &offset, &blocksize);
+
+ /* 4 bytes number of this disk */
+ append_ulong_to_mem(current_disk, &block, &offset, &blocksize);
+ /* 4 bytes number of the disk with the start of the central directory */
+ append_ulong_to_mem(cd_start_disk, &block, &offset, &blocksize);
+ /* 8 bytes total number of entries in the central directory on this disk */
+ append_int64_to_mem(cd_entries_this_disk, &block, &offset, &blocksize);
+ /* 8 bytes total number of entries in the central directory */
+ append_int64_to_mem(n, &block, &offset, &blocksize);
+ /* 8 bytes size of the central directory */
+ append_int64_to_mem(s, &block, &offset, &blocksize);
+ /* 8 bytes offset of start of central directory with respect to the starting disk number */
+ append_int64_to_mem(cd_start_offset, &block, &offset, &blocksize);
+ /* zip64 extensible data sector (variable size), we don't use it... */
+
+ /* write zip64 end of central directory locator: */
+ /* */
+ /* 4 bytes zip64 end of central dir locator signature (0x07064b50) */
+ append_ulong_to_mem(ZIP64_CENTRAL_DIR_TAIL_END_SIG, &block, &offset, &blocksize);
+ /* 4 bytes number of the disk with the start of the zip64 end of central directory */
+ append_ulong_to_mem(zip64_eocd_disk, &block, &offset, &blocksize);
+ /* 8 bytes relative offset of the zip64 end of central directory record, that is */
+ /* offset of CD + CD size */
+ append_int64_to_mem(zip64_eocd_offset, &block, &offset, &blocksize);
+ /* PUTLLG(l64Temp, f); */
+ /* 4 bytes total number of disks */
+ append_ulong_to_mem(current_disk + 1, &block, &offset, &blocksize);
+ }
+
+ /* end of central dir signature */
+ append_ulong_to_mem(ENDSIG, &block, &offset, &blocksize);
+ /* mv archives to come :) */
+ /* for now use n for all */
+ /* 2 bytes number of this disk */
+ if (current_disk < 0xFFFF)
+ append_ushort_to_mem((ush)current_disk, &block, &offset, &blocksize);
+ else
+ append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+ /* 2 bytes number of the disk with the start of the central directory */
+ if (cd_start_disk == (ulg)-1)
+ cd_start_disk = 0;
+ if (cd_start_disk < 0xFFFF)
+ append_ushort_to_mem((ush)cd_start_disk, &block, &offset, &blocksize);
+ else
+ append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+ /* 2 bytes total number of entries in the central directory on this disk */
+ if (cd_entries_this_disk < 0xFFFF)
+ append_ushort_to_mem((ush)cd_entries_this_disk, &block, &offset, &blocksize);
+ else
+ append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+ /* 2 bytes total number of entries in the central directory */
+ if (total_cd_entries < 0xFFFF)
+ append_ushort_to_mem((ush)total_cd_entries, &block, &offset, &blocksize);
+ else
+ append_ushort_to_mem((ush)0xFFFF, &block, &offset, &blocksize);
+ if( s > ZIP_UWORD32_MAX )
+ /* instead of s */
+ append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize);
+ else
+ /* 4 bytes size of the central directory */
+ append_ulong_to_mem((ulg)s, &block, &offset, &blocksize);
+ if(force_zip64 == 1 || cd_start_offset > ZIP_UWORD32_MAX)
+ /* instead of cd_start_offset */
+ append_ulong_to_mem(ZIP_UWORD32_MAX, &block, &offset, &blocksize);
+ else
+ /* 4 bytes offset of start of central directory with respect to the starting disk number */
+ append_ulong_to_mem((ulg)cd_start_offset, &block, &offset, &blocksize);
+
+#else /* !ZIP64_SUPPORT */
+ char *block = NULL; /* mem block to write to */
+ extent offset = 0; /* offset into block */
+ extent blocksize = 0; /* size of block */
+
+ /* end of central dir signature */
+ append_ulong_to_mem(ENDSIG, &block, &offset, &blocksize);
+ /* 2 bytes number of this disk */
+ append_ushort_to_mem((ush)current_disk, &block, &offset, &blocksize);
+ /* 2 bytes number of the disk with the start of the central directory */
+ append_ushort_to_mem((ush)cd_start_disk, &block, &offset, &blocksize);
+ /* 2 bytes total number of entries in the central directory on this disk */
+ append_ushort_to_mem((ush)cd_entries_this_disk, &block, &offset, &blocksize);
+ /* 2 bytes total number of entries in the central directory */
+ append_ushort_to_mem((ush)n, &block, &offset, &blocksize);
+ /* 4 bytes size of the central directory */
+ append_ulong_to_mem((ulg)s, &block, &offset, &blocksize);
+ /* 4 bytes offset of start of central directory with respect to the starting disk number */
+ append_ulong_to_mem((ulg)cd_start_offset, &block, &offset, &blocksize);
+#endif /* ZIP64_SUPPORT */
+
+ /* size of comment */
+ append_ushort_to_mem((ush)m, &block, &offset, &blocksize);
+ /* Write the comment, if any */
+#ifdef EBCDIC
+ memtoasc(z, z, m);
+#endif
+ if (m) {
+ /* PKWare defines the archive comment to be ASCII only so no OEM conversion */
+ append_string_to_mem(z, m, &block, &offset, &blocksize);
+ }
+
+ /* write the block */
+ if (bfwrite(block, 1, offset, BFWRITE_HEADER) != offset) {
+ free(block);
+ return ZE_TEMP;
+ }
+ free(block);
+
+#ifdef HANDLE_AMIGA_SFX
+ if (amiga_sfx_offset && zipbeg /* -J zeroes this */) {
+ s = zftello(y);
+ while (s & 3) s++, putc(0, f); /* final marker must be longword aligned */
+ PUTLG(0xF2030000 /* 1010 in Motorola byte order */, f);
+ c = (s - amiga_sfx_offset - 4) / 4; /* size of archive part in longwords */
+ if (zfseeko(y, amiga_sfx_offset, SEEK_SET) != 0)
+ return ZE_TEMP;
+ c = ((c >> 24) & 0xFF) | ((c >> 8) & 0xFF00)
+ | ((c & 0xFF00) << 8) | ((c & 0xFF) << 24); /* invert byte order */
+ PUTLG(c, y);
+ zfseeko(y, 0, SEEK_END); /* just in case */
+ }
+#endif
+
+ return ZE_OK;
+} /* end function putend() */
+
+
+
+/* Note: a zip "entry" includes a local header (which includes the file
+ name), an encryption header if encrypting, the compressed data
+ and possibly an extended local header. */
+
+int zipcopy(z)
+ struct zlist far *z; /* zip entry to copy */
+/* Copy the zip entry described by *z from in_file to y. Return an
+ error code in the ZE_ class. Also update tempzn by the number of bytes
+ copied. */
+/* Now copies to global output file y */
+/* Handle entries that span disks */
+/* If fix == 2, assume in_file is pointing to a local header and fill
+ in z from local header */
+{
+ uzoff_t n; /* holds local header offset */
+ ulg e = 0; /* extended local header size */
+ ulg start_disk = 0;
+ uzoff_t start_offset = 0;
+ char *split_path;
+ char buf[LOCHEAD + 1];
+ struct zlist far *localz;
+ int r;
+
+
+ Trace((stderr, "zipcopy %s\n", z->zname));
+
+ /* if fix == 2 assume in_file open and pointing at local header */
+ if (fix != 2) {
+ start_disk = z->dsk;
+ start_offset = z->off;
+
+ /* don't assume reading the right disk */
+
+ /* if start not on current disk then close current disk */
+ if (start_disk != current_in_disk) {
+ if (in_file) {
+ fclose(in_file);
+ in_file = NULL;
+ }
+ }
+
+ current_in_disk = start_disk;
+
+ /* disks are archive.z01, archive.z02, ..., archive.zip */
+ split_path = get_in_split_path(in_path, current_in_disk);
+
+ if (in_file == NULL) {
+ while ((in_file = zfopen(split_path, FOPR)) == NULL) {
+ /* could not open split */
+
+ if (!noisy) {
+ ZIPERR(ZE_OPEN, split_path);
+ }
+
+ /* Ask for directory with split. Updates global in_path */
+ r = ask_for_split_read_path(start_disk);
+ if (r == ZE_ABORT) {
+ /* user abort */
+ return ZE_ABORT;
+ } else if ((fix == 1 || fix == 2) && r == ZE_FORM) {
+ /* user asks to skip this disk */
+ return ZE_FORM;
+ }
+ free(split_path);
+ split_path = get_in_split_path(in_path, start_disk);
+ }
+ }
+
+ if (zfseeko(in_file, start_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("reading archive fseek: ", strerror(errno));
+ return ZE_READ;
+ }
+ } /* fix != 2 */
+
+ if (fix != 2 && !at_signature(in_file, "PK\03\04")) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("Did not find entry for ", z->iname);
+ return ZE_FORM;
+ }
+
+ /* read local header */
+ if (fread(buf, LOCHEAD, 1, in_file) != 1) {
+ int f = ferror(in_file);
+ zipwarn("reading local entry: ", strerror(errno));
+ if (fix != 2)
+ fclose(in_file);
+ return f ? ZE_READ : ZE_EOF;
+ }
+
+ /* Local Header
+ local file header signature 4 bytes (0x04034b50)
+ version needed to extract 2 bytes
+ general purpose bit flag 2 bytes
+ compression method 2 bytes
+ last mod file time 2 bytes
+ last mod file date 2 bytes
+ crc-32 4 bytes
+ compressed size 4 bytes
+ uncompressed size 4 bytes
+ file name length 2 bytes
+ extra field length 2 bytes
+
+ file name (variable size)
+ extra field (variable size)
+ */
+
+ if ((localz = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL) {
+ zipwarn("reading entry", "");
+ if (fix != 2)
+ fclose(in_file);
+ return ZE_MEM;
+ }
+
+ localz->ver = SH(LOCVER + buf);
+ localz->lflg = SH(LOCFLG + buf);
+ localz->how = SH(LOCHOW + buf);
+ localz->tim = LG(LOCTIM + buf); /* time and date into one long */
+ localz->crc = LG(LOCCRC + buf);
+ localz->nam = SH(LOCNAM + buf);
+ localz->ext = SH(LOCEXT + buf);
+ if (fix == 2) {
+ localz->siz = LG(LOCSIZ + buf);
+ localz->len = LG(LOCLEN + buf);
+ }
+
+ if (fix == 2) {
+ /* Do some sanity checks to make reasonably sure this is a local header */
+ ush os = localz->ver >> 8;
+ ush pkver = localz->ver - os;
+
+ /* OS - currently 0 - 18 (AppNote 6.3) and 30 (ATHEOS) */
+ if (os > 40) {
+ sprintf(errbuf, "Illegal host system mapping in local header: %d", os);
+ zipwarn(errbuf, "");
+ zipwarn("Skipping: ", z->iname);
+ return ZE_FORM;
+ }
+ /* PK Version - currently 10 - 62 (AppNote 6.2.2) */
+ /* If PKZip central directory encryption is used (62), the local header
+ values could be masked values. Specifically, as of AppNote 6.2.2
+ the time, crc-32, and uncompressed file size are masked and the
+ file name is also replaced with a hex entry count. Should
+ still be able to recover the entries, but they may be unreadable
+ without the 62 support fields. */
+ if (pkver > 100) {
+ sprintf(errbuf, "Illegal PK version mapping in local header: %d", pkver);
+ zipwarn(errbuf, "");
+ zipwarn("Skipping: ", z->iname);
+ return ZE_FORM;
+ }
+ /* Currently compression method is defined as 0 - 19 and 98 (AppNote 6.3) */
+ /* We can still copy an entry we can't read, but something over 200 is
+ probably illegal */
+ if (localz->how > 200) {
+ sprintf(errbuf, "Unrecognized compression method in local header: %d", localz->how);
+ zipwarn(errbuf, "");
+ zipwarn("Skipping: ", z->iname);
+ return ZE_FORM;
+ }
+
+ /* It's hard to make guesses on the other fields. Suggestions welcome. */
+ }
+
+ /* Initialize all fields pointing to malloced data to NULL */
+ localz->zname = localz->name = localz->iname = localz->extra = NULL;
+ localz->oname = NULL;
+#ifdef UNICODE_SUPPORT
+ localz->uname = NULL;
+#endif
+
+ /* Read file name, extra field and comment field */
+ if ((localz->iname = malloc(localz->nam+1)) == NULL ||
+ (localz->ext && (localz->extra = malloc(localz->ext)) == NULL))
+ return ZE_MEM;
+ if (fread(localz->iname, localz->nam, 1, in_file) != 1 ||
+ (localz->ext && fread(localz->extra, localz->ext, 1, in_file) != 1))
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+ localz->iname[localz->nam] = '\0'; /* terminate name */
+ if ((localz->name = malloc(localz->nam+1)) == NULL)
+ return ZE_MEM;
+ strcpy(localz->name, localz->iname);
+
+#ifdef ZIP64_SUPPORT
+ zip64_entry = adjust_zip_local_entry(localz);
+#endif
+
+ localz->vem = 0;
+ if (fix != 2) {
+ /* Need vem to determine if iname is Win32 OEM name */
+ localz->vem = z->vem;
+
+#ifdef UNICODE_SUPPORT
+ if (unicode_mismatch != 3) {
+ if (z->flg & UTF8_BIT) {
+ char *iname;
+ /* path is UTF-8 */
+ localz->uname = localz->iname;
+ iname = utf8_to_local_string(localz->uname);
+ if (iname == NULL) {
+ /* a bad UTF-8 character in name likely - go with (probably messed up) uname */
+ if ((localz->iname = malloc(strlen(localz->uname) + 1)) == NULL) {
+ return ZE_MEM;
+ }
+ strcpy(localz->iname, localz->uname);
+ } else {
+ /* go with local character set iname */
+ localz->iname = iname;
+ }
+ } else {
+ /* check for UTF-8 path extra field */
+ read_Unicode_Path_local_entry(localz);
+ }
+ }
+#endif
+
+#ifdef WIN32_OEM
+ /* If fix == 2 and reading local headers first, vem is not in the local
+ header so we don't know when to do OEM translation, as the ver field
+ is set to MSDOS (0) by all unless something specific is needed.
+ However, if local header has a Unicode path extra field, we can get
+ the real file name from there. */
+ if ((z->vem & 0xff00) == 0)
+ /* assume archive name is OEM if from DOS */
+ oem_to_local_string(localz->iname, localz->iname);
+#endif
+ }
+
+ if (fix == 2) {
+# ifdef WIN32
+# ifdef UNICODE_SUPPORT
+ localz->namew = NULL;
+ localz->inamew = NULL;
+ localz->znamew = NULL;
+ z->namew = NULL;
+ z->inamew = NULL;
+ z->znamew = NULL;
+# endif
+# endif
+ /* set z from localz */
+ z->flg = localz->lflg;
+ z->len = localz->len;
+ z->siz = localz->siz;
+
+ } else {
+ /* Compare localz to z */
+ if (localz->ver != z->ver) {
+ zipwarn("Local Version Needed To Extract does not match CD: ", z->iname);
+ }
+ if (localz->lflg != z->flg) {
+ zipwarn("Local Entry Flag does not match CD: ", z->iname);
+ }
+ if (!(z->flg & 8)) {
+ if (localz->crc != z->crc) {
+ zipwarn("Local Entry CRC does not match CD: ", z->iname);
+ }
+ }
+ if (fix != 3 && strcmp(localz->iname, z->iname) != 0) {
+ zipwarn("Local Entry name does not match CD: ", z->iname);
+ }
+
+ /* as copying get uncompressed and compressed sizes from central directory */
+ localz->len = z->len;
+ localz->siz = z->siz;
+ }
+
+#if 0
+ if (fix > 1) {
+ if (zfseeko(in_file, z->off + n, SEEK_SET)) /* seek to compressed data */
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+
+ if (fix > 2) {
+ /* Update length of entry's name, it may have been changed. This is
+ needed to support the ZipNote ability to rename archive entries. */
+ z->nam = strlen(z->iname);
+ n = (uzoff_t)((LOCHEAD) + (ulg)z->nam + (ulg)z->ext);
+ }
+
+ /* do not trust the old compressed size */
+ if (putlocal(z, PUTLOCAL_WRITE) != ZE_OK)
+ return ZE_TEMP;
+
+ z->off = tempzn;
+ tempzn += n;
+ n = z->siz;
+ } else {
+ if (zfseeko(in_file, z->off, SEEK_SET)) /* seek to local header */
+ return ferror(in_file) ? ZE_READ : ZE_EOF;
+
+ z->off = tempzn;
+ n += z->siz;
+ }
+#endif
+
+ /* from zipnote */
+ if (fix == 3) {
+ /* Update length of entry's name, as it may have been changed. This is
+ needed to support the ZipNote ability to rename archive entries. */
+ localz->nam = z->nam = strlen(z->iname);
+ /* update local name */
+ free(localz->iname);
+ if ((localz->iname = malloc(strlen(z->iname) + 1)) == NULL) {
+ zipwarn("out of memory in zipcopy", "");
+ return ZE_MEM;
+ }
+ strcpy(localz->iname, z->iname);
+ }
+
+ /* update disk and offset */
+ z->dsk = current_disk;
+ z->off = bytes_this_split;
+
+ /* copy the compressed data and the extended local header if there is one */
+
+ /* copy the compressed data. We recreate the local header as the local
+ header can't be split and putlocal ensures it won't. Also, since we
+ use siz and len from the central directory, we don't need the extended
+ local header if there is one, unless the file is encrypted as then the
+ extended header is used to indicate crypt head uses file time instead
+ of crc as the password check.
+
+ If fix = 2 then we don't have the central directory yet so keep
+ any data descriptors. */
+
+ if (fix != 2 && !(z->flg & 1)) {
+ /* Not encrypted */
+ localz->flg = z->flg &= ~8;
+ z->lflg = localz->lflg &= ~8;
+ }
+
+ e = 0;
+ if (z->lflg & 8) {
+#ifdef ZIP64_SUPPORT
+ if (zip64_entry)
+ e = 24;
+ else
+#endif
+ e = 16;
+ }
+ /* 4 is signature */
+ n = 4 + (uzoff_t)((LOCHEAD) + (ulg)(localz->nam) + (ulg)(localz->ext));
+
+ n += e + z->siz;
+ tempzn += n;
+
+ /* Output name */
+ if (fix == 2) {
+ if ((z->oname = malloc(strlen(localz->iname) + 1)) == NULL) {
+ return ZE_MEM;
+ }
+ strcpy(z->oname, localz->iname);
+#ifndef UTIL
+# ifdef WIN32
+ /* Win9x console always uses OEM character coding, and
+ WinNT console is set to OEM charset by default, too */
+ _INTERN_OEM(z->oname);
+# endif
+#endif
+ sprintf(errbuf, " copying: %s ", z->oname);
+ zipmessage_nl(errbuf, 0);
+ }
+
+ if (fix == 2)
+ z->crc = localz->crc;
+ else
+ localz->crc = z->crc;
+
+ if (putlocal(localz, PUTLOCAL_WRITE) != ZE_OK)
+ return ZE_TEMP;
+
+ /*
+ if (zfseeko(in_file, start_offset, SEEK_SET) != 0) {
+ fclose(in_file);
+ in_file = NULL;
+ zipwarn("reading archive fseek: ", strerror(errno));
+ return ZE_READ;
+ }
+ */
+
+ /* copy the data */
+ if (fix == 2 && localz->lflg & 8)
+ /* read to data descriptor */
+ r = bfcopy((uzoff_t) -2);
+ else
+ r = bfcopy(localz->siz);
+
+ if (r == ZE_ABORT) {
+ if (localz->ext) free(localz->extra);
+ if (localz->nam) free(localz->iname);
+ if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+ if (localz->uname) free(localz->uname);
+#endif
+ free(localz);
+ ZIPERR(ZE_ABORT, "Could not find split");
+ }
+
+ if (r == ZE_EOF || skip_this_disk) {
+ /* missing disk */
+ zipwarn("aborting: ", z->oname);
+
+ if (r == ZE_OK)
+ r = ZE_FORM;
+
+ if (fix == 2) {
+#ifdef DEBUG
+ zoff_t here = zftello(y);
+#endif
+
+ /* fix == 2 skips right to next disk */
+ skip_this_disk = 0;
+
+ /* seek back in output to start of this entry so can overwrite */
+ if (zfseeko(y, current_local_offset, SEEK_SET) != 0) {
+ ZIPERR(ZE_WRITE, "seek failed on output file");
+ }
+ bytes_this_split = current_local_offset;
+ tempzn = current_local_offset;
+ }
+
+ /* tell scan to skip this entry */
+ if (localz->ext) free(localz->extra);
+ if (localz->nam) free(localz->iname);
+ if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+ if (localz->uname) free(localz->uname);
+#endif
+ free(localz);
+ return r;
+ }
+
+ if (fix == 2 && z->flg & 8) {
+ /* this entry should have a data descriptor */
+ /* only -FF needs to read the descriptor as other modes
+ rely on the central directory */
+ if (des_good) {
+ /* found an apparently good data descriptor */
+ localz->crc = des_crc;
+ localz->siz = des_csize;
+ localz->len = des_usize;
+ } else {
+ /* no end to this entry found */
+ zipwarn("no end of stream entry found: ", z->oname);
+ zipwarn("rewinding and scanning for later entries", "");
+
+ /* seek back in output to start of this entry so can overwrite */
+ if (zfseeko(y, current_local_offset, SEEK_SET) != 0){
+
+ }
+
+ /* tell scan to skip this entry */
+ if (localz->ext) free(localz->extra);
+ if (localz->nam) free(localz->iname);
+ if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+ if (localz->uname) free(localz->uname);
+#endif
+ free(localz);
+ return ZE_FORM;
+ }
+ }
+
+ if (z->flg & 8) {
+ putextended(localz);
+ }
+
+ /* now can close the split if local header on previous split */
+ if (split_method == 1 && current_local_disk != current_disk) {
+ close_split(current_local_disk, current_local_file, current_local_tempname);
+ current_local_file = NULL;
+ free(current_local_tempname);
+ }
+
+ /* update local header and close start split */
+ /* to use this need to seek back, do this, then come back
+ if (putlocal(localz, PUTLOCAL_REWRITE) != ZE_OK)
+ r = ZE_TEMP;
+ */
+
+ if (fix == 2) {
+ z->ver = localz->ver;
+ z->how = localz->how;
+ z->tim = localz->tim;
+ z->crc = localz->crc;
+ z->lflg = localz->lflg;
+ z->flg = localz->lflg;
+ z->len = localz->len;
+ z->siz = localz->siz;
+ z->nam = localz->nam;
+ z->ext = localz->ext;
+ z->extra = localz->extra;
+ /* copy local extra fields to central directory for now */
+ z->cext = localz->ext;
+ z->cextra = NULL;
+ if (localz->ext) {
+ if ((z->cextra = malloc(localz->ext + 1)) == NULL) {
+ return ZE_MEM;
+ }
+ strcpy(z->cextra, localz->extra);
+ }
+ z->com = 0;
+ z->att = 0;
+ z->atx = 0;
+ z->name = localz->name;
+ z->iname = localz->iname;
+#ifdef UNICODE_SUPPORT
+ z->uname = localz->uname;
+#endif
+ if ((z->zname = malloc(localz->nam + 1)) == NULL) {
+ return ZE_MEM;
+ }
+ strcpy(z->zname, z->iname);
+ } else {
+ if (localz->ext) free(localz->extra);
+ if (localz->nam) free(localz->iname);
+ if (localz->nam) free(localz->name);
+#ifdef UNICODE_SUPPORT
+ if (localz->uname) free(localz->uname);
+#endif
+ free(localz);
+ }
+
+ if (fix == 2) {
+ sprintf(errbuf, " (%s bytes)", zip_fzofft(z->siz, NULL, "u"));
+ zipmessage_nl(errbuf, 1);
+
+ if (r == ZE_READ) {
+ zipwarn("entry truncated: ", z->oname);
+ sprintf(errbuf, "expected compressed/stored size %s, actual %s",
+ zip_fzofft(localz->siz, NULL, "u"), zip_fzofft(bytes_this_entry, NULL, "u"));
+ zipwarn(errbuf, "");
+ }
+ }
+
+ return r;
+}
+
+
+
+#ifndef UTIL
+
+#ifdef USE_EF_UT_TIME
+
+local int ef_scan_ut_time(ef_buf, ef_len, ef_is_cent, z_utim)
+char *ef_buf; /* buffer containing extra field */
+extent ef_len; /* total length of extra field */
+int ef_is_cent; /* flag indicating "is central extra field" */
+iztimes *z_utim; /* return storage: atime, mtime, ctime */
+/* This function scans the extra field for EF_TIME or EF_IZUNIX blocks
+ * containing Unix style time_t (GMT) values for the entry's access, creation
+ * and modification time.
+ * If a valid block is found, all time stamps are copied to the iztimes
+ * structure.
+ * The presence of an EF_TIME or EF_IZUNIX2 block results in ignoring
+ * all data from probably present obsolete EF_IZUNIX blocks.
+ * If multiple blocks of the same type are found, only the information from
+ * the last block is used.
+ * The return value is the EF_TIME Flags field (simulated in case of an
+ * EF_IZUNIX block) or 0 in case of failure.
+ */
+{
+ int flags = 0;
+ unsigned eb_id;
+ extent eb_len;
+ int have_new_type_eb = FALSE;
+
+ if (ef_len == 0 || ef_buf == NULL)
+ return 0;
+
+ Trace((stderr,"\nef_scan_ut_time: scanning extra field of length %u\n",
+ (unsigned)ef_len));
+ while (ef_len >= EB_HEADSIZE) {
+ eb_id = SH(EB_ID + ef_buf);
+ eb_len = SH(EB_LEN + ef_buf);
+
+ if (eb_len > (ef_len - EB_HEADSIZE)) {
+ /* Discovered some extra field inconsistency! */
+ Trace((stderr,"ef_scan_ut_time: block length %u > rest ef_size %u\n",
+ (unsigned)eb_len, (unsigned)(ef_len - EB_HEADSIZE)));
+ break;
+ }
+
+ switch (eb_id) {
+ case EF_TIME:
+ flags &= ~0x00ff; /* ignore previous IZUNIX or EF_TIME fields */
+ have_new_type_eb = TRUE;
+ if ( eb_len >= EB_UT_MINLEN && z_utim != NULL) {
+ unsigned eb_idx = EB_UT_TIME1;
+ Trace((stderr,"ef_scan_ut_time: Found TIME extra field\n"));
+ flags |= (ef_buf[EB_HEADSIZE+EB_UT_FLAGS] & 0x00ff);
+ if ((flags & EB_UT_FL_MTIME)) {
+ if ((eb_idx+4) <= eb_len) {
+ z_utim->mtime = LG((EB_HEADSIZE+eb_idx) + ef_buf);
+ eb_idx += 4;
+ Trace((stderr," Unix EF modtime = %ld\n", z_utim->mtime));
+ } else {
+ flags &= ~EB_UT_FL_MTIME;
+ Trace((stderr," Unix EF truncated, no modtime\n"));
+ }
+ }
+ if (ef_is_cent) {
+ break; /* central version of TIME field ends here */
+ }
+ if (flags & EB_UT_FL_ATIME) {
+ if ((eb_idx+4) <= eb_len) {
+ z_utim->atime = LG((EB_HEADSIZE+eb_idx) + ef_buf);
+ eb_idx += 4;
+ Trace((stderr," Unix EF acctime = %ld\n", z_utim->atime));
+ } else {
+ flags &= ~EB_UT_FL_ATIME;
+ }
+ }
+ if (flags & EB_UT_FL_CTIME) {
+ if ((eb_idx+4) <= eb_len) {
+ z_utim->ctime = LG((EB_HEADSIZE+eb_idx) + ef_buf);
+ /* eb_idx += 4; */ /* superfluous for now ... */
+ Trace((stderr," Unix EF cretime = %ld\n", z_utim->ctime));
+ } else {
+ flags &= ~EB_UT_FL_CTIME;
+ }
+ }
+ }
+ break;
+
+ case EF_IZUNIX2:
+ if (!have_new_type_eb) {
+ flags &= ~0x00ff; /* ignore any previous IZUNIX field */
+ have_new_type_eb = TRUE;
+ }
+ break;
+
+ case EF_IZUNIX:
+ if (eb_len >= EB_UX_MINLEN) {
+ Trace((stderr,"ef_scan_ut_time: Found IZUNIX extra field\n"));
+ if (have_new_type_eb) {
+ break; /* Ignore IZUNIX extra field block ! */
+ }
+ z_utim->atime = LG((EB_HEADSIZE+EB_UX_ATIME) + ef_buf);
+ z_utim->mtime = LG((EB_HEADSIZE+EB_UX_MTIME) + ef_buf);
+ Trace((stderr," Unix EF access time = %ld\n",z_utim->atime));
+ Trace((stderr," Unix EF modif. time = %ld\n",z_utim->mtime));
+ flags |= (EB_UT_FL_MTIME | EB_UT_FL_ATIME); /* signal success */
+ }
+ break;
+
+ case EF_THEOS:
+/* printf("Not implemented yet\n"); */
+ break;
+
+ default:
+ break;
+ }
+ /* Skip this extra field block */
+ ef_buf += (eb_len + EB_HEADSIZE);
+ ef_len -= (eb_len + EB_HEADSIZE);
+ }
+
+ return flags;
+}
+
+int get_ef_ut_ztime(z, z_utim)
+struct zlist far *z;
+iztimes *z_utim;
+{
+ int r;
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid) return 0;
+#endif
+
+ /* First, scan local extra field. */
+ r = ef_scan_ut_time(z->extra, z->ext, FALSE, z_utim);
+
+ /* If this was not successful, try central extra field, but only if
+ it is really different. */
+ if (!r && z->cext > 0 && z->cextra != z->extra)
+ r = ef_scan_ut_time(z->cextra, z->cext, TRUE, z_utim);
+
+ return r;
+}
+
+#endif /* USE_EF_UT_TIME */
+
+
+local void cutpath(p, delim)
+char *p; /* path string */
+int delim; /* path component separator char */
+/* Cut the last path component off the name *p in place.
+ * This should work on both internal and external names.
+ */
+{
+ char *r; /* pointer to last path delimiter */
+
+#ifdef VMS /* change [w.x.y]z to [w.x]y.DIR */
+ if ((r = MBSRCHR(p, ']')) != NULL)
+ {
+ *r = 0;
+ if ((r = MBSRCHR(p, '.')) != NULL)
+ {
+ *r = ']';
+ strcat(r, ".DIR;1"); /* this assumes a little padding--see PAD */
+ } else {
+ *p = 0;
+ }
+ } else {
+ if ((r = MBSRCHR(p, delim)) != NULL)
+ *r = 0;
+ else
+ *p = 0;
+ }
+#else /* !VMS */
+ if ((r = MBSRCHR(p, delim)) != NULL)
+ *r = 0;
+ else
+ *p = 0;
+#endif /* ?VMS */
+}
+
+int trash()
+/* Delete the compressed files and the directories that contained the deleted
+ files, if empty. Return an error code in the ZE_ class. Failure of
+ destroy() or deletedir() is ignored. */
+{
+ extent i; /* counter on deleted names */
+ extent n; /* number of directories to delete */
+ struct zlist far **s; /* table of zip entries to handle, sorted */
+ struct zlist far *z; /* current zip entry */
+
+ /* Delete marked names and count directories */
+ n = 0;
+ for (z = zfiles; z != NULL; z = z->nxt)
+ if (z->mark == 1 || z->trash)
+ {
+ z->mark = 1;
+ if (z->iname[z->nam - 1] != (char)0x2f) { /* don't unlink directory */
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: deleting file %s\n", z->name);
+ if (destroy(z->name)) {
+ zipwarn("error deleting ", z->name);
+ }
+ /* Try to delete all paths that lead up to marked names. This is
+ * necessary only with the -D option.
+ */
+ if (!dirnames) {
+ cutpath(z->name, '/'); /* XXX wrong ??? */
+ /* Below apparently does not work for Russian OEM but
+ '/' should be same as 0x2f for ascii and most ports so
+ changed it. Did not trace through the mappings but
+ maybe 0x2F is mapped differently on OEM_RUSS - EG 2/28/2003 */
+ /* CS, 5/14/2005: iname is the byte array read from and written
+ to the zip archive; it MUST be ASCII (compatible)!!!
+ If something goes wrong with OEM_RUSS, there is a charcode
+ mapping error between external name (z->name) and iname somewhere
+ in the in2ex & ex2in code. The charcode translation should be
+ checked.
+ This code line is changed back to the original code. */
+ /* CS, 6/12/2005: What is handled here is the difference between
+ ASCII charsets and non-ASCII charsets like the family of EBCDIC
+ charsets. On these systems, the slash character '/' is not coded
+ as 0x2f but as 0x61 (the ASCII 'a'). The iname struct member holds
+ the name as stored in the Zip file, which are ASCII or translated
+ into ASCII for new entries, whereas the "name" struct member hold
+ the external name, coded in the native charset of the system
+ (EBCDIC on EBCDIC systems) */
+ /* cutpath(z->iname, '/'); */ /* QQQ ??? */
+ cutpath(z->iname, 0x2f); /* 0x2f = ascii['/'] */
+ z->nam = strlen(z->iname);
+ if (z->nam > 0) {
+ z->iname[z->nam - 1] = (char)0x2f;
+ z->iname[z->nam++] = '\0';
+ }
+ if (z->nam > 0) n++;
+ }
+ } else {
+ n++;
+ }
+ }
+
+ /* Construct the list of all marked directories. Some may be duplicated
+ * if -D was used.
+ */
+ if (n)
+ {
+ if ((s = (struct zlist far **)malloc(n*sizeof(struct zlist far *))) ==
+ NULL)
+ return ZE_MEM;
+ n = 0;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (z->mark && z->nam > 0 && z->iname[z->nam - 1] == (char)0x2f /* '/' */
+ && (n == 0 || strcmp(z->name, s[n-1]->name) != 0)) {
+ s[n++] = z;
+ }
+ }
+ /* Sort the files in reverse order to get subdirectories first.
+ * To avoid problems with strange naming conventions as in VMS,
+ * we sort on the internal names, so x/y/z will always be removed
+ * before x/y. On VMS, x/y/z > x/y but [x.y.z] < [x.y]
+ */
+ qsort((char *)s, n, sizeof(struct zlist far *), rqcmp);
+
+ for (i = 0; i < n; i++) {
+ char *p = s[i]->name;
+ if (*p == '\0') continue;
+ if (p[strlen(p) - 1] == '/') { /* keep VMS [x.y]z.dir;1 intact */
+ p[strlen(p) - 1] = '\0';
+ }
+ if (i == 0 || strcmp(s[i]->name, s[i-1]->name) != 0) {
+ if (verbose) {
+ fprintf(mesg, "deleting directory %s (if empty) \n",
+ s[i]->name);
+ }
+ deletedir(s[i]->name);
+ }
+ }
+ free((zvoid *)s);
+ }
+ return ZE_OK;
+}
+
+#endif /* !UTIL */
diff --git a/zipnote.c b/zipnote.c
new file mode 100644
index 0000000..5e02cb6
--- /dev/null
+++ b/zipnote.c
@@ -0,0 +1,699 @@
+/*
+ zipnote.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * zipnote.c by Mark Adler.
+ */
+#define __ZIPNOTE_C
+
+#ifndef UTIL
+#define UTIL
+#endif
+#include "zip.h"
+#define DEFCPYRT /* main module: enable copyright string defines! */
+#include "revision.h"
+#include <signal.h>
+
+/* Calculate size of static line buffer used in write (-w) mode. */
+#define WRBUFSIZ 2047
+/* The line buffer size should be at least as large as FNMAX. */
+#if FNMAX > WRBUFSIZ
+# undef WRBUFSIZ
+# define WRBUFSIZ FNMAX
+#endif
+
+/* Character to mark zip entry names in the comment file */
+#define MARK '@'
+#define MARKE " (comment above this line)"
+#define MARKZ " (zip file comment below this line)"
+
+/* Temporary zip file pointer */
+local FILE *tempzf;
+
+
+/* Local functions */
+local void handler OF((int));
+local void license OF((void));
+local void help OF((void));
+local void version_info OF((void));
+local void putclean OF((char *, extent));
+/* getline name conflicts with GNU getline() function */
+local char *zgetline OF((char *, extent));
+local int catalloc OF((char * far *, char *));
+int main OF((int, char **));
+
+/* keep compiler happy until implement long options - 11/4/2003 EG */
+struct option_struct far options[] = {
+ /* short longopt value_type negatable ID name */
+ {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
+ /* the end of the list */
+ {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
+ };
+
+#ifdef MACOS
+#define ziperr(c, h) zipnoteerr(c, h)
+#define zipwarn(a, b) zipnotewarn(a, b)
+
+void zipnoteerr(int c, ZCONST char *h);
+void zipnotewarn(ZCONST char *a, ZCONST char *b);
+#endif
+
+#ifdef QDOS
+#define exit(p1) QDOSexit()
+#endif
+
+int set_filetype(out_path)
+ char *out_path;
+{
+#ifdef __BEOS__
+ /* Set the filetype of the zipfile to "application/zip" */
+ setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+ /* Set the filetype of the zipfile to "application/x-zip" */
+ setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+ /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+ setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+ /* Set the filetype of the zipfile to &DDC */
+ setfiletype(out_path, 0xDDC);
+#endif
+ return ZE_OK;
+}
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ */
+int rename_split(temp_name, out_path)
+ char *temp_name;
+ char *out_path;
+{
+ int r;
+ /* Replace old zip file with new zip file, leaving only the new one */
+ if ((r = replace(out_path, temp_name)) != ZE_OK)
+ {
+ zipwarn("new zip file left as: ", temp_name);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ZIPERR(r, "was replacing split file");
+ }
+ if (zip_attributes) {
+ setfileattr(out_path, zip_attributes);
+ }
+ return ZE_OK;
+}
+
+void zipmessage_nl(a, nl)
+ZCONST char *a; /* message string to output */
+int nl; /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+ If nl true, print and add new line. If logfile is
+ open then also write message to log file. */
+{
+ if (noisy) {
+ fprintf(mesg, "%s", a);
+ if (nl) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ } else {
+ mesg_line_started = 1;
+ }
+ fflush(mesg);
+ }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b; /* message strings juxtaposed in output */
+/* Print a message to mesg and flush. Also write to log file if
+ open. Write new line first if current line has output already. */
+{
+ if (noisy) {
+ if (mesg_line_started)
+ fprintf(mesg, "\n");
+ fprintf(mesg, "%s%s\n", a, b);
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+}
+
+void ziperr(c, h)
+int c; /* error code from the ZE_ class */
+ZCONST char *h; /* message about how it happened */
+/* Issue a message for the error, clean up files and memory, and exit. */
+{
+ if (PERR(c))
+ perror("zipnote error");
+ fprintf(mesg, "zipnote error: %s (%s)\n", ZIPERRORS(c), h);
+ if (tempzf != NULL)
+ fclose(tempzf);
+ if (tempzip != NULL)
+ {
+ destroy(tempzip);
+ free((zvoid *)tempzip);
+ }
+ if (zipfile != NULL)
+ free((zvoid *)zipfile);
+ EXIT(c);
+}
+
+
+local void handler(s)
+int s; /* signal number (ignored) */
+/* Upon getting a user interrupt, abort cleanly using ziperr(). */
+{
+#ifndef MSDOS
+ putc('\n', mesg);
+#endif /* !MSDOS */
+ ziperr(ZE_ABORT, "aborting");
+ s++; /* keep some compilers happy */
+}
+
+
+void zipwarn(a, b)
+ZCONST char *a, *b; /* message strings juxtaposed in output */
+/* Print a warning message to mesg (usually stderr) and return. */
+{
+ fprintf(mesg, "zipnote warning: %s%s\n", a, b);
+}
+
+
+local void license()
+/* Print license information to stdout. */
+{
+ extent i; /* counter for copyright array */
+
+ for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
+ puts(swlicense[i]);
+}
+
+
+local void help()
+/* Print help (along with license info) to stdout. */
+{
+ extent i; /* counter for help array */
+
+ /* help array */
+ static ZCONST char *text[] = {
+"",
+"ZipNote %s (%s)",
+#ifdef VM_CMS
+"Usage: zipnote [-w] [-q] [-b fm] zipfile",
+#else
+"Usage: zipnote [-w] [-q] [-b path] zipfile",
+#endif
+" the default action is to write the comments in zipfile to stdout",
+" -w write the zipfile comments from stdin",
+#ifdef VM_CMS
+" -b use \"fm\" as the filemode for the temporary zip file",
+#else
+" -b use \"path\" for the temporary zip file",
+#endif
+" -q quieter operation, suppress some informational messages",
+" -h show this help -v show version info -L show software license",
+"",
+"Example:",
+#ifdef VMS
+" define/user sys$output foo.tmp",
+" zipnote foo.zip",
+" edit foo.tmp",
+" ... then you edit the comments, save, and exit ...",
+" define/user sys$input foo.tmp",
+" zipnote -w foo.zip",
+#else
+#ifdef RISCOS
+" zipnote foo/zip > foo/tmp",
+" <!Edit> foo/tmp",
+" ... then you edit the comments, save, and exit ...",
+" zipnote -w foo/zip < foo/tmp",
+#else
+#ifdef VM_CMS
+" zipnote foo.zip > foo.tmp",
+" xedit foo tmp",
+" ... then you edit the comments, save, and exit ...",
+" zipnote -w foo.zip < foo.tmp",
+#else
+" zipnote foo.zip > foo.tmp",
+" ed foo.tmp",
+" ... then you edit the comments, save, and exit ...",
+" zipnote -w foo.zip < foo.tmp",
+#endif /* VM_CMS */
+#endif /* RISCOS */
+#endif /* VMS */
+"",
+" \"@ name\" can be followed by an \"@=newname\" line to change the name"
+ };
+
+ for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
+ printf(copyright[i], "zipnote");
+ putchar('\n');
+ }
+ for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+ {
+ printf(text[i], VERSION, REVDATE);
+ putchar('\n');
+ }
+}
+
+/*
+ * XXX put this in version.c
+ */
+
+local void version_info()
+/* Print verbose info about program version and compile time options
+ to stdout. */
+{
+ extent i; /* counter in text arrays */
+
+ /* Options info array */
+ static ZCONST char *comp_opts[] = {
+#ifdef DEBUG
+ "DEBUG",
+#endif
+ NULL
+ };
+
+ for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
+ {
+ printf(copyright[i], "zipnote");
+ putchar('\n');
+ }
+
+ for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+ {
+ printf(versinfolines[i], "ZipNote", VERSION, REVDATE);
+ putchar('\n');
+ }
+
+ version_local();
+
+ puts("ZipNote special compilation options:");
+ for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+ {
+ printf("\t%s\n",comp_opts[i]);
+ }
+ if (i == 0)
+ puts("\t[none]");
+}
+
+
+local void putclean(s, n)
+char *s; /* string to write to stdout */
+extent n; /* length of string */
+/* Write the string s to stdout, filtering out control characters that are
+ not tab or newline (mainly to remove carriage returns), and prefix MARK's
+ and backslashes with a backslash. Also, terminate with a newline if
+ needed. */
+{
+ int c; /* next character in string */
+ int e; /* last character written */
+
+ e = '\n'; /* if empty, write nothing */
+ while (n--)
+ {
+ c = *(uch *)s++;
+ if (c == MARK || c == '\\')
+ putchar('\\');
+ if (c >= ' ' || c == '\t' || c == '\n')
+ { e=c; putchar(e); }
+ }
+ if (e != '\n')
+ putchar('\n');
+}
+
+
+local char *zgetline(buf, size)
+char *buf;
+extent size;
+/* Read a line of text from stdin into string buffer 'buf' of size 'size'.
+ In case of buffer overflow or EOF, a NULL pointer is returned. */
+{
+ char *line;
+ unsigned len;
+
+ line = fgets(buf, size, stdin);
+ if (line != NULL && (len = strlen(line)) > 0) {
+ if (len == size-1 && line[len-1] != '\n') {
+ /* buffer is full and record delimiter not seen -> overflow */
+ line = NULL;
+ } else {
+ /* delete trailing record delimiter */
+ if (line[len-1] == '\n') line[len-1] = '\0';
+ }
+ }
+ return line;
+}
+
+
+local int catalloc(a, s)
+char * far *a; /* pointer to a pointer to a malloc'ed string */
+char *s; /* string to concatenate on a */
+/* Concatentate the string s to the malloc'ed string pointed to by a.
+ Preprocess s by removing backslash escape characters. */
+{
+ char *p; /* temporary pointer */
+ char *q; /* temporary pointer */
+
+ for (p = q = s; *q; *p++ = *q++)
+ if (*q == '\\' && *(q+1))
+ q++;
+ *p = 0;
+ if ((p = malloc(strlen(*a) + strlen(s) + 3)) == NULL)
+ return ZE_MEM;
+ strcat(strcat(strcpy(p, *a), **a ? "\r\n" : ""), s);
+ free((zvoid *)*a);
+ *a = p;
+ return ZE_OK;
+}
+
+
+#ifndef USE_ZIPNOTEMAIN
+int main(argc, argv)
+#else
+int zipnotemain(argc, argv)
+#endif
+int argc; /* number of tokens in command line */
+char **argv; /* command line tokens */
+/* Write the comments in the zipfile to stdout, or read them from stdin. */
+{
+ char abf[WRBUFSIZ+1]; /* input line buffer */
+ char *a; /* pointer to line buffer or NULL */
+ zoff_t c; /* start of central directory */
+ int k; /* next argument type */
+ char *q; /* steps through option arguments */
+ int r; /* arg counter, temporary variable */
+ zoff_t s; /* length of central directory */
+ int t; /* attributes of zip file */
+ int w; /* true if updating zip file from stdin */
+ FILE *x; /* input file for testing if can write it */
+ struct zlist far *z; /* steps through zfiles linked list */
+
+#ifdef THEOS
+ setlocale(LC_CTYPE, "I");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+ /* For Unix, set the locale to UTF-8. Any UTF-8 locale is
+ OK and they should all be the same. This allows seeing,
+ writing, and displaying (if the fonts are loaded) all
+ characters in UTF-8. */
+ {
+ char *loc;
+
+ /*
+ loc = setlocale(LC_CTYPE, NULL);
+ printf(" Initial language locale = '%s'\n", loc);
+ */
+
+ loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+ /*
+ printf("langinfo %s\n", nl_langinfo(CODESET));
+ */
+
+ if (loc != NULL) {
+ /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+ using_utf8 = 1;
+ /*
+ printf(" Locale set to %s\n", loc);
+ */
+ } else {
+ /*
+ printf(" Could not set Unicode UTF-8 locale\n");
+ */
+ }
+ }
+# endif
+#endif
+
+ /* If no args, show help */
+ if (argc == 1)
+ {
+ help();
+ EXIT(ZE_OK);
+ }
+
+ /* Direct info messages to stderr; stdout is used for data output. */
+ mesg = stderr;
+
+ init_upper(); /* build case map table */
+
+ /* Go through args */
+ zipfile = tempzip = NULL;
+ tempzf = NULL;
+ signal(SIGINT, handler);
+#ifdef SIGTERM /* AMIGA has no SIGTERM */
+ signal(SIGTERM, handler);
+#endif
+#ifdef SIGABRT
+ signal(SIGABRT, handler);
+#endif
+#ifdef SIGBREAK
+ signal(SIGBREAK, handler);
+#endif
+#ifdef SIGBUS
+ signal(SIGBUS, handler);
+#endif
+#ifdef SIGILL
+ signal(SIGILL, handler);
+#endif
+#ifdef SIGSEGV
+ signal(SIGSEGV, handler);
+#endif
+ k = w = 0;
+ for (r = 1; r < argc; r++)
+ if (*argv[r] == '-') {
+ if (argv[r][1])
+ for (q = argv[r]+1; *q; q++)
+ switch (*q)
+ {
+ case 'b': /* Specify path for temporary file */
+ if (k)
+ ziperr(ZE_PARMS, "use -b before zip file name");
+ else
+ k = 1; /* Next non-option is path */
+ break;
+ case 'h': /* Show help */
+ help(); EXIT(ZE_OK);
+ case 'l': case 'L': /* Show copyright and disclaimer */
+ license(); EXIT(ZE_OK);
+ case 'q': /* Quiet operation, suppress info messages */
+ noisy = 0; break;
+ case 'v': /* Show version info */
+ version_info(); EXIT(ZE_OK);
+ case 'w':
+ w = 1; break;
+ default:
+ ziperr(ZE_PARMS, "unknown option");
+ }
+ else
+ ziperr(ZE_PARMS, "zip file cannot be stdin");
+ } else
+ if (k == 0)
+ {
+ if (zipfile == NULL)
+ {
+ if ((zipfile = ziptyp(argv[r])) == NULL)
+ ziperr(ZE_MEM, "was processing arguments");
+ }
+ else
+ ziperr(ZE_PARMS, "can only specify one zip file");
+ }
+ else
+ {
+ tempath = argv[r];
+ k = 0;
+ }
+ if (zipfile == NULL)
+ ziperr(ZE_PARMS, "need to specify zip file");
+
+ if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+ ziperr(ZE_MEM, "input");
+ }
+ strcpy(in_path, zipfile);
+
+ /* Read zip file */
+ if ((r = readzipfile()) != ZE_OK)
+ ziperr(r, zipfile);
+ if (zfiles == NULL)
+ ziperr(ZE_NAME, zipfile);
+
+ /* Put comments to stdout, if not -w */
+ if (!w)
+ {
+ for (z = zfiles; z != NULL; z = z->nxt)
+ {
+ printf("%c %s\n", MARK, z->zname);
+ putclean(z->comment, z->com);
+ printf("%c%s\n", MARK, MARKE);
+ }
+ printf("%c%s\n", MARK, MARKZ);
+ putclean(zcomment, zcomlen);
+ EXIT(ZE_OK);
+ }
+
+ /* If updating comments, make sure zip file is writeable */
+ if ((x = fopen(zipfile, "a")) == NULL)
+ ziperr(ZE_CREAT, zipfile);
+ fclose(x);
+ t = getfileattr(zipfile);
+
+ /* Process stdin, replacing comments */
+ z = zfiles;
+ while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL &&
+ (a[0] != MARK || strcmp(a + 1, MARKZ)))
+ { /* while input and not file comment */
+ if (a[0] != MARK || a[1] != ' ') /* better be "@ name" */
+ ziperr(ZE_NOTE, "unexpected input");
+ while (z != NULL && strcmp(a + 2, z->zname))
+ z = z->nxt; /* allow missing entries in order */
+ if (z == NULL)
+ ziperr(ZE_NOTE, "unknown entry name");
+ if ((a = zgetline(abf, WRBUFSIZ+1)) != NULL && a[0] == MARK && a[1] == '=')
+ {
+ if (z->name != z->iname)
+ free((zvoid *)z->iname);
+ if ((z->iname = malloc(strlen(a+1))) == NULL)
+ ziperr(ZE_MEM, "was changing name");
+#ifdef EBCDIC
+ strtoasc(z->iname, a+2);
+#else
+ strcpy(z->iname, a+2);
+#endif
+
+/*
+ * Don't update z->nam here, we need the old value a little later.....
+ * The update is handled in zipcopy().
+ */
+ a = zgetline(abf, WRBUFSIZ+1);
+ }
+ if (z->com) /* change zip entry comment */
+ free((zvoid *)z->comment);
+ z->comment = malloc(1); *(z->comment) = 0;
+ while (a != NULL && *a != MARK)
+ {
+ if ((r = catalloc(&(z->comment), a)) != ZE_OK)
+ ziperr(r, "was building new zipentry comments");
+ a = zgetline(abf, WRBUFSIZ+1);
+ }
+ z->com = strlen(z->comment);
+ z = z->nxt; /* point to next entry */
+ }
+ if (a != NULL) /* change zip file comment */
+ {
+ zcomment = malloc(1); *zcomment = 0;
+ while ((a = zgetline(abf, WRBUFSIZ+1)) != NULL)
+ if ((r = catalloc(&zcomment, a)) != ZE_OK)
+ ziperr(r, "was building new zipfile comment");
+ zcomlen = strlen(zcomment);
+ }
+
+ /* Open output zip file for writing */
+#if defined(UNIX) && !defined(NO_MKSTEMP)
+ {
+ int yd;
+ int i;
+
+ /* use mkstemp to avoid race condition and compiler warning */
+
+ if (tempath != NULL)
+ {
+ /* if -b used to set temp file dir use that for split temp */
+ if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, tempath);
+ if (lastchar(tempzip) != '/')
+ strcat(tempzip, "/");
+ }
+ else
+ {
+ /* create path by stripping name and appending template */
+ if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
+ ZIPERR(ZE_MEM, "allocating temp filename");
+ }
+ strcpy(tempzip, zipfile);
+ for(i = strlen(tempzip); i > 0; i--) {
+ if (tempzip[i - 1] == '/')
+ break;
+ }
+ tempzip[i] = '\0';
+ }
+ strcat(tempzip, "ziXXXXXX");
+
+ if ((yd = mkstemp(tempzip)) == EOF) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ if ((tempzf = y = fdopen(yd, FOPW)) == NULL) {
+ ZIPERR(ZE_TEMP, tempzip);
+ }
+ }
+#else
+ if ((tempzf = y = fopen(tempzip = tempname(zipfile), FOPW)) == NULL)
+ ziperr(ZE_TEMP, tempzip);
+#endif
+
+ /* Open input zip file again, copy preamble if any */
+ if ((in_file = fopen(zipfile, FOPR)) == NULL)
+ ziperr(ZE_NAME, zipfile);
+
+ if (zipbeg && (r = bfcopy(zipbeg)) != ZE_OK)
+ ziperr(r, r == ZE_TEMP ? tempzip : zipfile);
+ tempzn = zipbeg;
+
+ /* Go through local entries, copying them over as is */
+ fix = 3; /* needed for zipcopy if name changed */
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if ((r = zipcopy(z)) != ZE_OK)
+ ziperr(r, "was copying an entry");
+ }
+ fclose(x);
+
+ /* Write central directory and end of central directory with new comments */
+ if ((c = zftello(y)) == (zoff_t)-1) /* get start of central */
+ ziperr(ZE_TEMP, tempzip);
+ for (z = zfiles; z != NULL; z = z->nxt)
+ if ((r = putcentral(z)) != ZE_OK)
+ ziperr(r, tempzip);
+ if ((s = zftello(y)) == (zoff_t)-1) /* get end of central */
+ ziperr(ZE_TEMP, tempzip);
+ s -= c; /* compute length of central */
+ if ((r = putend((zoff_t)zcount, s, c, zcomlen, zcomment)) != ZE_OK)
+ ziperr(r, tempzip);
+ tempzf = NULL;
+ if (fclose(y))
+ ziperr(ZE_TEMP, tempzip);
+ if ((r = replace(zipfile, tempzip)) != ZE_OK)
+ {
+ zipwarn("new zip file left as: ", tempzip);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ziperr(r, "was replacing the original zip file");
+ }
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ setfileattr(zipfile, t);
+#ifdef RISCOS
+ /* Set the filetype of the zipfile to &DDC */
+ setfiletype(zipfile,0xDDC);
+#endif
+ free((zvoid *)zipfile);
+ zipfile = NULL;
+
+ /* Done! */
+ RETURN(0);
+}
diff --git a/zipnote.txt b/zipnote.txt
new file mode 100644
index 0000000..cbafd28
--- /dev/null
+++ b/zipnote.txt
@@ -0,0 +1,63 @@
+zipnote(1) zipnote(1)
+
+NAME
+ zipnote - write the comments in zipfile to stdout, edit comments and
+ rename files in zipfile
+
+SYNOPSIS
+ zipnote [-w] [-b path] [-h] [-v] [-L] zipfile
+
+ARGUMENTS
+ zipfile Zipfile to read comments from or edit.
+
+OPTIONS
+ -w Write comments to a zipfile from stdin (see below).
+
+ -b path
+ Use path for the temporary zip file.
+
+ -h Show a short help.
+
+ -v Show version information.
+
+ -L Show software license.
+
+DESCRIPTION
+ zipnote writes the comments in a zipfile to stdout. This is the
+ default mode. A second mode allows updating the comments in a zipfile
+ as well as allows changing the names of the files in the zipfile.
+ These modes are described below.
+
+EXAMPLES
+ To write all comments in a zipfile to stdout use for example
+
+ zipnote foo.zip > foo.tmp
+
+ This writes all comments in the zipfile foo.zip to the file foo.tmp in
+ a specific format.
+
+ If desired, this file can then be edited to change the comments and
+ then used to update the zipfile.
+
+ zipnote -w foo.zip < foo.tmp
+
+ The names of the files in the zipfile can also be changed in this way.
+ This is done by following lines like
+ "@ name"
+ in the created temporary file (called foo.tmp here) with lines like
+ "@=newname"
+ and then using the -w option as above.
+
+BUGS
+ The temporary file format is rather specific and zipnote is rather
+ picky about it. It should be easier to change file names in a script.
+
+ Does not yet support large (> 2 GB) or split archives.
+
+SEE ALSO
+ zip(1), unzip(1)
+
+AUTHOR
+ Info-ZIP
+
+ v3.0 of 8 May 2008 zipnote(1)
diff --git a/zipsplit.c b/zipsplit.c
new file mode 100644
index 0000000..8db76a1
--- /dev/null
+++ b/zipsplit.c
@@ -0,0 +1,978 @@
+/*
+ zipsplit.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * zipsplit.c by Mark Adler.
+ */
+#define __ZIPSPLIT_C
+
+#ifndef UTIL
+#define UTIL
+#endif
+#include "zip.h"
+#define DEFCPYRT /* main module: enable copyright string defines! */
+#include "revision.h"
+#include <signal.h>
+
+#define DEFSIZ 36000L /* Default split size (change in help() too) */
+#ifdef MSDOS
+# define NL 2 /* Number of bytes written for a \n */
+#else /* !MSDOS */
+# define NL 1 /* Number of bytes written for a \n */
+#endif /* ?MSDOS */
+#ifdef RISCOS
+# define INDEX "zipspl/idx" /* Name of index file */
+# define TEMPL_FMT "%%0%dld"
+# define TEMPL_SIZ 13
+# define ZPATH_SEP '.'
+#else
+#ifdef QDOS
+# define ZPATH_SEP '_'
+# define INDEX "zipsplit_idx" /* Name of index file */
+# define TEMPL_FMT "%%0%dld_zip"
+# define TEMPL_SIZ 17
+# define exit(p1) QDOSexit()
+#else
+#ifdef VM_CMS
+# define INDEX "zipsplit.idx" /* Name of index file */
+# define TEMPL_FMT "%%0%dld.zip"
+# define TEMPL_SIZ 21
+# define ZPATH_SEP '.'
+#else
+# define INDEX "zipsplit.idx" /* Name of index file */
+# define TEMPL_FMT "%%0%dld.zip"
+# define TEMPL_SIZ 17
+# define ZPATH_SEP '.'
+#endif /* VM_CMS */
+#endif /* QDOS */
+#endif /* RISCOS */
+
+#ifdef MACOS
+#define ziperr(c, h) zipspliterr(c, h)
+#define zipwarn(a, b) zipsplitwarn(a, b)
+void zipsplitwarn(ZCONST char *a, ZCONST char *b);
+void zipspliterr(int c, ZCONST char *h);
+#endif /* MACOS */
+
+/* Local functions */
+local zvoid *talloc OF((extent));
+local void tfree OF((zvoid *));
+local void tfreeall OF((void));
+local void handler OF((int));
+local void license OF((void));
+local void help OF((void));
+local void version_info OF((void));
+local extent simple OF((uzoff_t *, extent, uzoff_t, uzoff_t));
+local int descmp OF((ZCONST zvoid *, ZCONST zvoid *));
+local extent greedy OF((uzoff_t *, extent, uzoff_t, uzoff_t));
+local int retry OF((void));
+int main OF((int, char **));
+
+
+/* Output zip files */
+local char template[TEMPL_SIZ]; /* name template for output files */
+local int zipsmade = 0; /* number of zip files made */
+local int indexmade = 0; /* true if index file made */
+local char *path = NULL; /* space for full name */
+local char *name; /* where name goes in path[] */
+
+
+/* The talloc() and tree() routines extend malloc() and free() to keep
+ track of all allocated memory. Then the tfreeall() routine uses this
+ information to free all allocated memory before exiting. */
+
+#define TMAX 6 /* set intelligently by examining the code */
+zvoid *talls[TMAX]; /* malloc'ed pointers to track */
+int talln = 0; /* number of entries in talls[] */
+
+
+int set_filetype(out_path)
+ char *out_path;
+{
+#ifdef __BEOS__
+ /* Set the filetype of the zipfile to "application/zip" */
+ setfiletype( out_path, "application/zip" );
+#endif
+
+#ifdef __ATHEOS__
+ /* Set the filetype of the zipfile to "application/x-zip" */
+ setfiletype(out_path, "application/x-zip");
+#endif
+
+#ifdef MACOS
+ /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */
+ setfiletype(out_path, 'IZip', 'ZIP ');
+#endif
+
+#ifdef RISCOS
+ /* Set the filetype of the zipfile to &DDC */
+ setfiletype(out_path, 0xDDC);
+#endif
+ return ZE_OK;
+}
+
+/* rename a split
+ * A split has a tempfile name until it is closed, then
+ * here rename it as out_path the final name for the split.
+ *
+ * This is not used in zipsplit but is referenced by the generic split
+ * writing code. If zipsplit is made split aware (so can write splits of
+ * splits, if that makes sense) then this would get used. But if that
+ * happens these utility versions should be dropped and the main ones
+ * used.
+ */
+int rename_split(temp_name, out_path)
+ char *temp_name;
+ char *out_path;
+{
+ int r;
+ /* Replace old zip file with new zip file, leaving only the new one */
+ if ((r = replace(out_path, temp_name)) != ZE_OK)
+ {
+ zipwarn("new zip file left as: ", temp_name);
+ free((zvoid *)tempzip);
+ tempzip = NULL;
+ ZIPERR(r, "was replacing split file");
+ }
+ if (zip_attributes) {
+ setfileattr(out_path, zip_attributes);
+ }
+ return ZE_OK;
+}
+
+void zipmessage_nl(a, nl)
+ZCONST char *a; /* message string to output */
+int nl; /* 1 = add nl to end */
+/* If nl false, print a message to mesg without new line.
+ If nl true, print and add new line. If logfile is
+ open then also write message to log file. */
+{
+ if (noisy) {
+ fprintf(mesg, "%s", a);
+ if (nl) {
+ fprintf(mesg, "\n");
+ mesg_line_started = 0;
+ } else {
+ mesg_line_started = 1;
+ }
+ fflush(mesg);
+ }
+}
+
+void zipmessage(a, b)
+ZCONST char *a, *b; /* message strings juxtaposed in output */
+/* Print a message to mesg and flush. Also write to log file if
+ open. Write new line first if current line has output already. */
+{
+ if (noisy) {
+ if (mesg_line_started)
+ fprintf(mesg, "\n");
+ fprintf(mesg, "%s%s\n", a, b);
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+}
+
+local zvoid *talloc(s)
+extent s;
+/* does a malloc() and saves the pointer to free later (does not check
+ for an overflow of the talls[] list) */
+{
+ zvoid *p;
+
+ if ((p = (zvoid *)malloc(s)) != NULL)
+ talls[talln++] = p;
+ return p;
+}
+
+
+local void tfree(p)
+zvoid *p;
+/* does a free() and also removes the pointer from the talloc() list */
+{
+ int i;
+
+ free(p);
+ i = talln;
+ while (i--)
+ if (talls[i] == p)
+ break;
+ if (i >= 0)
+ {
+ while (++i < talln)
+ talls[i - 1] = talls[i];
+ talln--;
+ }
+}
+
+
+local void tfreeall()
+/* free everything talloc'ed and not tfree'd */
+{
+ while (talln)
+ free(talls[--talln]);
+}
+
+
+void ziperr(c, h)
+int c; /* error code from the ZE_ class */
+ZCONST char *h; /* message about how it happened */
+/* Issue a message for the error, clean up files and memory, and exit. */
+{
+ if (PERR(c))
+ perror("zipsplit error");
+ fprintf(mesg, "zipsplit error: %s (%s)\n", ZIPERRORS(c), h);
+ if (indexmade)
+ {
+ strcpy(name, INDEX);
+ destroy(path);
+ }
+ for (; zipsmade; zipsmade--)
+ {
+ sprintf(name, template, zipsmade);
+ destroy(path);
+ }
+ tfreeall();
+ if (zipfile != NULL)
+ free((zvoid *)zipfile);
+ EXIT(c);
+}
+
+
+local void handler(s)
+int s; /* signal number (ignored) */
+/* Upon getting a user interrupt, abort cleanly using ziperr(). */
+{
+#ifndef MSDOS
+ putc('\n', mesg);
+#endif /* !MSDOS */
+ ziperr(ZE_ABORT, "aborting");
+ s++; /* keep some compilers happy */
+}
+
+
+void zipwarn(a, b)
+ZCONST char *a, *b; /* message strings juxtaposed in output */
+/* Print a warning message to mesg (usually stderr) and return. */
+{
+ fprintf(mesg, "zipsplit warning: %s%s\n", a, b);
+}
+
+
+local void license()
+/* Print license information to stdout. */
+{
+ extent i; /* counter for copyright array */
+
+ for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++)
+ puts(swlicense[i]);
+}
+
+
+local void help()
+/* Print help (along with license info) to stdout. */
+{
+ extent i; /* counter for help array */
+
+ /* help array */
+ static ZCONST char *text[] = {
+"",
+"ZipSplit %s (%s)",
+#ifdef VM_CMS
+"Usage: zipsplit [-tipqs] [-n size] [-r room] [-b fm] zipfile",
+#else
+"Usage: zipsplit [-tipqs] [-n size] [-r room] [-b path] zipfile",
+#endif
+" -t report how many files it will take, but don't make them",
+#ifdef RISCOS
+" -i make index (" INDEX ") and count its size against first zip file",
+#else
+" -i make index (zipsplit.idx) and count its size against first zip file",
+#endif
+" -n make zip files no larger than \"size\" (default = 36000)",
+" -r leave room for \"room\" bytes on the first disk (default = 0)",
+#ifdef VM_CMS
+" -b use \"fm\" as the filemode for the output zip files",
+#else
+" -b use \"path\" for the output zip files",
+#endif
+" -q quieter operation, suppress some informational messages",
+" -p pause between output zip files",
+" -s do a sequential split even if it takes more zip files",
+" -h show this help -v show version info -L show software license"
+ };
+
+ for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) {
+ printf(copyright[i], "zipsplit");
+ putchar('\n');
+ }
+ for (i = 0; i < sizeof(text)/sizeof(char *); i++)
+ {
+ printf(text[i], VERSION, REVDATE);
+ putchar('\n');
+ }
+}
+
+
+local void version_info()
+/* Print verbose info about program version and compile time options
+ to stdout. */
+{
+ extent i; /* counter in text arrays */
+
+ /* Options info array */
+ static ZCONST char *comp_opts[] = {
+#ifdef DEBUG
+ "DEBUG",
+#endif
+ NULL
+ };
+
+ for (i = 0; i < sizeof(versinfolines)/sizeof(char *); i++)
+ {
+ printf(versinfolines[i], "ZipSplit", VERSION, REVDATE);
+ putchar('\n');
+ }
+
+ version_local();
+
+ puts("ZipSplit special compilation options:");
+ for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++)
+ {
+ printf("\t%s\n",comp_opts[i]);
+ }
+ if (i == 0)
+ puts("\t[none]");
+}
+
+
+local extent simple(a, n, c, d)
+uzoff_t *a; /* items to put in bins, return value: destination bins */
+extent n; /* number of items */
+uzoff_t c; /* capacity of each bin */
+uzoff_t d; /* amount to deduct from first bin */
+/* Return the number of bins of capacity c that are needed to contain the
+ integers in a[0..n-1] placed sequentially into the bins. The value d
+ is deducted initially from the first bin (space for index). The entries
+ in a[] are replaced by the destination bins. */
+{
+ extent k; /* current bin number */
+ uzoff_t t; /* space used in current bin */
+
+ t = k = 0;
+ while (n--)
+ {
+ if (*a + t > c - (k == 0 ? d : 0))
+ {
+ k++;
+ t = 0;
+ }
+ t += *a;
+ *(ulg huge *)a++ = k;
+ }
+ return k + 1;
+}
+
+
+local int descmp(a, b)
+ZCONST zvoid *a, *b; /* pointers to pointers to ulg's to compare */
+/* Used by qsort() in greedy() to do a descending sort. */
+{
+ return **(uzoff_t **)a < **(uzoff_t **)b ? 1 :
+ (**(uzoff_t **)a > **(uzoff_t **)b ? -1 : 0);
+}
+
+
+local extent greedy(a, n, c, d)
+uzoff_t *a; /* items to put in bins, return value: destination bins */
+extent n; /* number of items */
+uzoff_t c; /* capacity of each bin */
+uzoff_t d; /* amount to deduct from first bin */
+/* Return the number of bins of capacity c that are needed to contain the
+ items with sizes a[0..n-1] placed non-sequentially into the bins. The
+ value d is deducted initially from the first bin (space for index).
+ The entries in a[] are replaced by the destination bins. */
+{
+ uzoff_t *b; /* space left in each bin (malloc'ed for each m) */
+ uzoff_t *e; /* copy of argument a[] (malloc'ed) */
+ extent i; /* steps through items */
+ extent j; /* steps through bins */
+ extent k; /* best bin to put current item in */
+ extent m; /* current number of bins */
+ uzoff_t **s; /* pointers to e[], sorted descending (malloc'ed) */
+ uzoff_t t; /* space left in best bin (index k) */
+
+ /* Algorithm:
+ 1. Copy a[] to e[] and sort pointers to e[0..n-1] (in s[]), in
+ descending order.
+ 2. Compute total of s[] and set m to the smallest number of bins of
+ capacity c that can hold the total.
+ 3. Allocate m bins.
+ 4. For each item in s[], starting with the largest, put it in the
+ bin with the smallest current capacity greater than or equal to the
+ item's size. If no bin has enough room, increment m and go to step 4.
+ 5. Else, all items ended up in a bin--return m.
+ */
+
+ /* Copy a[] to e[], put pointers to e[] in s[], and sort s[]. Also compute
+ the initial number of bins (minus 1). */
+ if ((e = (uzoff_t *)malloc(n * sizeof(uzoff_t))) == NULL ||
+ (s = (uzoff_t **)malloc(n * sizeof(uzoff_t *))) == NULL)
+ {
+ if (e != NULL)
+ free((zvoid *)e);
+ ziperr(ZE_MEM, "was trying a smart split");
+ return 0; /* only to make compiler happy */
+ }
+ memcpy((char *)e, (char *)a, n * sizeof(uzoff_t));
+ for (t = i = 0; i < n; i++)
+ t += *(s[i] = e + i);
+ m = (extent)((t + c - 1) / c) - 1; /* pre-decrement for loop */
+ qsort((char *)s, n, sizeof(ulg *), descmp);
+
+ /* Stuff bins until successful */
+ do {
+ /* Increment the number of bins, allocate and initialize bins */
+ if ((b = (uzoff_t *)malloc(++m * sizeof(uzoff_t))) == NULL)
+ {
+ free((zvoid *)s);
+ free((zvoid *)e);
+ ziperr(ZE_MEM, "was trying a smart split");
+ }
+ b[0] = c - d; /* leave space in first bin */
+ for (j = 1; j < m; j++)
+ b[j] = c;
+
+ /* Fill the bins greedily */
+ for (i = 0; i < n; i++)
+ {
+ /* Find smallest bin that will hold item i (size s[i]) */
+ t = c + 1;
+ for (k = j = 0; j < m; j++)
+ if (*s[i] <= b[j] && b[j] < t)
+ t = b[k = j];
+
+ /* If no bins big enough for *s[i], try next m */
+ if (t == c + 1)
+ break;
+
+ /* Diminish that bin and save where it goes */
+ b[k] -= *s[i];
+ a[(int)((uzoff_t huge *)(s[i]) - (uzoff_t huge *)e)] = k;
+ }
+
+ /* Clean up */
+ free((zvoid *)b);
+
+ /* Do until all items put in a bin */
+ } while (i < n);
+
+ /* Done--clean up and return the number of bins needed */
+ free((zvoid *)s);
+ free((zvoid *)e);
+ return m;
+}
+
+/* keep compiler happy until implement long options - 11/4/2003 EG */
+struct option_struct far options[] = {
+ /* short longopt value_type negatable ID name */
+ {"h", "help", o_NO_VALUE, o_NOT_NEGATABLE, 'h', "help"},
+ /* the end of the list */
+ {NULL, NULL, o_NO_VALUE, o_NOT_NEGATABLE, 0, NULL} /* end has option_ID = 0 */
+ };
+
+
+local int retry()
+{
+ char m[10];
+ fputs("Error writing to disk--redo entire disk? ", mesg);
+ fgets(m, 10, stdin);
+ return *m == 'y' || *m == 'Y';
+}
+
+
+#ifndef USE_ZIPSPLITMAIN
+int main(argc, argv)
+#else
+int zipsplitmain(argc, argv)
+#endif
+
+int argc; /* number of tokens in command line */
+char **argv; /* command line tokens */
+/* Split a zip file into several zip files less than a specified size. See
+ the command help in help() above. */
+{
+ uzoff_t *a; /* malloc'ed list of sizes, dest bins */
+ extent *b; /* heads of bin linked lists (malloc'ed) */
+ uzoff_t c; /* bin capacity, start of central directory */
+ int d; /* if true, just report the number of disks */
+ FILE *e; /* input zip file */
+ FILE *f; /* output index and zip files */
+ extent g; /* number of bins from greedy(), entry to write */
+ int h; /* how to split--true means simple split, counter */
+ zoff_t i = 0; /* size of index file plus room to leave */
+ extent j; /* steps through zip entries, bins */
+ int k; /* next argument type */
+ extent *n = NULL; /* next item in bin list (heads in b) */
+ uzoff_t *p; /* malloc'ed list of sizes, dest bins for greedy() */
+ char *q; /* steps through option characters */
+ int r; /* temporary variable, counter */
+ extent s; /* number of bins needed */
+ zoff_t t; /* total of sizes, end of central directory */
+ int u; /* flag to wait for user on output files */
+ struct zlist far **w; /* malloc'ed table for zfiles linked list */
+ int x; /* if true, make an index file */
+ struct zlist far *z; /* steps through zfiles linked list */
+#ifdef AMIGA
+ char tailchar; /* temporary variable used in name generation below */
+#endif
+ char errbuf[5000];
+
+#ifdef THEOS
+ setlocale(LC_CTYPE, "I");
+#endif
+
+#ifdef UNICODE_SUPPORT
+# ifdef UNIX
+ /* For Unix, set the locale to UTF-8. Any UTF-8 locale is
+ OK and they should all be the same. This allows seeing,
+ writing, and displaying (if the fonts are loaded) all
+ characters in UTF-8. */
+ {
+ char *loc;
+
+ /*
+ loc = setlocale(LC_CTYPE, NULL);
+ printf(" Initial language locale = '%s'\n", loc);
+ */
+
+ loc = setlocale(LC_CTYPE, "en_US.UTF-8");
+
+ /*
+ printf("langinfo %s\n", nl_langinfo(CODESET));
+ */
+
+ if (loc != NULL) {
+ /* using UTF-8 character set so can set UTF-8 GPBF bit 11 */
+ using_utf8 = 1;
+ /*
+ printf(" Locale set to %s\n", loc);
+ */
+ } else {
+ /*
+ printf(" Could not set Unicode UTF-8 locale\n");
+ */
+ }
+ }
+# endif
+#endif
+
+ /* If no args, show help */
+ if (argc == 1)
+ {
+ help();
+ EXIT(ZE_OK);
+ }
+
+ /* Informational messages are written to stdout. */
+ mesg = stdout;
+
+ init_upper(); /* build case map table */
+
+ /* Go through args */
+ signal(SIGINT, handler);
+#ifdef SIGTERM /* Amiga has no SIGTERM */
+ signal(SIGTERM, handler);
+#endif
+#ifdef SIGABRT
+ signal(SIGABRT, handler);
+#endif
+#ifdef SIGBREAK
+ signal(SIGBREAK, handler);
+#endif
+#ifdef SIGBUS
+ signal(SIGBUS, handler);
+#endif
+#ifdef SIGILL
+ signal(SIGILL, handler);
+#endif
+#ifdef SIGSEGV
+ signal(SIGSEGV, handler);
+#endif
+ k = h = x = d = u = 0;
+ c = DEFSIZ;
+ for (r = 1; r < argc; r++)
+ if (*argv[r] == '-')
+ {
+ if (argv[r][1])
+ for (q = argv[r]+1; *q; q++)
+ switch (*q)
+ {
+ case 'b': /* Specify path for output files */
+ if (k)
+ ziperr(ZE_PARMS, "options are separate and precede zip file");
+ else
+ k = 1; /* Next non-option is path */
+ break;
+ case 'h': /* Show help */
+ help(); EXIT(ZE_OK);
+ case 'i': /* Make an index file */
+ x = 1;
+ break;
+ case 'l': case 'L': /* Show copyright and disclaimer */
+ license(); EXIT(ZE_OK);
+ case 'n': /* Specify maximum size of resulting zip files */
+ if (k)
+ ziperr(ZE_PARMS, "options are separate and precede zip file");
+ else
+ k = 2; /* Next non-option is size */
+ break;
+ case 'p':
+ u = 1;
+ break;
+ case 'q': /* Quiet operation, suppress info messages */
+ noisy = 0;
+ break;
+ case 'r':
+ if (k)
+ ziperr(ZE_PARMS, "options are separate and precede zip file");
+ else
+ k = 3; /* Next non-option is room to leave */
+ break;
+ case 's':
+ h = 1; /* Only try simple */
+ break;
+ case 't': /* Just report number of disks */
+ d = 1;
+ break;
+ case 'v': /* Show version info */
+ version_info(); EXIT(ZE_OK);
+ default:
+ ziperr(ZE_PARMS, "Use option -h for help.");
+ }
+ else
+ ziperr(ZE_PARMS, "zip file cannot be stdin");
+ }
+ else
+ switch (k)
+ {
+ case 0:
+ if (zipfile == NULL)
+ {
+ if ((zipfile = ziptyp(argv[r])) == NULL)
+ ziperr(ZE_MEM, "was processing arguments");
+ }
+ else
+ ziperr(ZE_PARMS, "can only specify one zip file");
+ break;
+ case 1:
+ tempath = argv[r];
+ k = 0;
+ break;
+ case 2:
+ if ((c = (ulg)atol(argv[r])) < 100) /* 100 is smallest zip file */
+ ziperr(ZE_PARMS, "invalid size given. Use option -h for help.");
+ k = 0;
+ break;
+ default: /* k must be 3 */
+ i = (ulg)atol(argv[r]);
+ k = 0;
+ break;
+ }
+ if (zipfile == NULL)
+ ziperr(ZE_PARMS, "need to specify zip file");
+
+ if ((in_path = malloc(strlen(zipfile) + 1)) == NULL) {
+ ziperr(ZE_MEM, "input");
+ }
+ strcpy(in_path, zipfile);
+
+ /* Read zip file */
+ if ((r = readzipfile()) != ZE_OK)
+ ziperr(r, zipfile);
+ if (zfiles == NULL)
+ ziperr(ZE_NAME, zipfile);
+
+ /* Make a list of sizes and check against capacity. Also compute the
+ size of the index file. */
+ c -= ENDHEAD + 4; /* subtract overhead/zipfile */
+ if ((a = (uzoff_t *)talloc(zcount * sizeof(uzoff_t))) == NULL ||
+ (w = (struct zlist far **)talloc(zcount * sizeof(struct zlist far *))) ==
+ NULL)
+ {
+ ziperr(ZE_MEM, "was computing split");
+ return 1;
+ }
+ t = 0;
+ for (j = 0, z = zfiles; j < zcount; j++, z = z->nxt)
+ {
+ w[j] = z;
+ if (x)
+ i += z->nam + 6 + NL;
+ /* New scanzip_reg only reads central directory so use cext for ext */
+ t += a[j] = 8 + LOCHEAD + CENHEAD +
+ 2 * (zoff_t)z->nam + 2 * (zoff_t)z->cext + z->com + z->siz;
+ if (a[j] > c) {
+ sprintf(errbuf, "Entry is larger than max split size of: %s",
+ zip_fzofft(c, NULL, "u"));
+ zipwarn(errbuf, "");
+ zipwarn("use -n to set split size", "");
+ ziperr(ZE_BIG, z->zname);
+ }
+ }
+
+ /* Decide on split to use, report number of files */
+ if (h)
+ s = simple(a, zcount, c, i);
+ else
+ {
+ if ((p = (uzoff_t *)talloc(zcount * sizeof(uzoff_t))) == NULL)
+ ziperr(ZE_MEM, "was computing split");
+ memcpy((char *)p, (char *)a, zcount * sizeof(uzoff_t));
+ s = simple(a, zcount, c, i);
+ g = greedy(p, zcount, c, i);
+ if (s <= g)
+ tfree((zvoid *)p);
+ else
+ {
+ tfree((zvoid *)a);
+ a = p;
+ s = g;
+ }
+ }
+ printf("%ld zip files w%s be made (%s%% efficiency)\n",
+ (ulg)s, d ? "ould" : "ill",
+ zip_fzofft( ((200 * ((t + c - 1)/c)) / s + 1) / 2, NULL, "d"));
+ if (d)
+ {
+ tfreeall();
+ free((zvoid *)zipfile);
+ zipfile = NULL;
+ EXIT(ZE_OK);
+ }
+
+ /* Set up path for output files */
+ /* Point "name" past the path, where the filename should go */
+ if ((path = (char *)talloc(tempath == NULL ? 13 : strlen(tempath) + 14)) ==
+ NULL)
+ ziperr(ZE_MEM, "was making output file names");
+ if (tempath == NULL)
+ name = path;
+ else
+ {
+#ifndef VM_CMS
+ /* Copy the output path to the target */
+ strcpy(path, tempath);
+#endif
+#ifdef AMIGA
+ tailchar = path[strlen(path) - 1]; /* last character */
+ if (path[0] && (tailchar != '/') && (tailchar != ':'))
+ strcat(path, "/");
+#else
+#ifdef RISCOS
+ if (path[0] && path[strlen(path) - 1] != '.')
+ strcat(path, ".");
+#else
+#ifdef QDOS
+ if (path[0] && path[strlen(path) - 1] != '_')
+ strcat(path, "_");
+#else
+#ifndef VMS
+ if (path[0] && path[strlen(path) - 1] != '/')
+ strcat(path, "/");
+#endif /* !VMS */
+#endif /* ?QDOS */
+#endif /* ?RISCOS */
+#endif /* ?AMIGA */
+ name = path + strlen(path);
+ }
+
+ /* Make linked lists of results */
+ if ((b = (extent *)talloc(s * sizeof(extent))) == NULL ||
+ (n = (extent *)talloc(zcount * sizeof(extent))) == NULL)
+ ziperr(ZE_MEM, "was computing split");
+ for (j = 0; j < s; j++)
+ b[j] = (extent)-1;
+ j = zcount;
+ while (j--)
+ {
+ g = (extent)a[j];
+ n[j] = b[g];
+ b[g] = j;
+ }
+
+ /* Make a name template for the zip files that is eight or less characters
+ before the .zip, and that will not overwrite the original zip file. */
+ for (k = 1, j = s; j >= 10; j /= 10)
+ k++;
+ if (k > 7)
+ ziperr(ZE_PARMS, "way too many zip files must be made");
+/*
+ * XXX, ugly ....
+ */
+/* Find the final "path" separator character */
+#ifdef QDOS
+ q = LastDir(zipfile);
+#else
+#ifdef VMS
+ if ((q = strrchr(zipfile, ']')) != NULL)
+#else
+#ifdef AMIGA
+ if (((q = strrchr(zipfile, '/')) != NULL)
+ || ((q = strrchr(zipfile, ':'))) != NULL)
+#else
+#ifdef RISCOS
+ if ((q = strrchr(zipfile, '.')) != NULL)
+#else
+#ifdef MVS
+ if ((q = strrchr(zipfile, '.')) != NULL)
+#else
+ if ((q = strrchr(zipfile, '/')) != NULL)
+#endif /* MVS */
+#endif /* RISCOS */
+#endif /* AMIGA */
+#endif /* VMS */
+ q++;
+ else
+ q = zipfile;
+#endif /* QDOS */
+
+ r = 0;
+ while ((g = *q++) != '\0' && g != ZPATH_SEP && r < 8 - k)
+ template[r++] = (char)g;
+ if (r == 0)
+ template[r++] = '_';
+ else if (g >= '0' && g <= '9')
+ template[r - 1] = (char)(template[r - 1] == '_' ? '-' : '_');
+ sprintf(template + r, TEMPL_FMT, k);
+#ifdef VM_CMS
+ /* For CMS, add the "path" as the filemode at the end */
+ if (tempath)
+ {
+ strcat(template,".");
+ strcat(template,tempath);
+ }
+#endif
+
+ /* Make the zip files from the linked lists of entry numbers */
+ if ((e = fopen(zipfile, FOPR)) == NULL)
+ ziperr(ZE_NAME, zipfile);
+ free((zvoid *)zipfile);
+ zipfile = NULL;
+ for (j = 0; j < s; j++)
+ {
+ /* jump here on a disk retry */
+ redobin:
+
+ current_disk = 0;
+ cd_start_disk = 0;
+ cd_entries_this_disk = 0;
+
+ /* prompt if requested */
+ if (u)
+ {
+ char m[10];
+ fprintf(mesg, "Insert disk #%ld of %ld and hit return: ",
+ (ulg)j + 1, (ulg)s);
+ fgets(m, 10, stdin);
+ }
+
+ /* write index file on first disk if requested */
+ if (j == 0 && x)
+ {
+ strcpy(name, INDEX);
+ printf("creating: %s\n", path);
+ indexmade = 1;
+ if ((f = fopen(path, "w")) == NULL)
+ {
+ if (u && retry()) goto redobin;
+ ziperr(ZE_CREAT, path);
+ }
+ for (j = 0; j < zcount; j++)
+ fprintf(f, "%5s %s\n",
+ zip_fzofft( (a[j] + 1), NULL, "d"), w[j]->zname);
+
+ if ((j = ferror(f)) != 0 || fclose(f))
+ {
+ if (j)
+ fclose(f);
+ if (u && retry()) goto redobin;
+ ziperr(ZE_WRITE, path);
+ }
+ }
+
+ /* create output zip file j */
+ sprintf(name, template, j + 1L);
+ printf("creating: %s\n", path);
+ zipsmade = j + 1;
+ if ((y = f = fopen(path, FOPW)) == NULL)
+ {
+ if (u && retry()) goto redobin;
+ ziperr(ZE_CREAT, path);
+ }
+ bytes_this_split = 0;
+ tempzn = 0;
+
+ /* write local headers and copy compressed data */
+ for (g = b[j]; g != (extent)-1; g = (extent)n[g])
+ {
+ if (zfseeko(e, w[g]->off, SEEK_SET))
+ ziperr(ferror(e) ? ZE_READ : ZE_EOF, zipfile);
+ in_file = e;
+ if ((r = zipcopy(w[g])) != ZE_OK)
+ {
+ if (r == ZE_TEMP)
+ {
+ if (u && retry()) goto redobin;
+ ziperr(ZE_WRITE, path);
+ }
+ else
+ ziperr(r, zipfile);
+ }
+ }
+
+ /* write central headers */
+ if ((c = zftello(f)) == (uzoff_t)-1)
+ {
+ if (u && retry()) goto redobin;
+ ziperr(ZE_WRITE, path);
+ }
+ for (g = b[j], k = 0; g != (extent)-1; g = n[g], k++)
+ if ((r = putcentral(w[g])) != ZE_OK)
+ {
+ if (u && retry()) goto redobin;
+ ziperr(ZE_WRITE, path);
+ }
+
+ /* write end-of-central header */
+ cd_start_offset = c;
+ total_cd_entries = k;
+ if ((t = zftello(f)) == (zoff_t)-1 ||
+ (r = putend((zoff_t)k, t - c, c, (extent)0, (char *)NULL)) !=
+ ZE_OK ||
+ ferror(f) || fclose(f))
+ {
+ if (u && retry()) goto redobin;
+ ziperr(ZE_WRITE, path);
+ }
+#ifdef RISCOS
+ /* Set the filetype to &DDC */
+ setfiletype(path,0xDDC);
+#endif
+ }
+ fclose(e);
+
+ /* Done! */
+ if (u)
+ fputs("Done.\n", mesg);
+ tfreeall();
+
+ RETURN(0);
+}
diff --git a/zipsplit.txt b/zipsplit.txt
new file mode 100644
index 0000000..bd78ad7
--- /dev/null
+++ b/zipsplit.txt
@@ -0,0 +1,53 @@
+zipnote(1) zipnote(1)
+
+NAME
+ zipsplit - split a zipfile into smaller zipfiles
+
+SYNOPSIS
+ zipsplit [-t] [-i] [-p] [-s] [-n size] [-r room] [-b path] [-h] [-v]
+ [-L] zipfile
+
+ARGUMENTS
+ zipfile Zipfile to split.
+
+OPTIONS
+ -t Report how many files it will take, but don't make them.
+
+ -i Make index (zipsplit.idx) and count its size against first zip
+ file.
+
+ -n size
+ Make zip files no larger than "size" (default = 36000).
+
+ -r room
+ Leave room for "room" bytes on the first disk (default = 0).
+
+ -b path
+ Use path for the output zip files.
+
+ -p Pause between output zip files.
+
+ -s Do a sequential split even if it takes more zip files.
+
+ -h Show a short help.
+
+ -v Show version information.
+
+ -L Show software license.
+
+DESCRIPTION
+ zipsplit reads a zipfile and splits it into smaller zipfiles.
+
+EXAMPLES
+ To be filled in.
+
+BUGS
+ Does not yet support large (> 2 GB) or split archives.
+
+SEE ALSO
+ zip(1), unzip(1)
+
+AUTHOR
+ Info-ZIP
+
+ v3.0 of 8 May 2008 zipnote(1)
diff --git a/zipup.c b/zipup.c
new file mode 100644
index 0000000..39f7d9c
--- /dev/null
+++ b/zipup.c
@@ -0,0 +1,1922 @@
+/*
+ zipup.c - Zip 3
+
+ Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+ * zipup.c by Mark Adler and Jean-loup Gailly.
+ */
+#define __ZIPUP_C
+
+/* Found that for at least unix port zip.h has to be first or ctype.h will
+ define off_t and when using 64-bit file environment off_t in other files
+ is 8 bytes while off_t here is 4 bytes, and this makes the zlist struct
+ different sizes and needless to say leads to segmentation faults. Putting
+ zip.h first seems to fix this. 8/14/04 EG */
+#include "zip.h"
+#include <ctype.h>
+#include <errno.h>
+
+#ifndef UTIL /* This module contains no code for Zip Utilities */
+
+#include "revision.h"
+#include "crc32.h"
+#include "crypt.h"
+#ifdef USE_ZLIB
+# include "zlib.h"
+#endif
+#ifdef BZIP2_SUPPORT
+# ifdef BZIP2_USEBZIP2DIR
+# include "bzip2/bzlib.h"
+# else
+# include "bzlib.h"
+# endif
+#endif
+
+#ifdef OS2
+# include "os2/os2zip.h"
+#endif
+
+#if defined(MMAP)
+# include <sys/mman.h>
+# ifndef PAGESIZE /* used to be SYSV, what about pagesize on SVR3 ? */
+# define PAGESIZE getpagesize()
+# endif
+# if defined(NO_VALLOC) && !defined(valloc)
+# define valloc malloc
+# endif
+#endif
+
+/* Use the raw functions for MSDOS and Unix to save on buffer space.
+ They're not used for VMS since it doesn't work (raw is weird on VMS).
+ */
+
+#ifdef AMIGA
+# include "amiga/zipup.h"
+#endif /* AMIGA */
+
+#ifdef AOSVS
+# include "aosvs/zipup.h"
+#endif /* AOSVS */
+
+#ifdef ATARI
+# include "atari/zipup.h"
+#endif
+
+#ifdef __BEOS__
+# include "beos/zipup.h"
+#endif
+
+#ifdef __ATHEOS__
+# include "atheos/zipup.h"
+#endif /* __ATHEOS__ */
+
+#ifdef __human68k__
+# include "human68k/zipup.h"
+#endif /* __human68k__ */
+
+#ifdef MACOS
+# include "macos/zipup.h"
+#endif
+
+#ifdef DOS
+# include "msdos/zipup.h"
+#endif /* DOS */
+
+#ifdef NLM
+# include "novell/zipup.h"
+# include <nwfattr.h>
+#endif
+
+#ifdef OS2
+# include "os2/zipup.h"
+#endif /* OS2 */
+
+#ifdef RISCOS
+# include "acorn/zipup.h"
+#endif
+
+#ifdef TOPS20
+# include "tops20/zipup.h"
+#endif
+
+#ifdef UNIX
+# include "unix/zipup.h"
+#endif
+
+#ifdef CMS_MVS
+# include "zipup.h"
+#endif /* CMS_MVS */
+
+#ifdef TANDEM
+# include "zipup.h"
+#endif /* TANDEM */
+
+#ifdef VMS
+# include "vms/zipup.h"
+#endif /* VMS */
+
+#ifdef QDOS
+# include "qdos/zipup.h"
+#endif /* QDOS */
+
+#ifdef WIN32
+# include "win32/zipup.h"
+#endif
+
+#ifdef THEOS
+# include "theos/zipup.h"
+#endif
+
+/* Local functions */
+#ifndef RISCOS
+ local int suffixes OF((char *, char *));
+#else
+ local int filetypes OF((char *, char *));
+#endif
+local unsigned file_read OF((char *buf, unsigned size));
+#ifdef USE_ZLIB
+ local int zl_deflate_init OF((int pack_level));
+#else /* !USE_ZLIB */
+# ifdef ZP_NEED_MEMCOMPR
+ local unsigned mem_read OF((char *buf, unsigned size));
+# endif
+#endif /* ?USE_ZLIB */
+
+/* zip64 support 08/29/2003 R.Nausedat */
+local zoff_t filecompress OF((struct zlist far *z_entry, int *cmpr_method));
+
+#ifdef BZIP2_SUPPORT
+local zoff_t bzfilecompress OF((struct zlist far *z_entry, int *cmpr_method));
+#endif
+
+/* Deflate "internal" global data (currently not in zip.h) */
+#if defined(MMAP) || defined(BIG_MEM)
+# ifdef USE_ZLIB
+ local uch *window = NULL; /* Used to read all input file at once */
+ local ulg window_size; /* size of said window */
+# else /* !USE_ZLIB */
+ extern uch *window; /* Used to read all input file at once */
+#endif /* ?USE_ZLIB */
+#endif /* MMAP || BIG_MEM */
+#ifndef USE_ZLIB
+ extern ulg window_size; /* size of said window */
+
+ unsigned (*read_buf) OF((char *buf, unsigned size)) = file_read;
+ /* Current input function. Set to mem_read for in-memory compression */
+#endif /* !USE_ZLIB */
+
+
+/* Local data */
+local ulg crc; /* crc on uncompressed file data */
+local ftype ifile; /* file to compress */
+#if defined(MMAP) || defined(BIG_MEM)
+ local ulg remain;
+ /* window bytes not yet processed.
+ * special value "(ulg)-1L" reserved to signal normal reads.
+ */
+#endif /* MMAP || BIG_MEM */
+#ifdef USE_ZLIB
+ local int deflInit = FALSE; /* flag: zlib deflate is initialized */
+ local z_stream zstrm; /* zlib's data interface structure */
+ local char *f_ibuf = NULL;
+ local char *f_obuf = NULL;
+#else /* !USE_ZLIB */
+ local char file_outbuf[1024]; /* output buffer for compression to file */
+
+# ifdef ZP_NEED_MEMCOMPR
+ local char *in_buf;
+ /* Current input buffer, in_buf is used only for in-memory compression. */
+ local unsigned in_offset;
+ /* Current offset in input buffer. in_offset is used only for in-memory
+ * compression. On 16 bit machines, the buffer is limited to 64K.
+ */
+ local unsigned in_size; /* size of current input buffer */
+# endif /* ZP_NEED_MEMCOMPR */
+#endif /* ?USE_ZLIB */
+
+#ifdef BZIP2_SUPPORT
+ local int bzipInit; /* flag: bzip2lib is initialized */
+ local bz_stream bstrm; /* zlib's data interface structure */
+# if !defined(USE_ZLIB)
+ local char *f_ibuf = NULL;
+ local char *f_obuf = NULL;
+# endif /* !USE_ZLIB */
+#endif /* BZIP2_SUPPORT */
+
+#ifdef DEBUG
+ zoff_t isize; /* input file size. global only for debugging */
+#else /* !DEBUG */
+ local zoff_t isize; /* input file size. global only for debugging */
+#endif /* ?DEBUG */
+ /* If file_read detects binary it sets this flag - 12/16/04 EG */
+ local int file_binary = 0; /* first buf */
+ local int file_binary_final = 0; /* for bzip2 for entire file. assume text until find binary */
+
+
+/* moved check to function 3/14/05 EG */
+int is_seekable(y)
+ FILE *y;
+{
+ zoff_t pos;
+
+#ifdef BROKEN_FSEEK
+ if (!fseekable(y)) {
+ return 0;
+ }
+#endif
+
+ pos = zftello(y);
+ if (zfseeko(y, pos, SEEK_SET)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+int percent(n, m)
+ uzoff_t n;
+ uzoff_t m; /* n is the original size, m is the new size */
+/* Return the percentage compression from n to m using only integer
+ operations */
+{
+ zoff_t p;
+
+#if 0
+ if (n > 0xffffffL) /* If n >= 16M */
+ { /* then divide n and m by 256 */
+ n += 0x80; n >>= 8;
+ m += 0x80; m >>= 8;
+ }
+ return n > m ? (int)(1 + (200 * (n - m)/n)) / 2 : 0;
+#endif
+
+/* 2004-12-01 SMS.
+ * Changed to do big-n test only for small zoff_t.
+ * Changed big-n arithmetic to accomodate apparently negative values
+ * when a small zoff_t value exceeds 2G.
+ * Increased the reduction divisor from 256 to 512 to avoid the sign bit
+ * in a reduced intermediate, allowing signed arithmetic for the final
+ * result (which is no longer artificially limited to non-negative
+ * values).
+ * Note that right shifts must be on unsigned values to avoid undesired
+ * sign extension.
+ */
+
+/* Handle n = 0 case and account for int maybe being 16-bit. 12/28/2004 EG
+ */
+
+#define PC_MAX_SAFE 0x007fffffL /* 9 clear bits at high end. */
+#define PC_MAX_RND 0xffffff00L /* 8 clear bits at low end. */
+
+ if (sizeof(uzoff_t) < 8) /* Don't fiddle with big zoff_t. */
+ {
+ if ((ulg)n > PC_MAX_SAFE) /* Reduce large values. (n > m) */
+ {
+ if ((ulg)n < PC_MAX_RND) /* Divide n by 512 with rounding, */
+ n = ((ulg)n + 0x100) >> 9; /* if boost won't overflow. */
+ else /* Otherwise, use max value. */
+ n = PC_MAX_SAFE;
+
+ if ((ulg)m < PC_MAX_RND) /* Divide m by 512 with rounding, */
+ m = ((ulg)m + 0x100) >> 9; /* if boost won't overflow. */
+ else /* Otherwise, use max value. */
+ m = PC_MAX_SAFE;
+ }
+ }
+ if (n != 0)
+ p = ((200 * ((zoff_t)n - (zoff_t)m) / (zoff_t)n) + 1) / 2;
+ else
+ p = 0;
+ return (int)p; /* Return (rounded) % reduction. */
+}
+
+
+#ifndef RISCOS
+
+local int suffixes(a, s)
+ char *a; /* name to check suffix of */
+ char *s; /* list of suffixes separated by : or ; */
+/* Return true if a ends in any of the suffixes in the list s. */
+{
+ int m; /* true if suffix matches so far */
+ char *p; /* pointer into special */
+ char *q; /* pointer into name a */
+
+#ifdef QDOS
+ short dlen = devlen(a);
+ a = a + dlen;
+#endif
+
+ m = 1;
+#ifdef VMS
+ if( (q = strrchr(a,';')) != NULL ) /* Cut out VMS file version */
+ --q;
+ else
+ q = a + strlen(a) - 1;
+#else /* !VMS */
+ q = a + strlen(a) - 1;
+#endif /* ?VMS */
+ for (p = s + strlen(s) - 1; p >= s; p--)
+ if (*p == ':' || *p == ';')
+ {
+ if (m)
+ return 1;
+ else
+ {
+ m = 1;
+#ifdef VMS
+ if( (q = strrchr(a,';')) != NULL ) /* Cut out VMS file version */
+ --q;
+ else
+ q = a + strlen(a) - 1;
+#else /* !VMS */
+ q = a + strlen(a) - 1;
+#endif /* ?VMS */
+ }
+ }
+ else
+ {
+ m = m && q >= a && case_map(*p) == case_map(*q);
+ q--;
+ }
+ return m;
+}
+
+#else /* RISCOS */
+
+local int filetypes(a, s)
+char *a; /* extra field of file to check filetype of */
+char *s; /* list of filetypes separated by : or ; */
+/* Return true if a is any of the filetypes in the list s. */
+{
+ char *p; /* pointer into special */
+ char typestr[4]; /* filetype hex string taken from a */
+
+ if ((((unsigned*)a)[2] & 0xFFF00000) != 0xFFF00000) {
+ /* The file is not filestamped, always try to compress it */
+ return 0;
+ }
+
+ sprintf(typestr,"%.3X",(((unsigned*)a)[2] & 0x000FFF00) >> 8);
+
+ for (p=s;p<=s+strlen(s)-3;p+=3) { /* p+=3 to skip 3 hex type */
+ while (*p==':' || *p==';')
+ p++;
+
+ if (typestr[0] == toupper(p[0]) &&
+ typestr[1] == toupper(p[1]) &&
+ typestr[2] == toupper(p[2]))
+ return 1;
+ }
+ return 0;
+}
+#endif /* ?RISCOS */
+
+
+
+/* Note: a zip "entry" includes a local header (which includes the file
+ name), an encryption header if encrypting, the compressed data
+ and possibly an extended local header. */
+
+int zipup(z)
+struct zlist far *z; /* zip entry to compress */
+/* Compress the file z->name into the zip entry described by *z and write
+ it to the file *y. Encrypt if requested. Return an error code in the
+ ZE_ class. Also, update tempzn by the number of bytes written. */
+/* y is now global */
+{
+ iztimes f_utim; /* UNIX GMT timestamps, filled by filetime() */
+ ulg tim; /* time returned by filetime() */
+ ulg a = 0L; /* attributes returned by filetime() */
+ char *b; /* malloc'ed file buffer */
+ extent k = 0; /* result of zread */
+ int l = 0; /* true if this file is a symbolic link */
+ int m; /* method for this entry */
+
+ zoff_t o = 0, p; /* offsets in zip file */
+ zoff_t q = (zoff_t) -3; /* size returned by filetime */
+ uzoff_t uq; /* unsigned q */
+ zoff_t s = 0; /* size of compressed data */
+
+ int r; /* temporary variable */
+ int isdir; /* set for a directory name */
+ int set_type = 0; /* set if file type (ascii/binary) unknown */
+ zoff_t last_o; /* used to detect wrap around */
+
+ ush tempext = 0; /* temp copies of extra fields */
+ ush tempcext = 0;
+ char *tempextra = NULL;
+ char *tempcextra = NULL;
+
+
+#ifdef WINDLL
+# ifdef ZIP64_SUPPORT
+ extern _int64 filesize64;
+ extern unsigned long low;
+ extern unsigned long high;
+# endif
+#endif
+
+ z->nam = strlen(z->iname);
+ isdir = z->iname[z->nam-1] == (char)0x2f; /* ascii[(unsigned)('/')] */
+
+ file_binary = -1; /* not set, set after first read */
+ file_binary_final = 0; /* not set, set after first read */
+
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ if (!no_win32_wide)
+ tim = filetimew(z->namew, &a, &q, &f_utim);
+ else
+ tim = filetime(z->name, &a, &q, &f_utim);
+#else
+ tim = filetime(z->name, &a, &q, &f_utim);
+#endif
+ if (tim == 0 || q == (zoff_t) -3)
+ return ZE_OPEN;
+
+ /* q is set to -1 if the input file is a device, -2 for a volume label */
+ if (q == (zoff_t) -2) {
+ isdir = 1;
+ q = 0;
+ } else if (isdir != ((a & MSDOS_DIR_ATTR) != 0)) {
+ /* don't overwrite a directory with a file and vice-versa */
+ return ZE_MISS;
+ }
+ /* reset dot_count for each file */
+ if (!display_globaldots)
+ dot_count = -1;
+
+ /* display uncompressed size */
+ uq = ((uzoff_t) q > (uzoff_t) -3) ? 0 : (uzoff_t) q;
+ if (noisy && display_usize) {
+ fprintf(mesg, " (");
+ DisplayNumString( mesg, uq );
+ fprintf(mesg, ")");
+ mesg_line_started = 1;
+ fflush(mesg);
+ }
+ if (logall && display_usize) {
+ fprintf(logfile, " (");
+ DisplayNumString( logfile, uq );
+ fprintf(logfile, ")");
+ logfile_line_started = 1;
+ fflush(logfile);
+ }
+
+ /* initial z->len so if error later have something */
+ z->len = uq;
+
+ z->att = (ush)UNKNOWN; /* will be changed later */
+ z->atx = 0; /* may be changed by set_extra_field() */
+
+ /* Free the old extra fields which are probably obsolete */
+ /* Should probably read these and keep any we don't update. 12/30/04 EG */
+ if (extra_fields == 2) {
+ /* If keeping extra fields, make copy before clearing for set_extra_field()
+ A better approach is to modify the port code, but maybe later */
+ if (z->ext) {
+ if ((tempextra = malloc(z->ext)) == NULL) {
+ ZIPERR(ZE_MEM, "extra fields copy");
+ }
+ memcpy(tempextra, z->extra, z->ext);
+ tempext = z->ext;
+ }
+ if (z->cext) {
+ if ((tempcextra = malloc(z->cext)) == NULL) {
+ ZIPERR(ZE_MEM, "extra fields copy");
+ }
+ memcpy(tempcextra, z->cextra, z->cext);
+ tempcext = z->cext;
+ }
+ }
+ if (z->ext) {
+ free((zvoid *)(z->extra));
+ }
+ if (z->cext && z->extra != z->cextra) {
+ free((zvoid *)(z->cextra));
+ }
+ z->extra = z->cextra = NULL;
+ z->ext = z->cext = 0;
+
+#if defined(MMAP) || defined(BIG_MEM)
+ remain = (ulg)-1L; /* changed only for MMAP or BIG_MEM */
+#endif /* MMAP || BIG_MEM */
+#if (!defined(USE_ZLIB) || defined(MMAP) || defined(BIG_MEM))
+ window_size = 0L;
+#endif /* !USE_ZLIB || MMAP || BIG_MEM */
+
+ /* Select method based on the suffix and the global method */
+#ifndef RISCOS
+ m = special != NULL && suffixes(z->name, special) ? STORE : method;
+#else /* RISCOS must set m after setting extra field */
+ m = method;
+#endif /* ?RISCOS */
+
+ /* For now force deflate if using descriptors. Instead zip and unzip
+ could check bytes read against compressed size in each data descriptor
+ found and skip over any that don't match. This is how at least one
+ other zipper does it. To be added later. Until then it
+ probably doesn't hurt to force deflation when streaming. 12/30/04 EG
+ */
+
+ /* Now is a good time. For now allow storing for testing. 12/16/05 EG */
+ /* By release need to force deflation based on reports some inflate
+ streamed data to find the end of the data */
+ /* Need to handle bzip2 */
+#ifdef NO_STREAMING_STORE
+ if (use_descriptors && m == STORE)
+ {
+ m = DEFLATE;
+ }
+#endif
+
+ /* Open file to zip up unless it is stdin */
+ if (strcmp(z->name, "-") == 0)
+ {
+ ifile = (ftype)zstdin;
+#if defined(MSDOS) || defined(__human68k__)
+ if (isatty(zstdin) == 0) /* keep default mode if stdin is a terminal */
+ setmode(zstdin, O_BINARY);
+#endif
+ z->tim = tim;
+ }
+ else
+ {
+#if !(defined(VMS) && defined(VMS_PK_EXTRA))
+ if (extra_fields) {
+ /* create extra field and change z->att and z->atx if desired */
+ set_extra_field(z, &f_utim);
+# ifdef QLZIP
+ if(qlflag)
+ a |= (S_IXUSR) << 16; /* Cross compilers don't set this */
+# endif
+# ifdef RISCOS
+ m = special != NULL && filetypes(z->extra, special) ? STORE : method;
+# endif /* RISCOS */
+
+ /* For now allow store for testing */
+#ifdef NO_STREAMING_STORE
+ /* For now force deflation if using data descriptors. */
+ if (use_descriptors && m == STORE)
+ {
+ m = DEFLATE;
+ }
+#endif
+
+ }
+#endif /* !(VMS && VMS_PK_EXTRA) */
+ l = issymlnk(a);
+ if (l) {
+ ifile = fbad;
+ m = STORE;
+ }
+ else if (isdir) { /* directory */
+ ifile = fbad;
+ m = STORE;
+ q = 0;
+ }
+#ifdef THEOS
+ else if (((a >> 16) & S_IFMT) == S_IFLIB) { /* library */
+ ifile = fbad;
+ m = STORE;
+ q = 0;
+ }
+#endif
+ else {
+#ifdef CMS_MVS
+ if (bflag) {
+ if ((ifile = zopen(z->name, fhowb)) == fbad)
+ return ZE_OPEN;
+ }
+ else
+#endif /* CMS_MVS */
+#if defined(UNICODE_SUPPORT) && defined(WIN32)
+ if (!no_win32_wide) {
+ if ((ifile = zwopen(z->namew, fhow)) == fbad)
+ return ZE_OPEN;
+ } else {
+ if ((ifile = zopen(z->name, fhow)) == fbad)
+ return ZE_OPEN;
+ }
+#else
+ if ((ifile = zopen(z->name, fhow)) == fbad)
+ return ZE_OPEN;
+#endif
+ }
+
+ z->tim = tim;
+
+#if defined(VMS) && defined(VMS_PK_EXTRA)
+ /* vms_get_attributes must be called after vms_open() */
+ if (extra_fields) {
+ /* create extra field and change z->att and z->atx if desired */
+ vms_get_attributes(ifile, z, &f_utim);
+ }
+#endif /* VMS && VMS_PK_EXTRA */
+
+#if defined(MMAP) || defined(BIG_MEM)
+ /* Map ordinary files but not devices. This code should go in fileio.c */
+ if (!translate_eol && m != STORE && q != -1L && (ulg)q > 0 &&
+ (ulg)q + MIN_LOOKAHEAD > (ulg)q) {
+# ifdef MMAP
+ /* Map the whole input file in memory */
+ if (window != NULL)
+ free(window); /* window can't be a mapped file here */
+ window_size = (ulg)q + MIN_LOOKAHEAD;
+ remain = window_size & (PAGESIZE-1);
+ /* If we can't touch the page beyond the end of file, we must
+ * allocate an extra page.
+ */
+ if (remain > MIN_LOOKAHEAD) {
+ window = (uch*)mmap(0, window_size, PROT_READ, MAP_PRIVATE, ifile, 0);
+ } else {
+ window = (uch*)valloc(window_size - remain + PAGESIZE);
+ if (window != NULL) {
+ window = (uch*)mmap((char*)window, window_size - remain, PROT_READ,
+ MAP_PRIVATE | MAP_FIXED, ifile, 0);
+ } else {
+ window = (uch*)(-1);
+ }
+ }
+ if (window == (uch*)(-1)) {
+ Trace((mesg, " mmap failure on %s\n", z->name));
+ window = NULL;
+ window_size = 0L;
+ remain = (ulg)-1L;
+ } else {
+ remain = (ulg)q;
+ }
+# else /* !MMAP, must be BIG_MEM */
+ /* Read the whole input file at once */
+ window_size = (ulg)q + MIN_LOOKAHEAD;
+ window = window ? (uch*) realloc(window, (unsigned)window_size)
+ : (uch*) malloc((unsigned)window_size);
+ /* Just use normal code if big malloc or realloc fails: */
+ if (window != NULL) {
+ remain = (ulg)zread(ifile, (char*)window, q+1);
+ if (remain != (ulg)q) {
+ fprintf(mesg, " q=%lu, remain=%lu ", (ulg)q, remain);
+ error("can't read whole file at once");
+ }
+ } else {
+ window_size = 0L;
+ }
+# endif /* ?MMAP */
+ }
+#endif /* MMAP || BIG_MEM */
+
+ } /* strcmp(z->name, "-") == 0 */
+
+ if (extra_fields == 2) {
+ unsigned len;
+ char *p;
+
+ /* step through old extra fields and copy over any not already
+ in new extra fields */
+ p = copy_nondup_extra_fields(tempextra, tempext, z->extra, z->ext, &len);
+ free(z->extra);
+ z->ext = len;
+ z->extra = p;
+ p = copy_nondup_extra_fields(tempcextra, tempcext, z->cextra, z->cext, &len);
+ free(z->cextra);
+ z->cext = len;
+ z->cextra = p;
+
+ if (tempext)
+ free(tempextra);
+ if (tempcext)
+ free(tempcextra);
+ }
+
+ if (q == 0)
+ m = STORE;
+ if (m == BEST)
+ m = DEFLATE;
+
+ /* Do not create STORED files with extended local headers if the
+ * input size is not known, because such files could not be extracted.
+ * So if the zip file is not seekable and the input file is not
+ * on disk, obey the -0 option by forcing deflation with stored block.
+ * Note however that using "zip -0" as filter is not very useful...
+ * ??? to be done.
+ */
+
+ /* An alternative used by others is to allow storing but on reading do
+ * a second check when a signature is found. This is simply to check
+ * the compressed size to the bytes read since the start of the file data.
+ * If this is the right signature then the compressed size should match
+ * the size of the compressed data to that point. If not look for the
+ * next signature. We should do this. 12/31/04 EG
+ *
+ * For reading and testing we should do this, but should not write
+ * stored streamed data unless for testing as finding the end of
+ * streamed deflated data can be done by inflating. 6/26/06 EG
+ */
+
+ /* Fill in header information and write local header to zip file.
+ * This header will later be re-written since compressed length and
+ * crc are not yet known.
+ */
+
+ /* (Assume ext, cext, com, and zname already filled in.) */
+#if defined(OS2) || defined(WIN32)
+# ifdef WIN32_OEM
+ /* When creating OEM-coded names on Win32, the entries must always be marked
+ as "created on MSDOS" (OS_CODE = 0), because UnZip needs to handle archive
+ entry names just like those created by Zip's MSDOS port.
+ */
+ z->vem = (ush)(dosify ? 20 : 0 + Z_MAJORVER * 10 + Z_MINORVER);
+# else
+ z->vem = (ush)(z->dosflag ? (dosify ? 20 : /* Made under MSDOS by PKZIP 2.0 */
+ (0 + Z_MAJORVER * 10 + Z_MINORVER))
+ : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
+ /* For a plain old (8+3) FAT file system, we cheat and pretend that the file
+ * was not made on OS2/WIN32 but under DOS. unzip is confused otherwise.
+ */
+# endif
+#else /* !(OS2 || WIN32) */
+ z->vem = (ush)(dosify ? 20 : OS_CODE + Z_MAJORVER * 10 + Z_MINORVER);
+#endif /* ?(OS2 || WIN32) */
+
+ z->ver = (ush)(m == STORE ? 10 : 20); /* Need PKUNZIP 2.0 except for store */
+#ifdef BZIP2_SUPPORT
+ if (method == BZIP2)
+ z->ver = (ush)(m == STORE ? 10 : 46);
+#endif
+ z->crc = 0; /* to be updated later */
+ /* Assume first that we will need an extended local header: */
+ if (isdir)
+ /* If dir then q = 0 and extended header not needed */
+ z->flg = 0;
+ else
+ z->flg = 8; /* to be updated later */
+#if CRYPT
+ if (!isdir && key != NULL) {
+ z->flg |= 1;
+ /* Since we do not yet know the crc here, we pretend that the crc
+ * is the modification time:
+ */
+ z->crc = z->tim << 16;
+ /* More than pretend. File is encrypted using crypt header with that. */
+ }
+#endif /* CRYPT */
+ z->lflg = z->flg;
+ z->how = (ush)m; /* may be changed later */
+ z->siz = (zoff_t)(m == STORE && q >= 0 ? q : 0); /* will be changed later */
+ z->len = (zoff_t)(q != -1L ? q : 0); /* may be changed later */
+ if (z->att == (ush)UNKNOWN) {
+ z->att = BINARY; /* set sensible value in header */
+ set_type = 1;
+ }
+ /* Attributes from filetime(), flag bits from set_extra_field(): */
+#if defined(DOS) || defined(OS2) || defined(WIN32)
+ z->atx = z->dosflag ? a & 0xff : a | (z->atx & 0x0000ff00);
+#else
+ z->atx = dosify ? a & 0xff : a | (z->atx & 0x0000ff00);
+#endif /* DOS || OS2 || WIN32 */
+
+ if ((r = putlocal(z, PUTLOCAL_WRITE)) != ZE_OK) {
+ if (ifile != fbad)
+ zclose(ifile);
+ return r;
+ }
+
+ /* now get split information set by bfwrite() */
+ z->off = current_local_offset;
+
+ /* disk local header was written to */
+ z->dsk = current_local_disk;
+
+ tempzn += 4 + LOCHEAD + z->nam + z->ext;
+
+
+#if CRYPT
+ if (!isdir && key != NULL) {
+ crypthead(key, z->crc);
+ z->siz += RAND_HEAD_LEN; /* to be updated later */
+ tempzn += RAND_HEAD_LEN;
+ }
+#endif /* CRYPT */
+ if (ferror(y)) {
+ if (ifile != fbad)
+ zclose(ifile);
+ ZIPERR(ZE_WRITE, "unexpected error on zip file");
+ }
+
+ last_o = o;
+ o = zftello(y); /* for debugging only, ftell can fail on pipes */
+ if (ferror(y))
+ clearerr(y);
+
+ if (o != -1 && last_o > o) {
+ fprintf(mesg, "last %s o %s\n", zip_fzofft(last_o, NULL, NULL),
+ zip_fzofft(o, NULL, NULL));
+ ZIPERR(ZE_BIG, "seek wrap - zip file too big to write");
+ }
+
+ /* Write stored or deflated file to zip file */
+ isize = 0L;
+ crc = CRCVAL_INITIAL;
+
+ if (isdir) {
+ /* nothing to write */
+ }
+ else if (m != STORE) {
+ if (set_type) z->att = (ush)UNKNOWN;
+ /* ... is finally set in file compression routine */
+#ifdef BZIP2_SUPPORT
+ if (m == BZIP2) {
+ s = bzfilecompress(z, &m);
+ }
+ else
+#endif /* BZIP2_SUPPORT */
+ {
+ s = filecompress(z, &m);
+ }
+#ifndef PGP
+ if (z->att == (ush)BINARY && translate_eol && file_binary) {
+ if (translate_eol == 1)
+ zipwarn("has binary so -l ignored", "");
+ else
+ zipwarn("has binary so -ll ignored", "");
+ }
+ else if (z->att == (ush)BINARY && translate_eol) {
+ if (translate_eol == 1)
+ zipwarn("-l used on binary file - corrupted?", "");
+ else
+ zipwarn("-ll used on binary file - corrupted?", "");
+ }
+#endif
+ }
+ else
+ {
+ if ((b = malloc(SBSZ)) == NULL)
+ return ZE_MEM;
+
+ if (l) {
+ k = rdsymlnk(z->name, b, SBSZ);
+/*
+ * compute crc first because zfwrite will alter the buffer b points to !!
+ */
+ crc = crc32(crc, (uch *) b, k);
+ if (zfwrite(b, 1, k) != k)
+ {
+ free((zvoid *)b);
+ return ZE_TEMP;
+ }
+ isize = k;
+
+#ifdef MINIX
+ q = k;
+#endif /* MINIX */
+ }
+ else
+ {
+ while ((k = file_read(b, SBSZ)) > 0 && k != (extent) EOF)
+ {
+ if (zfwrite(b, 1, k) != k)
+ {
+ if (ifile != fbad)
+ zclose(ifile);
+ free((zvoid *)b);
+ return ZE_TEMP;
+ }
+ if (!display_globaldots) {
+ if (dot_size > 0) {
+ /* initial space */
+ if (noisy && dot_count == -1) {
+#ifndef WINDLL
+ putc(' ', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",' ');
+#endif
+ dot_count++;
+ }
+ dot_count++;
+ if (dot_size <= (dot_count + 1) * SBSZ) dot_count = 0;
+ }
+ if ((verbose || noisy) && dot_size && !dot_count) {
+#ifndef WINDLL
+ putc('.', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",'.');
+#endif
+ mesg_line_started = 1;
+ }
+ }
+ }
+ }
+ free((zvoid *)b);
+ s = isize;
+ }
+ if (ifile != fbad && zerr(ifile)) {
+ perror("\nzip warning");
+ if (logfile)
+ fprintf(logfile, "\nzip warning: %s\n", strerror(errno));
+ zipwarn("could not read input file: ", z->oname);
+ }
+ if (ifile != fbad)
+ zclose(ifile);
+#ifdef MMAP
+ if (remain != (ulg)-1L) {
+ munmap((caddr_t) window, window_size);
+ window = NULL;
+ }
+#endif /*MMAP */
+
+ tempzn += s;
+ p = tempzn; /* save for future fseek() */
+
+#if (!defined(MSDOS) || defined(OS2))
+#if !defined(VMS) && !defined(CMS_MVS) && !defined(__mpexl)
+ /* Check input size (but not in VMS -- variable record lengths mess it up)
+ * and not on MSDOS -- diet in TSR mode reports an incorrect file size)
+ */
+#ifndef TANDEM /* Tandem EOF does not match byte count unless Unstructured */
+ if (!translate_eol && q != -1L && isize != q)
+ {
+ Trace((mesg, " i=%lu, q=%lu ", isize, q));
+ zipwarn(" file size changed while zipping ", z->name);
+ }
+#endif /* !TANDEM */
+#endif /* !VMS && !CMS_MVS && !__mpexl */
+#endif /* (!MSDOS || OS2) */
+
+ if (isdir)
+ {
+ /* A directory */
+ z->siz = 0;
+ z->len = 0;
+ z->how = STORE;
+ z->ver = 10;
+ /* never encrypt directory so don't need extended local header */
+ z->flg &= ~8;
+ z->lflg &= ~8;
+ }
+ else
+ {
+ /* Try to rewrite the local header with correct information */
+ z->crc = crc;
+ z->siz = s;
+#if CRYPT
+ if (!isdir && key != NULL)
+ z->siz += RAND_HEAD_LEN;
+#endif /* CRYPT */
+ z->len = isize;
+ /* if can seek back to local header */
+#ifdef BROKEN_FSEEK
+ if (use_descriptors || !fseekable(y) || zfseeko(y, z->off, SEEK_SET))
+#else
+ if (use_descriptors || zfseeko(y, z->off, SEEK_SET))
+#endif
+ {
+ if (z->how != (ush) m)
+ error("can't rewrite method");
+ if (m == STORE && q < 0)
+ ZIPERR(ZE_PARMS, "zip -0 not supported for I/O on pipes or devices");
+ if ((r = putextended(z)) != ZE_OK)
+ return r;
+ /* if Zip64 and not seekable then Zip64 data descriptor */
+#ifdef ZIP64_SUPPORT
+ tempzn += (zip64_entry ? 24L : 16L);
+#else
+ tempzn += 16L;
+#endif
+ z->flg = z->lflg; /* if z->flg modified by deflate */
+ } else {
+ /* ftell() not as useful across splits */
+ if (bytes_this_entry != (uzoff_t)(key ? s + 12 : s)) {
+ fprintf(mesg, " s=%s, actual=%s ",
+ zip_fzofft(s, NULL, NULL), zip_fzofft(bytes_this_entry, NULL, NULL));
+ error("incorrect compressed size");
+ }
+#if 0
+ /* seek ok, ftell() should work, check compressed size */
+# if !defined(VMS) && !defined(CMS_MVS)
+ if (p - o != s) {
+ fprintf(mesg, " s=%s, actual=%s ",
+ zip_fzofft(s, NULL, NULL), zip_fzofft(p-o, NULL, NULL));
+ error("incorrect compressed size");
+ }
+# endif /* !VMS && !CMS_MVS */
+#endif /* 0 */
+ z->how = (ush)m;
+ switch (m)
+ {
+ case STORE:
+ z->ver = 10; break;
+ /* Need PKUNZIP 2.0 for DEFLATE */
+ case DEFLATE:
+ z->ver = 20; break;
+#ifdef BZIP2_SUPPORT
+ case BZIP2:
+ z->ver = 46; break;
+#endif
+ }
+ /*
+ * The encryption header needs the crc, but we don't have it
+ * for a new file. The file time is used instead and the encryption
+ * header then used to encrypt the data. The AppNote standard only
+ * can be applied to a file that the crc is known, so that means
+ * either an existing entry in an archive or get the crc before
+ * creating the encryption header and then encrypt the data.
+ */
+ if ((z->flg & 1) == 0) {
+ /* not encrypting so don't need extended local header */
+ z->flg &= ~8;
+ }
+ /* deflate may have set compression level bit markers in z->flg,
+ and we can't think of any reason central and local flags should
+ be different. */
+ z->lflg = z->flg;
+
+ /* If not using descriptors, back up and rewrite local header. */
+ if (split_method == 1 && current_local_file != y) {
+ if (zfseeko(current_local_file, z->off, SEEK_SET))
+ return ZE_READ;
+ }
+
+ /* if local header in another split, putlocal will close it */
+ if ((r = putlocal(z, PUTLOCAL_REWRITE)) != ZE_OK)
+ return r;
+
+ if (zfseeko(y, bytes_this_split, SEEK_SET))
+ return ZE_READ;
+
+ if ((z->flg & 1) != 0) {
+ /* encrypted file, extended header still required */
+ if ((r = putextended(z)) != ZE_OK)
+ return r;
+#ifdef ZIP64_SUPPORT
+ if (zip64_entry)
+ tempzn += 24L;
+ else
+ tempzn += 16L;
+#else
+ tempzn += 16L;
+#endif
+ }
+ }
+ } /* isdir */
+ /* Free the local extra field which is no longer needed */
+ if (z->ext) {
+ if (z->extra != z->cextra) {
+ free((zvoid *)(z->extra));
+ z->extra = NULL;
+ }
+ z->ext = 0;
+ }
+
+ /* Display statistics */
+ if (noisy)
+ {
+ if (verbose) {
+ fprintf( mesg, "\t(in=%s) (out=%s)",
+ zip_fzofft(isize, NULL, "u"), zip_fzofft(s, NULL, "u"));
+ }
+#ifdef BZIP2_SUPPORT
+ if (m == BZIP2)
+ fprintf(mesg, " (bzipped %d%%)\n", percent(isize, s));
+ else
+#endif
+ if (m == DEFLATE)
+ fprintf(mesg, " (deflated %d%%)\n", percent(isize, s));
+ else
+ fprintf(mesg, " (stored 0%%)\n");
+ mesg_line_started = 0;
+ fflush(mesg);
+ }
+ if (logall)
+ {
+#ifdef BZIP2_SUPPORT
+ if (m == BZIP2)
+ fprintf(logfile, " (bzipped %d%%)\n", percent(isize, s));
+ else
+#endif
+ if (m == DEFLATE)
+ fprintf(logfile, " (deflated %d%%)\n", percent(isize, s));
+ else
+ fprintf(logfile, " (stored 0%%)\n");
+ logfile_line_started = 0;
+ fflush(logfile);
+ }
+
+#ifdef WINDLL
+# ifdef ZIP64_SUPPORT
+ /* The DLL api has been updated and uses a different
+ interface. 7/24/04 EG */
+ if (lpZipUserFunctions->ServiceApplication64 != NULL)
+ {
+ if ((*lpZipUserFunctions->ServiceApplication64)(z->zname, isize))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+ else
+ {
+ filesize64 = isize;
+ low = (unsigned long)(filesize64 & 0x00000000FFFFFFFF);
+ high = (unsigned long)((filesize64 >> 32) & 0x00000000FFFFFFFF);
+ if (lpZipUserFunctions->ServiceApplication64_No_Int64 != NULL) {
+ if ((*lpZipUserFunctions->ServiceApplication64_No_Int64)(z->zname, low, high))
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+ }
+# else
+ if (lpZipUserFunctions->ServiceApplication != NULL)
+ {
+ if ((*lpZipUserFunctions->ServiceApplication)(z->zname, isize))
+ {
+ ZIPERR(ZE_ABORT, "User terminated operation");
+ }
+ }
+# endif
+#endif
+
+ return ZE_OK;
+}
+
+
+
+
+local unsigned file_read(buf, size)
+ char *buf;
+ unsigned size;
+/* Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+{
+ unsigned len;
+ char *b;
+ zoff_t isize_prev; /* Previous isize. Used for overflow check. */
+
+#if defined(MMAP) || defined(BIG_MEM)
+ if (remain == 0L) {
+ return 0;
+ } else if (remain != (ulg)-1L) {
+ /* The window data is already in place. We still compute the crc
+ * by 32K blocks instead of once on whole file to keep a certain
+ * locality of reference.
+ */
+ Assert(buf == (char*)window + isize, "are you lost?");
+ if ((ulg)size > remain) size = (unsigned)remain;
+ if (size > WSIZE) size = WSIZE; /* don't touch all pages at once */
+ remain -= (ulg)size;
+ len = size;
+ } else
+#endif /* MMAP || BIG_MEM */
+ if (translate_eol == 0) {
+ len = zread(ifile, buf, size);
+ if (len == (unsigned)EOF || len == 0) return len;
+#ifdef OS390
+ b = buf;
+ if (aflag == ASCII) {
+ while (*b != '\0') {
+ *b = (char)ascii[(uch)*b];
+ b++;
+ }
+ }
+#endif
+ } else if (translate_eol == 1) {
+ /* translate_eol == 1 */
+ /* Transform LF to CR LF */
+ size >>= 1;
+ b = buf+size;
+ size = len = zread(ifile, b, size);
+ if (len == (unsigned)EOF || len == 0) return len;
+
+ /* check buf for binary - 12/16/04 */
+ if (file_binary == -1) {
+ /* first read */
+ file_binary = is_text_buf(b, size) ? 0 : 1;
+ }
+
+ if (file_binary != 1) {
+#ifdef EBCDIC
+ if (aflag == ASCII)
+ {
+ do {
+ char c;
+
+ if ((c = *b++) == '\n') {
+ *buf++ = CR; *buf++ = LF; len++;
+ } else {
+ *buf++ = (char)ascii[(uch)c];
+ }
+ } while (--size != 0);
+ }
+ else
+#endif /* EBCDIC */
+ {
+ do {
+ if ((*buf++ = *b++) == '\n') *(buf-1) = CR, *buf++ = LF, len++;
+ } while (--size != 0);
+ }
+ buf -= len;
+ } else { /* do not translate binary */
+ memcpy(buf, b, size);
+ }
+
+ } else {
+ /* translate_eol == 2 */
+ /* Transform CR LF to LF and suppress final ^Z */
+ b = buf;
+ size = len = zread(ifile, buf, size-1);
+ if (len == (unsigned)EOF || len == 0) return len;
+
+ /* check buf for binary - 12/16/04 */
+ if (file_binary == -1) {
+ /* first read */
+ file_binary = is_text_buf(b, size) ? 0 : 1;
+ }
+
+ if (file_binary != 1) {
+ buf[len] = '\n'; /* I should check if next char is really a \n */
+#ifdef EBCDIC
+ if (aflag == ASCII)
+ {
+ do {
+ char c;
+
+ if ((c = *b++) == '\r' && *b == '\n') {
+ len--;
+ } else {
+ *buf++ = (char)(c == '\n' ? LF : ascii[(uch)c]);
+ }
+ } while (--size != 0);
+ }
+ else
+#endif /* EBCDIC */
+ {
+ do {
+ if (( *buf++ = *b++) == CR && *b == LF) buf--, len--;
+ } while (--size != 0);
+ }
+ if (len == 0) {
+ zread(ifile, buf, 1); len = 1; /* keep single \r if EOF */
+#ifdef EBCDIC
+ if (aflag == ASCII) {
+ *buf = (char)(*buf == '\n' ? LF : ascii[(uch)(*buf)]);
+ }
+#endif
+ } else {
+ buf -= len;
+ if (buf[len-1] == CTRLZ) len--; /* suppress final ^Z */
+ }
+ }
+ }
+ crc = crc32(crc, (uch *) buf, len);
+ /* 2005-05-23 SMS.
+ Increment file size. A small-file program reading a large file may
+ cause isize to overflow, so complain (and abort) if it goes
+ negative or wraps around. Awful things happen later otherwise.
+ */
+ isize_prev = isize;
+ isize += (ulg)len;
+ if (isize < isize_prev) {
+ ZIPERR(ZE_BIG, "overflow in byte count");
+ }
+ return len;
+}
+
+
+#ifdef USE_ZLIB
+
+local int zl_deflate_init(pack_level)
+ int pack_level;
+{
+ unsigned i;
+ int windowBits;
+ int err = Z_OK;
+ int zp_err = ZE_OK;
+
+ if (zlib_version[0] != ZLIB_VERSION[0]) {
+ sprintf(errbuf, "incompatible zlib version (expected %s, found %s)",
+ ZLIB_VERSION, zlib_version);
+ zp_err = ZE_LOGIC;
+ } else if (strcmp(zlib_version, ZLIB_VERSION) != 0) {
+ fprintf(mesg,
+ "\twarning: different zlib version (expected %s, using %s)\n",
+ ZLIB_VERSION, zlib_version);
+ }
+
+ /* windowBits = log2(WSIZE) */
+ for (i = ((unsigned)WSIZE), windowBits = 0; i != 1; i >>= 1, ++windowBits);
+
+ zstrm.zalloc = (alloc_func)Z_NULL;
+ zstrm.zfree = (free_func)Z_NULL;
+
+ Trace((stderr, "initializing deflate()\n"));
+ err = deflateInit2(&zstrm, pack_level, Z_DEFLATED, -windowBits, 8, 0);
+
+ if (err == Z_MEM_ERROR) {
+ sprintf(errbuf, "cannot initialize zlib deflate");
+ zp_err = ZE_MEM;
+ } else if (err != Z_OK) {
+ sprintf(errbuf, "zlib deflateInit failure (%d)", err);
+ zp_err = ZE_LOGIC;
+ }
+
+ deflInit = TRUE;
+ return zp_err;
+}
+
+
+void zl_deflate_free()
+{
+ int err;
+
+ if (f_obuf != NULL) {
+ free(f_obuf);
+ f_obuf = NULL;
+ }
+ if (f_ibuf != NULL) {
+ free(f_ibuf);
+ f_ibuf = NULL;
+ }
+ if (deflInit) {
+ err = deflateEnd(&zstrm);
+ if (err != Z_OK && err !=Z_DATA_ERROR) {
+ ziperr(ZE_LOGIC, "zlib deflateEnd failed");
+ }
+ deflInit = FALSE;
+ }
+}
+
+#else /* !USE_ZLIB */
+
+# ifdef ZP_NEED_MEMCOMPR
+/* ===========================================================================
+ * In-memory read function. As opposed to file_read(), this function
+ * does not perform end-of-line translation, and does not update the
+ * crc and input size.
+ * Note that the size of the entire input buffer is an unsigned long,
+ * but the size used in mem_read() is only an unsigned int. This makes a
+ * difference on 16 bit machines. mem_read() may be called several
+ * times for an in-memory compression.
+ */
+local unsigned mem_read(b, bsize)
+ char *b;
+ unsigned bsize;
+{
+ if (in_offset < in_size) {
+ ulg block_size = in_size - in_offset;
+ if (block_size > (ulg)bsize) block_size = (ulg)bsize;
+ memcpy(b, in_buf + in_offset, (unsigned)block_size);
+ in_offset += (unsigned)block_size;
+ return (unsigned)block_size;
+ } else {
+ return 0; /* end of input */
+ }
+}
+# endif /* ZP_NEED_MEMCOMPR */
+
+
+/* ===========================================================================
+ * Flush the current output buffer.
+ */
+void flush_outbuf(o_buf, o_idx)
+ char *o_buf;
+ unsigned *o_idx;
+{
+ if (y == NULL) {
+ error("output buffer too small for in-memory compression");
+ }
+ /* Encrypt and write the output buffer: */
+ if (*o_idx != 0) {
+ zfwrite(o_buf, 1, (extent)*o_idx);
+ if (ferror(y)) ziperr(ZE_WRITE, "write error on zip file");
+ }
+ *o_idx = 0;
+}
+
+/* ===========================================================================
+ * Return true if the zip file can be seeked. This is used to check if
+ * the local header can be re-rewritten. This function always returns
+ * true for in-memory compression.
+ * IN assertion: the local header has already been written (ftell() > 0).
+ */
+int seekable()
+{
+ return fseekable(y);
+}
+#endif /* ?USE_ZLIB */
+
+
+/* ===========================================================================
+ * Compression to archive file.
+ */
+local zoff_t filecompress(z_entry, cmpr_method)
+ struct zlist far *z_entry;
+ int *cmpr_method;
+{
+#ifdef USE_ZLIB
+ int err = Z_OK;
+ unsigned mrk_cnt = 1;
+ int maybe_stored = FALSE;
+ ulg cmpr_size;
+#if defined(MMAP) || defined(BIG_MEM)
+ unsigned ibuf_sz = (unsigned)SBSZ;
+#else
+# define ibuf_sz ((unsigned)SBSZ)
+#endif
+#ifndef OBUF_SZ
+# define OBUF_SZ ZBSZ
+#endif
+ unsigned u;
+
+#if defined(MMAP) || defined(BIG_MEM)
+ if (remain == (ulg)-1L && f_ibuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+ if (f_ibuf == NULL)
+#endif /* MMAP || BIG_MEM */
+ f_ibuf = (char *)malloc(SBSZ);
+ if (f_obuf == NULL)
+ f_obuf = (char *)malloc(OBUF_SZ);
+#if defined(MMAP) || defined(BIG_MEM)
+ if ((remain == (ulg)-1L && f_ibuf == NULL) || f_obuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+ if (f_ibuf == NULL || f_obuf == NULL)
+#endif /* MMAP || BIG_MEM */
+ ziperr(ZE_MEM, "allocating zlib file-I/O buffers");
+
+ if (!deflInit) {
+ err = zl_deflate_init(level);
+ if (err != ZE_OK)
+ ziperr(err, errbuf);
+ }
+
+ if (level <= 2) {
+ z_entry->flg |= 4;
+ } else if (level >= 8) {
+ z_entry->flg |= 2;
+ }
+#if defined(MMAP) || defined(BIG_MEM)
+ if (remain != (ulg)-1L) {
+ zstrm.next_in = (Bytef *)window;
+ ibuf_sz = (unsigned)WSIZE;
+ } else
+#endif /* MMAP || BIG_MEM */
+ {
+ zstrm.next_in = (Bytef *)f_ibuf;
+ }
+ zstrm.avail_in = file_read(zstrm.next_in, ibuf_sz);
+ if (zstrm.avail_in < ibuf_sz) {
+ unsigned more = file_read(zstrm.next_in + zstrm.avail_in,
+ (ibuf_sz - zstrm.avail_in));
+ if (more == EOF || more == 0) {
+ maybe_stored = TRUE;
+ } else {
+ zstrm.avail_in += more;
+ }
+ }
+ zstrm.next_out = (Bytef *)f_obuf;
+ zstrm.avail_out = OBUF_SZ;
+
+ if (!maybe_stored) while (zstrm.avail_in != 0 && zstrm.avail_in != EOF) {
+ err = deflate(&zstrm, Z_NO_FLUSH);
+ if (err != Z_OK && err != Z_STREAM_END) {
+ sprintf(errbuf, "unexpected zlib deflate error %d", err);
+ ziperr(ZE_LOGIC, errbuf);
+ }
+ if (zstrm.avail_out == 0) {
+ if (zfwrite(f_obuf, 1, OBUF_SZ) != OBUF_SZ) {
+ ziperr(ZE_TEMP, "error writing to zipfile");
+ }
+ zstrm.next_out = (Bytef *)f_obuf;
+ zstrm.avail_out = OBUF_SZ;
+ }
+ if (zstrm.avail_in == 0) {
+ if (verbose || noisy)
+ while((unsigned)(zstrm.total_in / (uLong)WSIZE) > mrk_cnt) {
+ mrk_cnt++;
+ if (!display_globaldots) {
+ if (dot_size > 0) {
+ /* initial space */
+ if (noisy && dot_count == -1) {
+#ifndef WINDLL
+ putc(' ', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",' ');
+#endif
+ dot_count++;
+ }
+ dot_count++;
+ if (dot_size <= (dot_count + 1) * WSIZE) dot_count = 0;
+ }
+ if (noisy && dot_size && !dot_count) {
+#ifndef WINDLL
+ putc('.', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",'.');
+#endif
+ mesg_line_started = 1;
+ }
+ }
+ }
+#if defined(MMAP) || defined(BIG_MEM)
+ if (remain == (ulg)-1L)
+ zstrm.next_in = (Bytef *)f_ibuf;
+#else
+ zstrm.next_in = (Bytef *)f_ibuf;
+#endif
+ zstrm.avail_in = file_read(zstrm.next_in, ibuf_sz);
+ }
+ }
+
+ do {
+ err = deflate(&zstrm, Z_FINISH);
+ if (maybe_stored) {
+ if (err == Z_STREAM_END && zstrm.total_out >= zstrm.total_in &&
+ fseekable(zipfile)) {
+ /* deflation does not reduce size, switch to STORE method */
+ unsigned len_out = (unsigned)zstrm.total_in;
+ if (zfwrite(f_ibuf, 1, len_out) != len_out) {
+ ziperr(ZE_TEMP, "error writing to zipfile");
+ }
+ zstrm.total_out = (uLong)len_out;
+ *cmpr_method = STORE;
+ break;
+ } else {
+ maybe_stored = FALSE;
+ }
+ }
+ if (zstrm.avail_out < OBUF_SZ) {
+ unsigned len_out = OBUF_SZ - zstrm.avail_out;
+ if (zfwrite(f_obuf, 1, len_out) != len_out) {
+ ziperr(ZE_TEMP, "error writing to zipfile");
+ }
+ zstrm.next_out = (Bytef *)f_obuf;
+ zstrm.avail_out = OBUF_SZ;
+ }
+ } while (err == Z_OK);
+
+ if (err != Z_STREAM_END) {
+ sprintf(errbuf, "unexpected zlib deflate error %d", err);
+ ziperr(ZE_LOGIC, errbuf);
+ }
+
+ if (z_entry->att == (ush)UNKNOWN)
+ z_entry->att = (ush)(zstrm.data_type == Z_ASCII ? ASCII : BINARY);
+ cmpr_size = (ulg)zstrm.total_out;
+
+ if ((err = deflateReset(&zstrm)) != Z_OK)
+ ziperr(ZE_LOGIC, "zlib deflateReset failed");
+ return cmpr_size;
+#else /* !USE_ZLIB */
+
+ /* Set the defaults for file compression. */
+ read_buf = file_read;
+
+ /* Initialize deflate's internals and execute file compression. */
+ bi_init(file_outbuf, sizeof(file_outbuf), TRUE);
+ ct_init(&z_entry->att, cmpr_method);
+ lm_init(level, &z_entry->flg);
+ return deflate();
+#endif /* ?USE_ZLIB */
+}
+
+#ifdef ZP_NEED_MEMCOMPR
+/* ===========================================================================
+ * In-memory compression. This version can be used only if the entire input
+ * fits in one memory buffer. The compression is then done in a single
+ * call of memcompress(). (An extension to allow repeated calls would be
+ * possible but is not needed here.)
+ * The first two bytes of the compressed output are set to a short with the
+ * method used (DEFLATE or STORE). The following four bytes contain the CRC.
+ * The values are stored in little-endian order on all machines.
+ * This function returns the byte size of the compressed output, including
+ * the first six bytes (method and crc).
+ */
+
+ulg memcompress(tgt, tgtsize, src, srcsize)
+ char *tgt, *src; /* target and source buffers */
+ ulg tgtsize, srcsize; /* target and source sizes */
+{
+ ulg crc;
+ unsigned out_total;
+ int method = DEFLATE;
+#ifdef USE_ZLIB
+ int err = Z_OK;
+#else
+ ush att = (ush)UNKNOWN;
+ ush flags = 0;
+#endif
+
+ if (tgtsize <= (ulg)6L) error("target buffer too small");
+ out_total = 2 + 4;
+
+#ifdef USE_ZLIB
+ if (!deflInit) {
+ err = zl_deflate_init(level);
+ if (err != ZE_OK)
+ ziperr(err, errbuf);
+ }
+
+ zstrm.next_in = (Bytef *)src;
+ zstrm.avail_in = (uInt)srcsize;
+ zstrm.next_out = (Bytef *)(tgt + out_total);
+ zstrm.avail_out = (uInt)tgtsize - (uInt)out_total;
+
+ err = deflate(&zstrm, Z_FINISH);
+ if (err != Z_STREAM_END)
+ error("output buffer too small for in-memory compression");
+ out_total += (unsigned)zstrm.total_out;
+
+ if ((err = deflateReset(&zstrm)) != Z_OK)
+ error("zlib deflateReset failed");
+#else /* !USE_ZLIB */
+ read_buf = mem_read;
+ in_buf = src;
+ in_size = (unsigned)srcsize;
+ in_offset = 0;
+ window_size = 0L;
+
+ bi_init(tgt + (2 + 4), (unsigned)(tgtsize - (2 + 4)), FALSE);
+ ct_init(&att, &method);
+ lm_init((level != 0 ? level : 1), &flags);
+ out_total += (unsigned)deflate();
+ window_size = 0L; /* was updated by lm_init() */
+#endif /* ?USE_ZLIB */
+
+ crc = CRCVAL_INITIAL;
+ crc = crc32(crc, (uch *)src, (extent)srcsize);
+
+ /* For portability, force little-endian order on all machines: */
+ tgt[0] = (char)(method & 0xff);
+ tgt[1] = (char)((method >> 8) & 0xff);
+ tgt[2] = (char)(crc & 0xff);
+ tgt[3] = (char)((crc >> 8) & 0xff);
+ tgt[4] = (char)((crc >> 16) & 0xff);
+ tgt[5] = (char)((crc >> 24) & 0xff);
+
+ return (ulg)out_total;
+}
+#endif /* ZP_NEED_MEMCOMPR */
+
+#ifdef BZIP2_SUPPORT
+
+local int bz_compress_init(pack_level)
+int pack_level;
+{
+ int err = BZ_OK;
+ int zp_err = ZE_OK;
+ const char *bzlibVer;
+
+ bzlibVer = BZ2_bzlibVersion();
+
+ /* $TODO - Check BZIP2 LIB version? */
+
+ bstrm.bzalloc = NULL;
+ bstrm.bzfree = NULL;
+ bstrm.opaque = NULL;
+
+ Trace((stderr, "initializing bzlib compress()\n"));
+ err = BZ2_bzCompressInit(&bstrm, pack_level, 0, 30);
+
+ if (err == BZ_MEM_ERROR) {
+ sprintf(errbuf, "cannot initialize bzlib compress");
+ zp_err = ZE_MEM;
+ } else if (err != BZ_OK) {
+ sprintf(errbuf, "bzlib bzCompressInit failure (%d)", err);
+ zp_err = ZE_LOGIC;
+ }
+
+ bzipInit = TRUE;
+ return zp_err;
+}
+
+void bz_compress_free()
+{
+ int err;
+
+ if (f_obuf != NULL) {
+ free(f_obuf);
+ f_obuf = NULL;
+ }
+ if (f_ibuf != NULL) {
+ free(f_ibuf);
+ f_ibuf = NULL;
+ }
+ if (bzipInit) {
+ err = BZ2_bzCompressEnd(&bstrm);
+ if (err != BZ_OK && err != BZ_DATA_ERROR) {
+ ziperr(ZE_LOGIC, "bzlib bzCompressEnd failed");
+ }
+ bzipInit = FALSE;
+ }
+}
+
+/* ===========================================================================
+ * BZIP2 Compression to archive file.
+ */
+
+local zoff_t bzfilecompress(z_entry, cmpr_method)
+struct zlist far *z_entry;
+int *cmpr_method;
+{
+ FILE *zipfile = y;
+
+ int err = BZ_OK;
+ unsigned mrk_cnt = 1;
+ int maybe_stored = FALSE;
+ zoff_t cmpr_size;
+#if defined(MMAP) || defined(BIG_MEM)
+ unsigned ibuf_sz = (unsigned)SBSZ;
+#else
+# define ibuf_sz ((unsigned)SBSZ)
+#endif
+#ifndef OBUF_SZ
+# define OBUF_SZ ZBSZ
+#endif
+
+#if defined(MMAP) || defined(BIG_MEM)
+ if (remain == (ulg)-1L && f_ibuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+ if (f_ibuf == NULL)
+#endif /* MMAP || BIG_MEM */
+ f_ibuf = (char *)malloc(SBSZ);
+ if (f_obuf == NULL)
+ f_obuf = (char *)malloc(OBUF_SZ);
+#if defined(MMAP) || defined(BIG_MEM)
+ if ((remain == (ulg)-1L && f_ibuf == NULL) || f_obuf == NULL)
+#else /* !(MMAP || BIG_MEM */
+ if (f_ibuf == NULL || f_obuf == NULL)
+#endif /* MMAP || BIG_MEM */
+ ziperr(ZE_MEM, "allocating zlib/bzlib file-I/O buffers");
+
+ if (!bzipInit) {
+ err = bz_compress_init(level);
+ if (err != ZE_OK)
+ ziperr(err, errbuf);
+ }
+
+#if defined(MMAP) || defined(BIG_MEM)
+ if (remain != (ulg)-1L) {
+ bstrm.next_in = (Bytef *)window;
+ ibuf_sz = (unsigned)WSIZE;
+ } else
+#endif /* MMAP || BIG_MEM */
+ {
+ bstrm.next_in = (char *)f_ibuf;
+ }
+ bstrm.avail_in = file_read(bstrm.next_in, ibuf_sz);
+ if (file_binary_final == 0) {
+ /* check for binary as library does not */
+ if (!is_text_buf(bstrm.next_in, ibuf_sz))
+ file_binary_final = 1;
+ }
+ if (bstrm.avail_in < ibuf_sz) {
+ unsigned more = file_read(bstrm.next_in + bstrm.avail_in,
+ (ibuf_sz - bstrm.avail_in));
+ if (more == (unsigned) EOF || more == 0) {
+ maybe_stored = TRUE;
+ } else {
+ bstrm.avail_in += more;
+ }
+ }
+ bstrm.next_out = (char *)f_obuf;
+ bstrm.avail_out = OBUF_SZ;
+
+ if (!maybe_stored) {
+ while (bstrm.avail_in != 0 && bstrm.avail_in != (unsigned) EOF) {
+ err = BZ2_bzCompress(&bstrm, BZ_RUN);
+ if (err != BZ_RUN_OK && err != BZ_STREAM_END) {
+ sprintf(errbuf, "unexpected bzlib compress error %d", err);
+ ziperr(ZE_LOGIC, errbuf);
+ }
+ if (bstrm.avail_out == 0) {
+ if (zfwrite(f_obuf, 1, OBUF_SZ) != OBUF_SZ) {
+ ziperr(ZE_TEMP, "error writing to zipfile");
+ }
+ bstrm.next_out = (char *)f_obuf;
+ bstrm.avail_out = OBUF_SZ;
+ }
+ /* $TODO what about high 32-bits of total-in??? */
+ if (bstrm.avail_in == 0) {
+ if (verbose || noisy)
+#ifdef LARGE_FILE_SUPPORT
+ while((unsigned)((bstrm.total_in_lo32
+ + (((zoff_t)bstrm.total_in_hi32) << 32))
+ / (zoff_t)(ulg)WSIZE) > mrk_cnt) {
+#else
+ while((unsigned)(bstrm.total_in_lo32 / (ulg)WSIZE) > mrk_cnt) {
+#endif
+ mrk_cnt++;
+ if (!display_globaldots) {
+ if (dot_size > 0) {
+ /* initial space */
+ if (noisy && dot_count == -1) {
+#ifndef WINDLL
+ putc(' ', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",' ');
+#endif
+ dot_count++;
+ }
+ dot_count++;
+ if (dot_size <= (dot_count + 1) * WSIZE) dot_count = 0;
+ }
+ if (noisy && dot_size && !dot_count) {
+#ifndef WINDLL
+ putc('.', mesg);
+ fflush(mesg);
+#else
+ fprintf(stdout,"%c",'.');
+#endif
+ mesg_line_started = 1;
+ }
+ }
+ }
+#if defined(MMAP) || defined(BIG_MEM)
+ if (remain == (ulg)-1L)
+ bstrm.next_in = (char *)f_ibuf;
+#else
+ bstrm.next_in = (char *)f_ibuf;
+#endif
+ bstrm.avail_in = file_read(bstrm.next_in, ibuf_sz);
+ if (file_binary_final == 0) {
+ /* check for binary as library does not */
+ if (!is_text_buf(bstrm.next_in, ibuf_sz))
+ file_binary_final = 1;
+ }
+ }
+ }
+ }
+
+ /* binary or text */
+ if (file_binary_final)
+ /* found binary in file */
+ z_entry->att = (ush)BINARY;
+ else
+ /* text file */
+ z_entry->att = (ush)ASCII;
+
+ do {
+ err = BZ2_bzCompress(&bstrm, BZ_FINISH);
+ if (maybe_stored) {
+ /* This code is only executed when the complete data stream fits
+ into the input buffer (see above where maybe_stored gets set).
+ So, it is safe to assume that total_in_hi32 (and total_out_hi32)
+ are 0, because the input buffer size is well below the 32-bit
+ limit.
+ */
+ if (err == BZ_STREAM_END
+ && bstrm.total_out_lo32 >= bstrm.total_in_lo32
+ && fseekable(zipfile)) {
+ /* BZIP2 compress does not reduce size,
+ switch to STORE method */
+ unsigned len_out = (unsigned)bstrm.total_in_lo32;
+ if (zfwrite(f_ibuf, 1, len_out) != len_out) {
+ ziperr(ZE_TEMP, "error writing to zipfile");
+ }
+ bstrm.total_out_lo32 = (ulg)len_out;
+ *cmpr_method = STORE;
+ break;
+ } else {
+ maybe_stored = FALSE;
+ }
+ }
+ if (bstrm.avail_out < OBUF_SZ) {
+ unsigned len_out = OBUF_SZ - bstrm.avail_out;
+ if (zfwrite(f_obuf, 1, len_out) != len_out) {
+ ziperr(ZE_TEMP, "error writing to zipfile");
+ }
+ bstrm.next_out = (char *)f_obuf;
+ bstrm.avail_out = OBUF_SZ;
+ }
+ } while (err == BZ_FINISH_OK);
+
+ if (err < BZ_OK) {
+ sprintf(errbuf, "unexpected bzlib compress error %d", err);
+ ziperr(ZE_LOGIC, errbuf);
+ }
+
+ if (z_entry->att == (ush)UNKNOWN)
+ z_entry->att = (ush)BINARY;
+#ifdef LARGE_FILE_SUPPORT
+ cmpr_size = (zoff_t)bstrm.total_out_lo32
+ + (((zoff_t)bstrm.total_out_hi32) << 32);
+#else
+ cmpr_size = (zoff_t)bstrm.total_out_lo32;
+#endif
+
+ if ((err = BZ2_bzCompressEnd(&bstrm)) != BZ_OK)
+ ziperr(ZE_LOGIC, "zlib deflateReset failed");
+ bzipInit = FALSE;
+ return cmpr_size;
+}
+
+#endif /* BZIP2_SUPPORT */
+#endif /* !UTIL */