From d2e14899b571e048f6e4d2b78ab793bebe9f023c Mon Sep 17 00:00:00 2001 From: DarkWyrm Date: Sat, 21 Sep 2002 16:08:49 +0000 Subject: [PATCH] Initial checkin. Everything should build git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1103 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/bin/zip/BUGS | 6 + src/apps/bin/zip/Jamfile | 76 ++ src/apps/bin/zip/LICENSE | 49 + src/apps/bin/zip/MANUAL | 1122 +++++++++++++++++ src/apps/bin/zip/api.c | 448 +++++++ src/apps/bin/zip/api.h | 152 +++ src/apps/bin/zip/bedefs.c | 7 + src/apps/bin/zip/beos.c | 934 ++++++++++++++ src/apps/bin/zip/crc32.c | 64 + src/apps/bin/zip/crc_i386.S | 232 ++++ src/apps/bin/zip/crctab.c | 227 ++++ src/apps/bin/zip/crypt.c | 20 + src/apps/bin/zip/crypt.h | 32 + src/apps/bin/zip/deflate.c | 902 ++++++++++++++ src/apps/bin/zip/ebcdic.h | 284 +++++ src/apps/bin/zip/fileio.c | 984 +++++++++++++++ src/apps/bin/zip/globals.c | 96 ++ src/apps/bin/zip/match.S | 407 +++++++ src/apps/bin/zip/mktime.c | 257 ++++ src/apps/bin/zip/revision.h | 105 ++ src/apps/bin/zip/tailor.h | 467 +++++++ src/apps/bin/zip/trees.c | 1364 +++++++++++++++++++++ src/apps/bin/zip/ttyio.c | 633 ++++++++++ src/apps/bin/zip/ttyio.h | 218 ++++ src/apps/bin/zip/util.c | 696 +++++++++++ src/apps/bin/zip/zip.c | 2287 +++++++++++++++++++++++++++++++++++ src/apps/bin/zip/zip.h | 559 +++++++++ src/apps/bin/zip/zipcloak.c | 425 +++++++ src/apps/bin/zip/ziperr.h | 67 + src/apps/bin/zip/zipfile.c | 1560 ++++++++++++++++++++++++ src/apps/bin/zip/zipnote.c | 500 ++++++++ src/apps/bin/zip/zipsplit.c | 810 +++++++++++++ src/apps/bin/zip/zipup.c | 1176 ++++++++++++++++++ 33 files changed, 17166 insertions(+) create mode 100644 src/apps/bin/zip/BUGS create mode 100644 src/apps/bin/zip/Jamfile create mode 100644 src/apps/bin/zip/LICENSE create mode 100644 src/apps/bin/zip/MANUAL create mode 100644 src/apps/bin/zip/api.c create mode 100644 src/apps/bin/zip/api.h create mode 100644 src/apps/bin/zip/bedefs.c create mode 100644 src/apps/bin/zip/beos.c create mode 100644 src/apps/bin/zip/crc32.c create mode 100644 src/apps/bin/zip/crc_i386.S create mode 100644 src/apps/bin/zip/crctab.c create mode 100644 src/apps/bin/zip/crypt.c create mode 100644 src/apps/bin/zip/crypt.h create mode 100644 src/apps/bin/zip/deflate.c create mode 100644 src/apps/bin/zip/ebcdic.h create mode 100644 src/apps/bin/zip/fileio.c create mode 100644 src/apps/bin/zip/globals.c create mode 100644 src/apps/bin/zip/match.S create mode 100644 src/apps/bin/zip/mktime.c create mode 100644 src/apps/bin/zip/revision.h create mode 100644 src/apps/bin/zip/tailor.h create mode 100644 src/apps/bin/zip/trees.c create mode 100644 src/apps/bin/zip/ttyio.c create mode 100644 src/apps/bin/zip/ttyio.h create mode 100644 src/apps/bin/zip/util.c create mode 100644 src/apps/bin/zip/zip.c create mode 100644 src/apps/bin/zip/zip.h create mode 100644 src/apps/bin/zip/zipcloak.c create mode 100644 src/apps/bin/zip/ziperr.h create mode 100644 src/apps/bin/zip/zipfile.c create mode 100644 src/apps/bin/zip/zipnote.c create mode 100644 src/apps/bin/zip/zipsplit.c create mode 100644 src/apps/bin/zip/zipup.c diff --git a/src/apps/bin/zip/BUGS b/src/apps/bin/zip/BUGS new file mode 100644 index 0000000000..21a9013f66 --- /dev/null +++ b/src/apps/bin/zip/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/src/apps/bin/zip/Jamfile b/src/apps/bin/zip/Jamfile new file mode 100644 index 0000000000..09673e5c2f --- /dev/null +++ b/src/apps/bin/zip/Jamfile @@ -0,0 +1,76 @@ +SubDir OBOS_TOP src apps bin zip ; + +BinCommand zip : + zip.c + zipup.c + crypt.c + ttyio.c + beos.c + globals.c + deflate.c + fileio.c + util.c + crc32.c + zipfile.c + trees.c + crctab.c +; + +LinkSharedOSLibs zip : be ; + +BinCommand zipcloak : + zipcloak.c + zipup.c + crypt.c + ttyio.c + beos.c + globals.c + deflate.c + fileio.c + util.c + crc32.c + zipfile.c + trees.c + crctab.c + bedefs.c +; + +LinkSharedOSLibs zipcloak : be ; + +BinCommand zipnote : + zipnote.c + zipup.c + crypt.c + ttyio.c + beos.c + globals.c + deflate.c + fileio.c + util.c + crc32.c + zipfile.c + trees.c + crctab.c + bedefs.c +; + +LinkSharedOSLibs zipnote : be ; + +BinCommand zipsplit : + zipsplit.c + zipup.c + crypt.c + ttyio.c + beos.c + globals.c + deflate.c + fileio.c + util.c + crc32.c + zipfile.c + trees.c + crctab.c + bedefs.c +; + +LinkSharedOSLibs zipsplit : be ; diff --git a/src/apps/bin/zip/LICENSE b/src/apps/bin/zip/LICENSE new file mode 100644 index 0000000000..f71e7e3f11 --- /dev/null +++ b/src/apps/bin/zip/LICENSE @@ -0,0 +1,49 @@ +This is version 1999-Oct-05 of the Info-ZIP copyright and license. +The definitive version of this document should be available at +ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely. + + +Copyright (c) 1990-1999 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, 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, Christian Spieler, 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 following restrictions: + + 1. Redistributions of source code must retain the above copyright notice, + definition, disclaimer, and this list of conditions. + + 2. Redistributions in binary form must reproduce the above copyright + notice, definition, disclaimer, and this list of conditions in + documentation and/or other materials provided with the distribution. + + 3. Altered versions--including, but not limited to, ports to new operating + systems, existing ports with new graphical interfaces, and dynamic, + shared, or static library versions--must be plainly marked as such + and must not be misrepresented as being 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 of the Info-ZIP URL(s). + + 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," + "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its own source and + binary releases. diff --git a/src/apps/bin/zip/MANUAL b/src/apps/bin/zip/MANUAL new file mode 100644 index 0000000000..84e7de1976 --- /dev/null +++ b/src/apps/bin/zip/MANUAL @@ -0,0 +1,1122 @@ + + + +ZIP(1L) ZIP(1L) + + +NAME + zip, zipcloak, zipnote, zipsplit - package and compress + (archive) files + +SYNOPSIS + zip [-aABcdDeEfFghjklLmoqrRSTuvVwXyz!@$] [-b path] + [-n suffixes] [-t mmddyyyy] [-tt mmddyyyy] [ zipfile [ + file1 file2 ...]] [-xi list] + + zipcloak [-dhL] [-b path] zipfile + + zipnote [-hwL] [-b path] zipfile + + zipsplit [-hiLpst] [-n size] [-b path] zipfile + +DESCRIPTION + zip is a compression and file packaging utility for Unix, + VMS, MSDOS, OS/2, Windows NT, Minix, Atari and 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 pro- + duced by PKZIP, and PKZIP and PKUNZIP can work with + archives produced by zip. zip version 2.3 is compatible + with PKZIP 2.04. Note that PKUNZIP 1.10 cannot extract + files produced by PKZIP 2.04 or zip 2.3. You must use + PKUNZIP 2.04g or unzip 5.0p1 (or later versions) to + extract them. + + For a brief help on zip and unzip, run each without speci- + fying any parameters on the command line. + + 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 directo- + ries. + + 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 com- + pression. zip automatically chooses the better of the two + for each file to be compressed. + + When given the name of an existing zip archive, zip will + replace identically named entries in the zip archive or + + + +Info-ZIP 14 August 1999 (v2.3) 1 + + + + + +ZIP(1L) ZIP(1L) + + + 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 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. + + If the file list is specified as -@, [Not on MacOS] zip + takes the list of input files from standard input. Under + UNIX, this option can be used to powerful effect in con- + junction 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). 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: + + 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 compressed, 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 pur- + pose 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 termi- + nal, zip acts as a filter, compressing standard input to + standard output. For example, + + tar cf - . | zip | dd of=/dev/nrst0 obs=16k + + + + +Info-ZIP 14 August 1999 (v2.3) 2 + + + + + +ZIP(1L) ZIP(1L) + + + 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. For + example: + + dd if=/dev/nrst0 ibs=16k | funzip | tar xvf - + + 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 exten- + sion, the extension .zip is added. If the name already + contains an extension other than .zip the existing exten- + sion is kept unchanged. + +OPTIONS + -a [Systems using EBCDIC] Translate file to ASCII for- + mat. + + -A 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 + "preamble" 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. + + -B [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 unstruc- + tured files + + -b path + Use the specified path for the temporary zip + + + +Info-ZIP 14 August 1999 (v2.3) 3 + + + + + +ZIP(1L) ZIP(1L) + + + archive. For example: + + zip -b /tmp stuff * + + will put the temporary zip archive in the directory + /tmp, copying over stuff.zip to the current direc- + tory when done. This option is only 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. + + -c Add one-line comments for each file. File opera- + tions (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. + + -d 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. + + 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. + + -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. + + -D Do not create entries in the zip archive for direc- + tories. 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 + except -i and -x and can include several options.) + The option -D is a shorthand for -x "*/" but the + + + +Info-ZIP 14 August 1999 (v2.3) 4 + + + + + +ZIP(1L) ZIP(1L) + + + latter cannot be set as default in the ZIPOPT envi- + ronment variable. + + -e 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 [OS/2] Use the .LONGNAME Extended Attribute (if + found) as filename. + + -f 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 cor- + rectly. + + 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 auto- + matic adjustment for ``summertime'' or Daylight + Savings Time). + + -F Fix the zip archive. This option can be used if + some portions of the archive are missing. It is not + guaranteed to work, so you MUST make a backup of + the original archive first. + + When doubled as in -FF the compressed sizes given + inside the damaged archive are not trusted 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, + for example if it has only been truncated, so try + this option first. + + Neither option will recover archives that have been + incorrectly transferred in ascii mode instead of + + + +Info-ZIP 14 August 1999 (v2.3) 5 + + + + + +ZIP(1L) ZIP(1L) + + + 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. + + -g 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 Display the zip help information (this also appears + if zip is run with no arguments). + + -i 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 substitution, so that the name + matching is performed by zip at all directory lev- + els. + + 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. + + -I [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 sin- + gle 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. + + + +Info-ZIP 14 August 1999 (v2.3) 6 + + + + + +ZIP(1L) ZIP(1L) + + + -j 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 path). + + -jj [MacOS] record Fullpath (+ Volname). The complete + path including volume will be stored. By default + the relative path will be stored. + + -J Strip any prepended data (e.g. a SFX stub) from the + archive. + + -k 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 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 ensure that + unzip -a on Unix will get back an exact copy of the + original file, to undo the effect of zip -l. + + -ll 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. + + -L Display the zip license. + + -m Move the specified files into the zip archive; + actually, this deletes the target directories/files + after making the specified zip archive. If a direc- + tory 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. + + -n 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 + semicolons. For example: + + + + +Info-ZIP 14 August 1999 (v2.3) 7 + + + + + +ZIP(1L) ZIP(1L) + + + 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 spe- + cialized compression methods). By default, zip + does not compress 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). + + -N [Amiga, MacOS] Save Amiga or MacOS filenotes as + zipfile comments. 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 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. + + + -P password + use password to encrypt zipfile entries (if any). + THIS IS INSECURE! Many multi-user operating sys- + tems 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 + + + +Info-ZIP 14 August 1999 (v2.3) 8 + + + + + +ZIP(1L) ZIP(1L) + + + even worse. Whenever possible, use the non-echo- + ing, interactive prompt to enter passwords. (And + where security is truly important, use strong + encryption such as Pretty Good Privacy instead of + the relatively weak encryption provided by standard + zipfile utilities.) + + -q Quiet mode; eliminate informational messages and + comment prompts. (Useful, for example, in shell + scripts and background tasks). + + -Qn [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 Travel the directory structure recursively; for + example: + + 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 sub- + stitution 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 (probably not what was intended). + + -R Travel the directory structure recursively starting + at the current 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 for PKZIP + users: the equivalent command is + + pkzip -rP foo *.c + + -S [MSDOS, OS/2, WIN32 and ATARI] Include system and + hidden files. + [MacOS] Includes finder invisible files, which are + ignored otherwise. + + -t mmddyyyy + Do not operate on files modified prior to the + + + +Info-ZIP 14 August 1999 (v2.3) 9 + + + + + +ZIP(1L) ZIP(1L) + + + specified date, where mm is the month (0-12), dd is + the day of the month (1-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 subdirecto- + ries that were last modified on or after 7 December + 1991, to the zip archive infamy.zip. + + -tt mmddyyyy + Do not operate on files modified after or at the + specified date, where mm is the month (0-12), dd is + the day of the month (1-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 subdirecto- + ries that were last modified before the 30 November + 1995, to the zip archive infamy.zip. + + -T 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. + + -u 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 arguments acts like + the -f (freshen) option. + + -v Verbose mode or print diagnostic version info. + + Normally, when applied to real operations, this + option enables the display of a progress indicator + during compression and requests verbose diagnostic + info about zipfile structure oddities. + + + +Info-ZIP 14 August 1999 (v2.3) 10 + + + + + +ZIP(1L) ZIP(1L) + + + When -v is the only command line argument, and std- + out is not redirected to a file, a diagnostic + screen is printed. In addition to the help screen + header with program name, version, and release + date, some pointers to the Info-ZIP home and dis- + tribution sites are given. Then, it shows informa- + tion 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] Save VMS file attributes. zip archives cre- + ated with this option will generally not be usable + on other systems. + + -w [VMS] Append the version number of the files to the + name, including multiple versions of files. + (default: use only the most recent version of a + specified file). + + -x 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 excluding all the files that end in .o. The + backslash avoids the shell filename substitution, + so that the name matching is performed 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 excluding all the files that match the pat- + terns in the file exclude.lst. + + -X Do not save extra file attributes (Extended + Attributes on OS/2, uid/gid and file times on + Unix). + + -y Store symbolic links as such in the zip archive, + instead of compressing and storing the file + referred to by the link (UNIX only). + + -z 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 VAX/VMS). The comment + can be taken from a file: + + zip -z foo < foowhat + + + +Info-ZIP 14 August 1999 (v2.3) 11 + + + + + +ZIP(1L) ZIP(1L) + + + -# Regulate the speed of compression using the speci- + fied digit #, where -0 indicates no compression + (store all files), -1 indicates the fastest com- + pression method (less compression) and -9 indicates + the slowest compression method (optimal compres- + sion, ignores the suffix list). The default com- + pression level is -6. + + -! [WIN32] Use priviliges (if granted) to obtain all + aspects of WinNT security. + + -@ Take the list of input files from standard input. + Only one filename per line. + + -$ [MSDOS, OS/2, WIN32] Include the volume label for + the the drive holding the first file to be com- + pressed. 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 that archive name given contains a dot already; + this allows the explicit specification of other suffixes). + + Because of the way the shell 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 directory. + + 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: + + + +Info-ZIP 14 August 1999 (v2.3) 12 + + + + + +ZIP(1L) ZIP(1L) + + + 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 corre- + sponding 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. + +PATTERN MATCHING + This section applies only to UNIX. Watch this space for + details on MSDOS and VMS operation. + + The UNIX shells (sh(1) and csh(1)) do filename substitu- + tion on command arguments. 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]). + + 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 pat- + tern, 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 char- + acters 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 + + + +Info-ZIP 14 August 1999 (v2.3) 13 + + + + + +ZIP(1L) ZIP(1L) + + + path prefix is. Note that the backslash must precede + every special character (i.e. ?*[]), or the entire argu- + ment must be enclosed in double quotes (""). + + In general, use backslash to make zip do the pattern + matching with the -f (freshen) and -d (delete) options, + and sometimes after the -x (exclude) option when used with + an appropriate operation (add, -u, -f, or -d). + +ENVIRONMENT + ZIPOPT contains default options that will be used when + running zip + + 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 speci- + fied extensions to be added to the zip file with + basename and extension swapped. zip + + 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. Processing may have completed + successfully anyway; some broken 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. Processing probably failed imme- + diately. + + 6 entry too large to be split with zipsplit + + + + +Info-ZIP 14 August 1999 (v2.3) 14 + + + + + +ZIP(1L) ZIP(1L) + + + 7 invalid comment format + + 8 zip -T failed or out of memory + + 9 the user aborted zip prematurely with con- + trol-C (or similar) + + 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 + + VMS interprets standard Unix (or PC) return values as + other, scarier-looking things, so zip instead maps them + into VMS-style status codes. The current mapping is as + follows: 1 (success) for normal exit, + and (0x7fff000? + 16*normal_zip_exit_status) for all + errors, where the `?' is 0 (warning) for zip value 12, 2 + (error) for the zip values 3, 6, 7, 9, 13, 16, 18, and 4 + (fatal error) for the remaining ones. + +BUGS + zip 2.3 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 2.3 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 transfer + zip files from Vax to MSDOS, type "set file type block" on + + + +Info-ZIP 14 August 1999 (v2.3) 15 + + + + + +ZIP(1L) ZIP(1L) + + + the Vax. When transfering from MSDOS to Vax, type "set + file type fixed" on the Vax. In both cases, type "set + file type binary" on MSDOS. + + Under VMS, zip hangs for file specification that uses DEC- + net syntax foo::*.*. + + 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. + + 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 + zip (which uses this 32-bit-mode size) differs from that + reported by DIR. zip stores the 32-bit format for porta- + bility, 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) 1990-1997 Mark Adler, Richard B. Wales, + Jean-loup Gailly, Onno van der Linden, Kai Uwe Rommel, + Igor Mandrichenko, John Bush and Paul Kienitz. Permission + is granted to any individual or institution to use, copy, + or redistribute this software so long as all of the origi- + nal 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 by email to: + zip-bugs@lists.wku.edu. 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 possible. + +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 format, and .ZIP filename + extension, and for accepting minor changes to the file + + + +Info-ZIP 14 August 1999 (v2.3) 16 + + + + + +ZIP(1L) ZIP(1L) + + + format; to Steve Burg for clarifications on the deflate + format; to Haruhiko Okumura and Leonid Broukhis for pro- + viding 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. The + manual page was rewritten for UNIX by R. P. C. Rodgers. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Info-ZIP 14 August 1999 (v2.3) 17 + + diff --git a/src/apps/bin/zip/api.c b/src/apps/bin/zip/api.c new file mode 100644 index 0000000000..f694d1a4b2 --- /dev/null +++ b/src/apps/bin/zip/api.c @@ -0,0 +1,448 @@ +/* + 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 +*/ +/*--------------------------------------------------------------------------- + + 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); + BOOL EXPENTRY ZpSetOptions(LPZPOPT Opts); + ZPOPT EXPENTRY ZpGetOptions(void); + int EXPENTRY ZpArchive(ZCL C); + + 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 + +#ifdef WINDLL +# include +# include "windll/windll.h" +#endif + +#ifdef OS2 +# define INCL_DOSMEMMGR +# include +#endif + +#ifdef __BORLANDC__ +#include +#endif +#include +#include +#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; + +/* Local forward declarations */ +extern int zipmain OF((int, char **)); +int AllocMemory(int, char *, char *); + +ZPOPT Options; +char **argVee; +int argCee; + +/*--------------------------------------------------------------------------- + Local functions + ---------------------------------------------------------------------------*/ + +int AllocMemory(int i, char *cmd, char *str) +{ +int j; +if ((argVee[i] = (char *) malloc( sizeof(char) * strlen(cmd)+1 )) == NULL) + { + for (j = 0; j < i; j++) + { + free (argVee[j]); + argVee[j] = NULL; + } + free(argVee); + fprintf(stdout, "Unable to allocate memory in zip library at %s\n", str); + return ZE_MEM; + } +strcpy( argVee[i], cmd ); +return ZE_OK; +} + +/*--------------------------------------------------------------------------- + Documented API entry points + ---------------------------------------------------------------------------*/ + +int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc) +{ +ZipUserFunctions = *lpZipUserFunc; +lpZipUserFunctions = &ZipUserFunctions; + +if (!lpZipUserFunctions->print || + !lpZipUserFunctions->comment) + return FALSE; + +return TRUE; +} + +BOOL EXPENTRY ZpSetOptions(LPZPOPT Opts) +{ +Options = *Opts; +return TRUE; +} + +ZPOPT EXPENTRY ZpGetOptions(void) +{ +#if CRYPT +Options.fEncryption = TRUE; +#else +Options.fEncryption = FALSE; +#endif +return Options; +} + +int EXPENTRY ZpArchive(ZCL C) +/* Add, update, freshen, or delete zip entries in a zip file. See the + command help in help() zip.c */ +{ +int i, k, j, m; +char szOrigDir[PATH_MAX]; + +argCee = 0; +/* malloc additional 26 to allow for additional command line arguments */ +if ((argVee = (char **)malloc((C.argc+26)*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") != ZE_OK) + return ZE_MEM; +argVee[argCee][1] = Options.fLevel; +argCee++; + +if (Options.fOffsets) /* Update offsets for SFX prefix */ + { + if (AllocMemory(argCee, "-A", "Offsets") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fDeleteEntries) /* Delete files from zip file -d */ + { + if (AllocMemory(argCee, "-d", "Delete") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fNoDirEntries) /* Do not add directory entries -D */ + { + if (AllocMemory(argCee, "-D", "No Dir Entries") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fFreshen) /* Freshen zip file--overwrite only -f */ + { + if (AllocMemory(argCee, "-f", "Freshen") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fRepair) /* Fix archive -F or -FF */ + { + if (Options.fRepair == 1) + { + if (AllocMemory(argCee, "-F", "Repair") != ZE_OK) + return ZE_MEM; + } + else + { + if (AllocMemory(argCee, "-FF", "Repair") != ZE_OK) + return ZE_MEM; + } + argCee++; + } +if (Options.fGrow) /* Allow appending to a zip file -g */ + { + if (AllocMemory(argCee, "-g", "Appending") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fJunkDir) /* Junk directory names -j */ + { + if (AllocMemory(argCee, "-j", "Junk Dir Names") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fEncrypt) /* encrypt -e */ + { + if (AllocMemory(argCee, "-e", "Encrypt") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fJunkSFX) /* Junk sfx prefix */ + { + if (AllocMemory(argCee, "-J", "Junk SFX") != ZE_OK) + return ZE_MEM; + argCee++; + } + +if (Options.fForce) /* Make entries using DOS names (k for Katz) -k */ + { + if (AllocMemory(argCee, "-k", "Force DOS") != ZE_OK) + return ZE_MEM; + argCee++; + } + +if (Options.fLF_CRLF) /* Translate LF_CRLF -l */ + { + if (AllocMemory(argCee, "-l", "LF-CRLF") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fCRLF_LF) /* Translate CR/LF to LF -ll */ + { + if (AllocMemory(argCee, "-ll", "CRLF-LF") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fMove) /* Delete files added to or updated in zip file -m */ + { + if (AllocMemory(argCee, "-m", "Move") != ZE_OK) + return ZE_MEM; + argCee++; + } + +if (Options.fLatestTime) /* Set zip file time to time of latest file in it -o */ + { + if (AllocMemory(argCee, "-o", "Time") != ZE_OK) + return ZE_MEM; + argCee++; + } + +if (Options.fComment) /* Add archive comment "-z" */ + { + if (AllocMemory(argCee, "-z", "Comment") != ZE_OK) + return ZE_MEM; + argCee++; + } + +if (Options.fQuiet) /* quiet operation -q */ + { + if (AllocMemory(argCee, "-q", "Quiet") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fRecurse == 1) /* recurse into subdirectories -r */ + { + if (AllocMemory(argCee, "-r", "Recurse -r") != ZE_OK) + return ZE_MEM; + argCee++; + } +else if (Options.fRecurse == 2) /* recurse into subdirectories -R */ + { + if (AllocMemory(argCee, "-R", "Recurse -R") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fSystem) /* include system and hidden files -S */ + { + if (AllocMemory(argCee, "-S", "System") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fExcludeDate) /* Exclude files newer than specified date -tt */ + { + if ((Options.Date != NULL) && (Options.Date[0] != '\0')) + { + if (AllocMemory(argCee, "-tt", "Date") != ZE_OK) + return ZE_MEM; + argCee++; + if (AllocMemory(argCee, Options.Date, "Date") != ZE_OK) + return ZE_MEM; + argCee++; + } + } + +if (Options.fIncludeDate) /* include files newer than specified date -t */ + { + if ((Options.Date != NULL) && (Options.Date[0] != '\0')) + { + if (AllocMemory(argCee, "-t", "Date") != ZE_OK) + return ZE_MEM; + argCee++; + if (AllocMemory(argCee, Options.Date, "Date") != ZE_OK) + return ZE_MEM; + argCee++; + } + } + +if (Options.fUpdate) /* Update zip file--overwrite only if newer -u */ + { + if (AllocMemory(argCee, "-u", "Update") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fVerbose) /* Mention oddities in zip file structure -v */ + { + if (AllocMemory(argCee, "-v", "Verbose") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (Options.fVolume) /* Include volume label -$ */ + { + if (AllocMemory(argCee, "-$", "Volume") != ZE_OK) + return ZE_MEM; + argCee++; + } +#ifdef WIN32 +if (Options.fPrivilege) /* Use privileges -! */ + { + if (AllocMemory(argCee, "-!", "Privileges") != ZE_OK) + return ZE_MEM; + argCee++; + } +#endif +if (Options.fExtra) /* Exclude extra attributes -X */ + { + if (AllocMemory(argCee, "-X", "Extra") != ZE_OK) + return ZE_MEM; + argCee++; + } +if ((Options.szTempDir != NULL) && (Options.szTempDir[0] != '\0') + && Options.fTemp) /* Use temporary directory -b */ + { + if (AllocMemory(argCee, "-b", "Temp dir switch command") != ZE_OK) + return ZE_MEM; + argCee++; + if (AllocMemory(argCee, Options.szTempDir, "Temporary directory") != ZE_OK) + return ZE_MEM; + argCee++; + } +if (AllocMemory(argCee, C.lpszZipFN, "Zip file name") != ZE_OK) + return ZE_MEM; +argCee++; + +getcwd(szOrigDir, PATH_MAX); /* Save current drive and directory */ + +if ((Options.szRootDir != NULL) && (Options.szRootDir[0] != '\0')) + { + chdir(Options.szRootDir); +#ifdef __BORLANDC__ + setdisk(toupper(Options.szRootDir[0]) - 'A'); +#endif + lstrcat(Options.szRootDir, "\\"); /* append trailing \\ */ + if (C.FNV != NULL) + { + for (k = 0; k < C.argc; k++) + { + if (AllocMemory(argCee, C.FNV[k], "Making argv") != ZE_OK) + return ZE_MEM; + if ((strncmp(Options.szRootDir, C.FNV[k], lstrlen(Options.szRootDir))) == 0) + { + m = 0; + for (j = lstrlen(Options.szRootDir); j < lstrlen(C.FNV[k]); j++) + argVee[argCee][m++] = C.FNV[k][j]; + argVee[argCee][m] = '\0'; + } + argCee++; + } + } + } +else + if (C.FNV != NULL) + for (k = 0; k < C.argc; k++) + { + if (AllocMemory(argCee, C.FNV[k], "Making argv") != ZE_OK) + return ZE_MEM; + argCee++; + } + +argVee[argCee] = NULL; + +ZipRet = zipmain(argCee, argVee); + +chdir(szOrigDir); +#ifdef __BORLANDC__ +setdisk(toupper(szOrigDir[0]) - 'A'); +#endif + +/* 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); + +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 + 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 + + p->zip.major = Z_MAJORVER; + p->zip.minor = Z_MINORVER; + p->zip.patchlevel = Z_PATCHLEVEL; + + + p->os2dll.major = D2_MAJORVER; + p->os2dll.minor = D2_MINORVER; + p->os2dll.patchlevel = D2_PATCHLEVEL; + + + p->windll.major = DW_MAJORVER; + p->windll.minor = DW_MINORVER; + p->windll.patchlevel = DW_PATCHLEVEL; +} diff --git a/src/apps/bin/zip/api.h b/src/apps/bin/zip/api.h new file mode 100644 index 0000000000..54da96b0fd --- /dev/null +++ b/src/apps/bin/zip/api.h @@ -0,0 +1,152 @@ +/* + 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 +*/ +/* 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 +/* 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 */ + _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); +typedef int (WINAPI DLLSERVICE) (LPCSTR, unsigned long); +#endif +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 */ +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 */ +} ZCL, _far *LPZCL; + +typedef struct { +DLLPRNT *print; +DLLCOMMENT *comment; +DLLPASSWORD *password; +DLLSERVICE *ServiceApplication; +} ZIPUSERFUNCTIONS, far * LPZIPUSERFUNCTIONS; + +extern LPZIPUSERFUNCTIONS lpZipUserFunctions; + +void EXPENTRY ZpVersion(ZpVer far *); +int EXPENTRY ZpInit(LPZIPUSERFUNCTIONS lpZipUserFunc); +BOOL EXPENTRY ZpSetOptions(LPZPOPT Opts); +ZPOPT EXPENTRY ZpGetOptions(void); +int EXPENTRY ZpArchive(ZCL C); + +#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/src/apps/bin/zip/bedefs.c b/src/apps/bin/zip/bedefs.c new file mode 100644 index 0000000000..ef740c493f --- /dev/null +++ b/src/apps/bin/zip/bedefs.c @@ -0,0 +1,7 @@ +#include "zip.h" + +#ifndef UTIL +void error(char *str) +{ +} +#endif \ No newline at end of file diff --git a/src/apps/bin/zip/beos.c b/src/apps/bin/zip/beos.c new file mode 100644 index 0000000000..046064f70e --- /dev/null +++ b/src/apps/bin/zip/beos.c @@ -0,0 +1,934 @@ +/* + 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 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#define PAD 0 +#define PATH_END '/' + +/* Library functions not in (most) header files */ + +#ifdef _POSIX_VERSION +# include +#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 +#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() */ + char name[FNMAX]; + 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; + } + 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) + */ + return 0; + + 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) + +#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_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/src/apps/bin/zip/crc32.c b/src/apps/bin/zip/crc32.c new file mode 100644 index 0000000000..0974c2321f --- /dev/null +++ b/src/apps/bin/zip/crc32.c @@ -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 +*/ +/* 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 + */ + +/* $Id: crc32.c,v 1.1 2002/09/21 16:08:49 darkwyrm Exp $ */ + +#define __CRC32_C /* identifies this source module */ + +#include "zip.h" + +#ifndef USE_ZLIB +#ifndef ASM_CRC + +#ifndef ZCONST +# define ZCONST const +#endif + +#ifdef CRC32 +# undef CRC32 +#endif +#define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) +#define DO1(buf) crc = CRC32(crc, *buf++) +#define DO2(buf) DO1(buf); DO1(buf) +#define DO4(buf) DO2(buf); DO2(buf) +#define DO8(buf) DO4(buf); DO4(buf) + +/* ========================================================================= */ +ulg crc32(crc, buf, len) + register 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 ZCONST ulg near *crc_table; + + if (buf == NULL) return 0L; + + crc_table = get_crc_table(); + + crc = crc ^ 0xffffffffL; +#ifndef NO_UNROLLED_LOOPS + while (len >= 8) { + DO8(buf); + len -= 8; + } +#endif + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ +} +#endif /* !ASM_CRC */ +#endif /* !USE_ZLIB */ diff --git a/src/apps/bin/zip/crc_i386.S b/src/apps/bin/zip/crc_i386.S new file mode 100644 index 0000000000..9add2d473c --- /dev/null +++ b/src/apps/bin/zip/crc_i386.S @@ -0,0 +1,232 @@ +/* + 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 +*/ +/* + * crc_i386.S, optimized CRC calculation function for Zip and UnZip, + * created by Paul Kienitz and Christian Spieler. Last revised 24 Dec 98. + * + * 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 ...) + * + * 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, ulg len). + * + * The 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. */ +#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 _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(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 + +#ifndef NO_32_BIT_LOADS +#define Do_CRC_lword \ + xorl (%esi), %eax ;/* c ^= *(ulg *)buf */\ + addl $4, %esi ;/* ((ulg *)buf)++ */\ + Do_CRC \ + Do_CRC \ + Do_CRC \ + Do_CRC +#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, %edx /* save len in edx */ + shrl $3, %ecx /* ecx = len / 8 */ + jz .L_No_Eights +/* align loop head at start of 486 internal cache line !! */ + ALIGNMENT +.L_Next_Eight: +# ifndef NO_32_BIT_LOADS + /* Do_CRC_lword */ + xorl (%esi), %eax ;/* c ^= *(ulg *)buf */ + addl $4, %esi ;/* ((ulg *)buf)++ */ + Do_CRC + Do_CRC + Do_CRC + Do_CRC + /* Do_CRC_lword */ + xorl (%esi), %eax ;/* c ^= *(ulg *)buf */ + addl $4, %esi ;/* ((ulg *)buf)++ */ + Do_CRC + Do_CRC + Do_CRC + Do_CRC +# else /* NO_32_BIT_LOADS */ + Do_CRC_byte + Do_CRC_byte + Do_CRC_byte + Do_CRC_byte + Do_CRC_byte + Do_CRC_byte + Do_CRC_byte + Do_CRC_byte +# endif /* ?NO_32_BIT_LOADS */ + decl %ecx + jnz .L_Next_Eight + +.L_No_Eights: + movl %edx, %ecx + andl $7, %ecx /* ecx = len % 8 */ +#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++); */ + 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 */ diff --git a/src/apps/bin/zip/crctab.c b/src/apps/bin/zip/crctab.c new file mode 100644 index 0000000000..cd309e3cd6 --- /dev/null +++ b/src/apps/bin/zip/crctab.c @@ -0,0 +1,227 @@ +/* + 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 +*/ +/* crctab.c -- supply the CRC table needed for CRC-32 calculations. + * Copyright (C) 1995 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* $Id: crctab.c,v 1.1 2002/09/21 16:08:49 darkwyrm Exp $ */ + +/* + Generate a table 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 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. +*/ + +#define __CRCTAB_C /* identifies this source module */ + +#include "zip.h" + +#if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB)) + +#ifndef ZCONST +# define ZCONST const +#endif + +#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[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 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 (i = 0; i < sizeof(p)/sizeof(uch); i++) + xor |= 1L << (31 - p[i]); +#else +# define xor 0xedb88320L +#endif + +#ifdef DYNALLOC_CRCTAB + crctab_p = (ulg near *) nearmalloc (256*sizeof(ulg)); + if (crctab_p == NULL) { + ziperr(ZE_MEM, "crc_table allocation"); + } +#endif /* DYNALLOC_CRCTAB */ + + 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] = c; + } + 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[256] = { + 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 +}; +#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 (ZCONST ulg near *)crc_table; +#endif +} + +#ifdef DYNALLOC_CRCTAB +void free_crc_table() +{ + if (!CRC_TABLE_IS_EMPTY) + { + nearfree((ulg near *)crc_table); + MARK_CRCTAB_EMPTY; + } +} +#endif + +#endif /* !USE_ZLIB || USE_OWN_CRCTAB */ diff --git a/src/apps/bin/zip/crypt.c b/src/apps/bin/zip/crypt.c new file mode 100644 index 0000000000..359072c21e --- /dev/null +++ b/src/apps/bin/zip/crypt.c @@ -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 +*/ +/* + crypt.c (dummy version) by Info-ZIP. Last revised: 15 Aug 98 + + This is a non-functional version of Info-ZIP's crypt.c encryption/ + decryption code for Zip, ZipCloak, UnZip and fUnZip. This file is + not copyrighted and may be distributed freely. :-) See the "WHERE" + file for sites from which to obtain the full encryption/decryption + sources (zcrypt28.zip or later). + */ + +/* something "externally visible" to shut up compiler/linker warnings */ +int zcr_dummy; diff --git a/src/apps/bin/zip/crypt.h b/src/apps/bin/zip/crypt.h new file mode 100644 index 0000000000..e83d1c9914 --- /dev/null +++ b/src/apps/bin/zip/crypt.h @@ -0,0 +1,32 @@ +/* + 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 +*/ +/* + crypt.h (dummy version) by Info-ZIP. Last revised: 15 Aug 98 + + This is a non-functional version of Info-ZIP's crypt.h encryption/ + decryption header file for Zip, ZipCloak, UnZip and fUnZip. This + file is not copyrighted and may be distributed without restriction. + See the "WHERE" file for sites from which to obtain the full crypt + sources (zcrypt28.zip or later). + */ + +#ifndef __crypt_h /* don't include more than once */ +#define __crypt_h + +#ifdef CRYPT +# undef CRYPT +#endif +#define CRYPT 0 /* dummy version */ + +#define zencode +#define zdecode + +#define zfwrite fwrite + +#endif /* !__crypt_h */ diff --git a/src/apps/bin/zip/deflate.c b/src/apps/bin/zip/deflate.c new file mode 100644 index 0000000000..e5406556c5 --- /dev/null +++ b/src/apps/bin/zip/deflate.c @@ -0,0 +1,902 @@ +/* + 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 +*/ +/* + * 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 + */ + +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 ulg deflate_fast OF((void)); + + 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)< 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= 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(stderr, + " start %d, match %d, length %d\n", + start, match, length); + error("invalid match"); + } + if (verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); +#ifndef WINDLL + do { putc(window[start++], stderr); } while (--length != 0); +#else + do { fprintf(stdout,"%c",window[start++]); } while (--length != 0); +#endif + } +} +#else +# define check_match(start, match, length) +#endif + +/* =========================================================================== + * 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) { + + /* 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; +#ifndef WINDLL + if (verbose) putc('.', stderr); +#else + if (verbose) fprintf(stdout,"%c",'.'); +#endif + } + 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); +} + +/* =========================================================================== + * 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, (long)strstart - block_start, (eof)) + +/* =========================================================================== + * 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 ulg 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. + */ +ulg 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 ulg 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/src/apps/bin/zip/ebcdic.h b/src/apps/bin/zip/ebcdic.h new file mode 100644 index 0000000000..9882e072de --- /dev/null +++ b/src/apps/bin/zip/ebcdic.h @@ -0,0 +1,284 @@ +/* + 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 +*/ +/*--------------------------------------------------------------------------- + + 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: + (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 , 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 +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 /* IZ_ISO2OEM_ARRAY */ + +#ifdef IZ_OEM2ISO_ARRAY +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 /* IZ_OEM2ISO_ARRAY */ + +#if defined(THEOS) || defined(THEOS_SUPPORT) +# include "theos/charconv.h" +#endif + +#endif /* __ebcdic_h */ diff --git a/src/apps/bin/zip/fileio.c b/src/apps/bin/zip/fileio.c new file mode 100644 index 0000000000..559ea1758c --- /dev/null +++ b/src/apps/bin/zip/fileio.c @@ -0,0 +1,984 @@ +/* + 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 +*/ +/* + * fileio.c by Mark Adler + */ +#define __FILEIO_C + +#include "zip.h" + +#ifdef MACOS +# include "helpers.h" +#endif + +#include + +#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 +#endif + +#ifdef NO_ERRNO +extern int errno; +#endif + +#if defined(VMS) || defined(TOPS20) +# define PAD 5 +#else +# define PAD 0 +#endif + +#ifdef NO_RENAME +int rename OF((ZCONST char *, ZCONST char *)); +#endif + + +#ifndef UTIL /* the companion #endif is a bit of ways down ... */ + +/* Local functions */ +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 struct stat zipstatb; +#if (!defined(MACOS) && !defined(WINDLL)) +local int zipstate = -1; +#else +int zipstate; +#endif +/* -1 unknown, 0 old zip file exists, 1 new zip file */ + +char *getnam(n, fp) +char *n; /* where to put name (must have >=FNMAX+1 bytes) */ +FILE *fp; +/* Read a \n or \r delimited name from stdin into n, and return + n. If EOF, then return NULL. Also, if the name read is too big, return + NULL. */ +{ + int c; /* last character read */ + char *p; /* pointer into name area */ + + p = n; + while ((c = getc(fp)) == '\n' || c == '\r') + ; + if (c == EOF) + return NULL; + do { + if (p - n >= FNMAX) + 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 > n) { + if ((c = p[-1]) != ' ' && c != '.') + break; + --p; + } +#endif + *p = 0; + return n; +} + +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)); + 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 +} + + +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; +} + +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) + { + zipwarn(" first full name: ", nodup[j - 1]->name); + zipwarn(" second full name: ", nodup[j]->name); +#ifdef EBCDIC + strtoebc(nodup[j]->iname, nodup[j]->iname); +#endif + zipwarn("name in zip file repeated: ", nodup[j]->iname); +#ifdef EBCDIC + strtoasc(nodup[j]->iname, nodup[j]->iname); +#endif + return ZE_PARMS; + } + free((zvoid *)s); + } + return ZE_OK; +} + +int filter(name, casesensitive) + char *name; + int casesensitive; + /* Scan the -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. + */ +{ + unsigned int n; + int slashes; + int include = icount ? 0 : 1; + char *p, *q; + + if (pcount == 0) return 1; + + for (n = 0; n < pcount; n++) { + if (!patterns[n].zname[0]) /* it can happen... */ + continue; + p = name; + if (patterns[n].select == 'R') { + /* 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; INCSTR(q)) + slashes++; + for (q = p; (q = MBSCHR(q, '/')) != NULL; INCSTR(q)) + slashes--; + if (slashes < 0) + for (q = p; (q = MBSCHR(q, '/')) != NULL; INCSTR(q)) + if (slashes++ == 0) { + p = q + CLEN(q); + break; + } + } + if (MATCH(patterns[n].zname, p, casesensitive)) { + if (patterns[n].select == 'x') return 0; + include = 1; + } + } + return include; +} + +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 */ + struct flist far *f; /* where in found, or new found entry */ + struct zlist far *z; /* where in zfiles (if found) */ + int dosflag; + + /* 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; + 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", zname); + 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->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 (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. */ + struct stat statb; + + if (zipstate == -1) + zipstate = strcmp(zipfile, "-") != 0 && + stat(zipfile, &zipstatb) == 0; + + if (zipstate == 1 && (statb = zipstatb, stat(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); + 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); + return ZE_MEM; + } + strcpy(f->name, name); + f->iname = iname; + f->zname = zname; + 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. + */ +{ + struct 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 + + if ((f = fopen(s, FOPR)) == NULL) { + fprintf(stderr," replace: can't open %s\n", s); + return ZE_TEMP; + } + if ((g = fopen(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 + struct 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 +} + + +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; + + 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 */ + tmpnam(ptr); /* Add filename part to temp subvol */ + err = chvol(cptr); + } + else + t = tmpnam(t); + + 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 */ + return mktemp(t); +#endif /* NO_MKTEMP */ +#endif /* TANDEM */ +#endif /* CMS_MVS */ +} + + +int fcopy(f, g, n) +FILE *f, *g; /* source and destination files */ +ulg n; /* number of bytes to copy or -1 for all */ +/* Copy n bytes from file *f to file *g, or until EOF if n == -1. Return + an error code in the ZE_ class. */ +{ + char *b; /* malloc'ed buffer for copying */ + extent k; /* result of fread() */ + ulg m; /* bytes copied so far */ + + if ((b = malloc(CBSZ)) == NULL) + return ZE_MEM; + m = 0; + while (n == (ulg)(-1L) || m < n) + { + if ((k = fread(b, 1, n == (ulg)(-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(stderr," fcopy: write error\n"); + return ZE_TEMP; + } + m += k; + } + 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 */ diff --git a/src/apps/bin/zip/globals.c b/src/apps/bin/zip/globals.c new file mode 100644 index 0000000000..0db32067ed --- /dev/null +++ b/src/apps/bin/zip/globals.c @@ -0,0 +1,96 @@ +/* + 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 +*/ +/* + * 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+81]; + +/* 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 */ +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 */ +#endif /* VMS */ +#if defined(OS2) || defined(WIN32) + int use_longname_ea = 0; /* 1=use the .LONGNAME EA as the file's name */ +#endif +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 linkput = 0; /* 1=store symbolic links as such */ +int noisy = 1; /* 0=quiet operation */ +int extra_fields = 1; /* 0=do not create extra fields */ +#ifdef WIN32 + 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 */ + +/* Zip file globals */ +char *zipfile; /* New or existing zip archive (zip file) */ +ulg zipbeg; /* Starting offset of zip structures */ +ulg cenbeg; /* Starting offset of central directory */ +struct zlist far *zfiles = NULL; /* Pointer to list of files in zip file */ +extent zcount; /* Number of files in zip file */ +extent 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 */ +ulg tempzn; /* Count of bytes written to output zip file */ + +/* 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 */ + +#ifdef IZ_CHECK_TZ +int zp_tz_is_valid; /* signals "timezone info is available" */ +#endif diff --git a/src/apps/bin/zip/match.S b/src/apps/bin/zip/match.S new file mode 100644 index 0000000000..fa02644e9f --- /dev/null +++ b/src/apps/bin/zip/match.S @@ -0,0 +1,407 @@ +/* + Copyright (c) 1990-1999 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.cdrom.com/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` + * with adaptations by Carsten Steger , + * Andreas Schwab and + * Kristoffer Eriksson + */ + +/* 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=. + * 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/src/apps/bin/zip/mktime.c b/src/apps/bin/zip/mktime.c new file mode 100644 index 0000000000..0f1edc5559 --- /dev/null +++ b/src/apps/bin/zip/mktime.c @@ -0,0 +1,257 @@ +/* free mktime function + Copyright 1988, 1989 by David MacKenzie + and Michael Haertel + Unlimited distribution permitted provided this copyright notice is + retained and any functional modifications are prominently identified. */ + +/* Revised 1997 by Christian Spieler: + The code was changed to get more conformance with ANSI's (resp. modern + UNIX releases) definition for mktime(): + - Added adjustment for out-of-range values in the fields of struct tm. + - Added iterations to get the correct UTC result for input values at + the gaps when daylight saving time is switched on or off. + - Allow forcing of DST "on" or DST "off" by setting `tm_isdst' field in + the tm struct to positive number resp. zero. The `tm_isdst' field must + be negative on entrance of mktime() to enable automatic determination + if DST is in effect for the requested local time. + - Added optional check for overflowing the time_t range. */ + +/* Note: This version of mktime is ignorant of the tzfile. + When the tm structure passed to mktime represents a local time that + is valid both as DST time and as standard time (= time value in the + gap when switching from DST back to standard time), the behaviour + for `tm_isdst < 0' depends on the current timezone: TZ east of GMT + assumes winter time, TZ west of GMT assumes summer time. + Although mktime() (resp. mkgmtime()) tries to adjust for invalid values + of struct tm members, this may fail for input values that are far away + from the valid ranges. The adjustment process does not check for overflows + or wrap arounds in the struct tm components. */ + +#ifndef OF +# ifdef __STDC__ +# define OF(a) a +# else +# define OF(a) () +# endif +#endif + +#ifndef ZCONST +# define ZCONST const +#endif + +#include + +time_t mkgmtime OF((struct tm *)); +time_t mktime OF((struct tm *)); + +/* 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); \ + } + +/* 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) + +/* Additional leapday in February of leap years. */ +#define leapday(m, y) ((m) == 1 && leap (y)) + +/* Length of month `m' (0 .. 11) */ +#define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y)) + +/* Accumulated number of days from 01-Jan up to start of current month. */ +static ZCONST short ydays[] = +{ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +}; + +/* 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 + 1900; /* 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 - 1900; + 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] + (months > 1 && leap (years)); + tm->tm_yday = days; + + /* Now calculate `days' to the number of days since Jan 1, 1970. */ + days = (unsigned)days + 365 * (unsigned)(years - 1970) + + (unsigned)(nleap (years)); + tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */ + tm->tm_isdst = 0; + + if (years < 1970) + 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_MDAY_MAX - 1) + + (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) || + (tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) + + (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) && + (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)(86400L * (unsigned long)(unsigned)days + + 3600L * (unsigned long)hours + + (unsigned long)(60 * minutes + seconds)); +} diff --git a/src/apps/bin/zip/revision.h b/src/apps/bin/zip/revision.h new file mode 100644 index 0000000000..9efba992f2 --- /dev/null +++ b/src/apps/bin/zip/revision.h @@ -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 +*/ +/* + * revision.h by Mark Adler. + */ + +#ifndef __revision_h +#define __revision_h 1 + +/* For api version checking */ +#define Z_MAJORVER 2 +#define Z_MINORVER 3 +#define Z_PATCHLEVEL 0 +#define Z_BETALEVEL "" + +#define VERSION "2.3" +#define REVDATE "November 29th 1999" + +#define DW_MAJORVER Z_MAJORVER +#define DW_MINORVER Z_MINORVER +#define DW_PATCHLEVEL Z_PATCHLEVEL + +#ifndef WINDLL +/* 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[] gets defined only once ! */ +extern ZCONST char *copyright[2]; /* keep array sizes in sync with number */ +extern ZCONST char *swlicense[40]; /* of text line in definition below !! */ +extern ZCONST char *versinfolines[7]; + +#else /* DEFCPYRT */ + +ZCONST char *copyright[] = { +"Copyright (C) 1990-1999 Info-ZIP", +"Type '%s \"-L\"' for software license." +/* XXX still necessary ???? */ +#ifdef AZTEC_C +, /* extremely lame compiler bug workaround */ +#endif +}; + +ZCONST char *versinfolines[] = { +"This is %s %s (%s), by Info-ZIP.", +"Currently maintained by Onno van der Linden. Please send bug reports to", +"the authors at Zip-Bugs@lists.wku.edu; see README for details.", +"", +"Latest sources and executables are at ftp://ftp.cdrom.com/pub/infozip, as of", +"above date; see http://www.cdrom.com/pub/infozip/Zip.html for other sites.", +"" +}; + +ZCONST char *swlicense[] = { +"Copyright (c) 1990-1999 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, 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, Christian Spieler, 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 following restrictions:", +"", +" 1. Redistributions of source code must retain the above copyright notice,", +" definition, disclaimer, and this list of conditions.", +"", +" 2. Redistributions in binary form must reproduce the above copyright", +" notice, definition, disclaimer, and this list of conditions in", +" documentation and/or other materials provided with the distribution.", +"", +" 3. Altered versions--including, but not limited to, ports to new operating", +" systems, existing ports with new graphical interfaces, and dynamic,", +" shared, or static library versions--must be plainly marked as such", +" and must not be misrepresented as being 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 of the Info-ZIP URL(s).", +}; +#endif /* DEFCPYRT */ +#endif /* !WINDLL */ +#endif /* !__revision_h */ diff --git a/src/apps/bin/zip/tailor.h b/src/apps/bin/zip/tailor.h new file mode 100644 index 0000000000..2f7e4aa8a0 --- /dev/null +++ b/src/apps/bin/zip/tailor.h @@ -0,0 +1,467 @@ +/* + 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 +*/ +#ifdef AMIGA +#include "amiga/osdep.h" +#endif + +#ifdef AOSVS +#include "aosvs/osdep.h" +#endif + +#ifdef ATARI +#include "atari/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 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 + +#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 +#else /* NO_PROTO */ +# define OF(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 + +/* + * 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 + +#ifndef NO_STDDEF_H +# include +#endif /* !NO_STDDEF_H */ + +#ifndef NO_STDLIB_H +# include +#endif /* !NO_STDLIB_H */ + +#ifndef NO_UNISTD_H +# include /* usually defines _POSIX_VERSION */ +#endif /* !NO_UNISTD_H */ + +#ifndef NO_FCNTL_H +# include +#endif /* !NO_FNCTL_H */ + +#ifndef NO_STRING_H +# include +#else +# include +#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 +char *strcpy(); +char *strcat(); +char *strrchr(); +/* XXX use !defined(ZMEM) && !defined(__hpux__) ? */ +#if !defined(ZMEM) && defined(NO_STRING_H) +char *memset(); +char *memcpy(); +#endif /* !ZMEM && NO_STRING_H */ + +/* XXX use !defined(__hpux__) ? */ +#ifdef NO_STDLIB_H +char *calloc(); +char *malloc(); +char *getenv(); +long atol(); +#endif /* NO_STDLIB_H */ + +#endif /* NO_PROTO */ + +#ifndef NO_MKTEMP +char *mktemp(); +#endif /* !NO_MKTEMP */ + +/* + * 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; +#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 + */ +#ifdef _MBCS +# include + + /* 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(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)) +# define SETLOCALE(category, locale) setlocale(category, locale) +#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) +# define SETLOCALE(category, locale) +#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_SYMLINK) +# undef S_IFLNK +#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 + +#if (defined(BIG_MEM) || defined(MMAP)) && !defined(DYN_ALLOC) +# define DYN_ALLOC +#endif + +#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 +#endif + +/* 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 + +#define NUM_HOSTS 19 +/* 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/src/apps/bin/zip/trees.c b/src/apps/bin/zip/trees.c new file mode 100644 index 0000000000..b49db354d1 --- /dev/null +++ b/src/apps/bin/zip/trees.c @@ -0,0 +1,1364 @@ +/* + 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 +*/ +/* + * 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. + * + * ulg 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 + +#include +#include "zip.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 */ + +local ulg cmpr_bytelen; /* total byte length of compressed file */ +local ulg cmpr_len_bits; /* number of bits past 'cmpr_bytelen' */ + +#ifdef DEBUG +local ulg 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 ulg bits_sent; /* bit length of the compressed data */ +extern ulg 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(stderr,"\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_bytelen = cmpr_len_bits = 0L; +#ifdef DEBUG + input_len = 0L; +#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< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 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(stderr,"\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 %ld", bits_sent)); + + send_tree((ct_data near *)dyn_ltree, lcodes-1); /* send the literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", bits_sent)); + + send_tree((ct_data near *)dyn_dtree, dcodes-1); /* send the distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", bits_sent)); +} + +/* =========================================================================== + * 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. + */ +ulg 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 == 0L && cmpr_len_bits == 0L) { /* force stored file */ +#else + if (stored_len <= opt_lenb && eof && file_method != NULL && + cmpr_bytelen == 0L && cmpr_len_bits == 0L && seekable()) { +#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 %lu(%lu) ", cmpr_bytelen + (cmpr_len_bits>>3), + (cmpr_bytelen << 3) + cmpr_len_bits - 7*eof)); + 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 ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_file_type() +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq; + *file_type = (ush)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII); +} + + +/* =========================================================================== + * 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 = 0L; +#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 += (ulg)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. + */ +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); + 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/src/apps/bin/zip/ttyio.c b/src/apps/bin/zip/ttyio.c new file mode 100644 index 0000000000..b507c76a96 --- /dev/null +++ b/src/apps/bin/zip/ttyio.c @@ -0,0 +1,633 @@ +/* + 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 +*/ +/*--------------------------------------------------------------------------- + + 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) + screenlines() (Unix only) + zgetch() (Unix and non-Unix 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 + +#ifdef __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 +# 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 +# include +# include +# include +# include +# else /* !VMS */ +# ifdef HAVE_TERMIOS_H +# include +# 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 +# endif +# ifdef HAVE_SYS_TERMIO_H +# include +# endif +# ifdef NEED_PTEM +# include +# include +# 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 +# endif +# include +# 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 +# endif +# else + char *ttyname OF((int)); +# endif +# endif /* ?VMS */ +#endif /* !HAVE_WORKING_GETCH */ + + + +#ifndef HAVE_WORKING_GETCH +#ifdef VMS + +/* + * 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 + */ + + /* SKM: make global? */ + 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}; */ + static short DevChan, iosb[4]; + static long status; + static unsigned long oldmode[2], newmode[2]; /* each = 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, + oldmode, 8, 0, 0, 0, 0); + if (!(status & 1)) + return status; + status = iosb[0]; + if (!(status & 1)) + return status; + + /* copy old mode into new-mode buffer, then modify to be either NOECHO or + * ECHO (depending on function argument opt) + */ + newmode[0] = oldmode[0]; + newmode[1] = oldmode[1]; + if (opt == 0) /* off */ + newmode[1] |= TT$M_NOECHO; /* set NOECHO bit */ + else + newmode[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, + newmode, 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() */ + + +#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)) + +#if (defined(UNIX) || defined(__BEOS__)) +#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 screenlines() +{ + 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 screenlines(): ws_row = %d\n", + wsz.ws_row); + } +#endif + /* number of columns = ws_col */ + return (wsz.ws_row > 0)? wsz.ws_row : 24; /* number of rows */ + + } else { /* this happens when piping to more(1), for example */ +#ifdef DEBUG_WINSZ + if (firsttime) { + firsttime = FALSE; + fprintf(stderr, + "ttyio.c screenlines(): ioctl(TIOCGWINSZ) failed\n")); + } +#endif + return 24; /* VT-100 assumed to be minimal hardware */ + } +} + +#else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */ + +int screenlines() +{ + char *envptr, *getenv(); + int n; + + /* GRR: this is overly simplistic, but don't have access to stty/gtty + * system anymore + */ + envptr = getenv("LINES"); + if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) + return 24; /* VT-100 assumed to be minimal hardware */ + else + return n; +} + +#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)c; +} + + +#else /* !UNIX && !__BEOS__ */ + + +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 /* ?(UNIX || __BEOS__) */ + +#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(UNIX) || defined(__MINT__) || defined(__BEOS__)) + +#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 /* UNIX || __MINT__ || __BEOS__ */ + + + +#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/src/apps/bin/zip/ttyio.h b/src/apps/bin/zip/ttyio.h new file mode 100644 index 0000000000..05c21ad22a --- /dev/null +++ b/src/apps/bin/zip/ttyio.h @@ -0,0 +1,218 @@ +/* + 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 +*/ +/* + 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(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 +# 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 +# define getch() getkey() +# else /* !__GO32__ */ +# include +# 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) + int echo OF((int)); +#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/src/apps/bin/zip/util.c b/src/apps/bin/zip/util.c new file mode 100644 index 0000000000..1faa683e3d --- /dev/null +++ b/src/apps/bin/zip/util.c @@ -0,0 +1,696 @@ +/* + 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 +*/ +/* + * util.c by Mark Adler. + */ +#define __UTIL_C + +#include "zip.h" +#include "ebcdic.h" +#include + +#ifdef MSDOS16 +# include +#endif + +uch upper[256], lower[256]; +/* Country-dependent case map table */ + + +#ifndef UTIL /* UTIL picks out namecmp code (all utils) */ + +/* Local functions */ +local int recmatch OF((ZCONST uch *, ZCONST uch *, int)); +local int count_args OF((char *s)); + +#ifdef MSDOS16 + local unsigned ident OF((unsigned chr)); +#endif + +#ifdef NO_MKTIME +#include "mktime.c" +#endif + +#ifndef HAVE_FSEEKABLE +int fseekable(fp) +FILE *fp; +{ + long x; + + return (fp == NULL || (fseek(fp, -1L, SEEK_CUR) == 0 && + (x = ftell(fp)) >= 0 && + fseek(fp, 1L, SEEK_CUR) == 0 && + ftell(fp) == x + 1)); +} +#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 == '%' || *p == '*') +#else /* !VMS */ +# ifdef RISCOS + /* RISC OS uses # as its single-character wildcard */ + else if (*p == '#' || *p == '*' || *p == '[') +# else /* !RISC OS */ + else if (*p == '?' || *p == '*' || *p == '[') +# endif +#endif /* ?VMS */ + return p; + return NULL; +} + + +local int recmatch(p, s, cs) +ZCONST uch *p; /* sh pattern to match */ +ZCONST uch *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. */ +{ + unsigned int c; /* pattern char or start of range in [-] loop */ + /* Get first character, the pattern for new recmatch calls follows */ + 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) */ +#ifdef VMS + if (c == '%') +#else /* !VMS */ +# ifdef RISCOS + if (c == '#') +# else /* !RISC OS */ + if (c == '?') +# endif +#endif /* ?VMS */ +#ifdef WILD_STOP_AT_DIR + return (*s && *s != '/') ? recmatch(p, s + CLEN(s), cs) : 0; +#else + return *s ? recmatch(p, s + CLEN(s), cs) : 0; +#endif + + /* '*' matches any number of characters, including zero */ +#ifdef AMIGA + if (c == '#' && *p == '?') /* "#?" is Amiga-ese for "*" */ + c = '*', p++; +#endif /* AMIGA */ + if (c == '*') + { + if (*p == 0) + return 1; +#ifdef WILD_STOP_AT_DIR + for (; *s && *s != '/'; INCSTR(s)) + if ((c = recmatch(p, s, cs)) != 0) + return (int)c; + return (*p == '/' || (*p == '\\' && p[1] == '/')) + ? recmatch(p, s, cs) : 2; +#else /* !WILD_STOP_AT_DIR */ + for (; *s; INCSTR(s)) + if ((c = recmatch(p, s, cs)) != 0) + return (int)c; + return 2; /* 2 means give up--shmatch will return false */ +#endif /* ?WILD_STOP_AT_DIR */ + } + +#ifndef VMS /* No bracket matching in VMS */ + /* Parse and process the list of characters and ranges in brackets */ + if (c == '[') + { + int e; /* flag true if next char to be taken literally */ + ZCONST uch *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 ? *s : case_map(*s)); + if (*(p+1) != '-') + for (c = c ? c : (unsigned)*p; c <= (unsigned)*p; c++) + /* compare range */ + if ((cs ? c : case_map(c)) == 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 (c == '\\') + if ((c = *p++) == '\0') /* if \ at end, then syntax error */ + return 0; + + /* Just a character--compare it */ + return (cs ? c == *s : case_map(c) == case_map(*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((ZCONST uch *) p, (ZCONST uch *) s, cs) == 1; +} + + +#if defined(DOS) || defined(WIN32) +/* 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 ((s1 = malloc(strlen(s) + 2)) == NULL) + /* will usually be OK */ + return recmatch((ZCONST uch *) p, (ZCONST uch *) s, cs) == 1; + strcpy(s1, s); + if (strchr(p, '.') && !strchr(s1, '.')) + strcat(s1, "."); + r = recmatch((ZCONST uch *)p, (ZCONST uch *)s1, cs); + 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(®s, ®s, &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++ ) { + 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 +/* 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 (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 = (char*)str;} + INCSTR(str); + } + return match; +} +#endif /* _MBCS */ + + + +#ifndef UTIL + +extern char *getenv(); + +/***************************************************************** + | 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; +} + +static 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 . */ +#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 */ +} + +#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(stderr, "%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 */ diff --git a/src/apps/bin/zip/zip.c b/src/apps/bin/zip/zip.c new file mode 100644 index 0000000000..ce94cf70e2 --- /dev/null +++ b/src/apps/bin/zip/zip.c @@ -0,0 +1,2287 @@ +/* + 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 +*/ +/* + * zip.c by Mark Adler. + */ +#define __ZIP_C + +#include "zip.h" +#include /* for tzset() declaration */ +#ifdef WINDLL +# include +# include +# include "windll/windll.h" +#endif +#define DEFCPYRT /* main module: enable copyright string defines! */ +#include "revision.h" +#include "crypt.h" +#include "ttyio.h" +#ifdef VMS +# include "vms/vmsmunch.h" +#endif + +#ifdef MACOS +# include "macglob.h" + extern MacZipGlobals MacZip; + extern int error_level; +#endif + +#if (defined(MSDOS) && !defined(__GO32__)) || defined(__human68k__) +# include +# if (!defined(P_WAIT) && defined(_P_WAIT)) +# define P_WAIT _P_WAIT +# endif +#endif + +#include + +#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 +local int action = ADD; /* one of ADD, UPDATE, FRESHEN, or DELETE */ +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 ulg before = 0; /* 0=ignore, else exclude files before this time */ +local ulg after = 0; /* 0=ignore, else exclude files newer than this time */ +local int test = 0; /* 1=test zip file with unzip -t */ +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; +#endif + +/* Temporary zip file name and file pointer */ +#ifndef MACOS +local char *tempzip; +local FILE *tempzf; +#else +char *tempzip; +FILE *tempzf; +#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)); +#endif /* !VMSCLI */ +#endif /* !MACOS && !WINDLL */ +local int get_filters OF((int argc, char **argv)); +#if (!defined(MACOS) && !defined(WINDLL)) +local void check_zipfile OF((char *zipname, char *zippath)); +local void version_info OF((void)); +local void zipstdout OF((void)); +#endif /* !MACOS && !WINDLL */ + +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)); + 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; + } +} + +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 (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 */ +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) + EXIT(0); /* avoid recursive ziperr() */ +#endif /* !WINDLL */ + + if (h != NULL) { + if (PERR(c)) + perror("zip I/O error"); + fflush(mesg); + fprintf(stderr, "\nzip error: %s (%s)\n", errors[c-1], h); + } + if (tempzip != NULL) + { + if (tempzip != zipfile) { + if (tempzf != NULL) + fclose(tempzf); +#ifndef DEBUG + destroy(tempzip); +#endif + free((zvoid *)tempzip); + } else { + /* -g option, attempt to restore the old file */ + int k = 0; /* keep count for end header */ + ulg cb = cenbeg; /* get start of central */ + struct zlist far *z; /* steps through zfiles linked list */ + + fprintf(stderr, "attempting to restore %s to its previous state\n", + zipfile); + fseek(tempzf, cenbeg, SEEK_SET); + tempzn = cenbeg; + for (z = zfiles; z != NULL; z = z->nxt) + { + putcentral(z, tempzf); + tempzn += 4 + CENHEAD + z->nam + z->cext + z->com; + k++; + } + putend(k, tempzn - cb, cb, zcomlen, zcomment, tempzf); + fclose(tempzf); + tempzf = 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 (zcomment != NULL) { + free((zvoid *)zcomment); + zcomment = NULL; + } + freeup(); +#ifndef WINDLL + EXIT(c); +#else + longjmp(zipdll_error_return, c); +#endif +} + + +void error(h) + 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', stderr); +#endif /* !MSDOS */ +#endif /* AMIGA && __SASC */ + ziperr(ZE_ABORT, "aborting"); + s++; /* keep some compilers happy */ +} +#endif /* !MACOS && !WINDLL */ + +void zipwarn(a, b) +char *a, *b; /* message strings juxtaposed in output */ +/* Print a warning message to stderr and return. */ +{ + if (noisy) fprintf(stderr, "\tzip warning: %s%s\n", a, b); +} + +#ifndef WINDLL +local void license() +/* Print license information to stdout. */ +{ + extent i; /* counter for copyright array */ + +#if 0 + for (i = 0; i < sizeof(copyright)/sizeof(char *); i++) { + printf(copyright[i], "zip"); + putchar('\n'); + } +#endif + 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 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 +," ", +" 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 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 +#ifdef VMS +" \"-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", +" \"-V\" save VMS file attributes -w append version number to stored name", +#else /* !VMS */ +" -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", +#endif /* ?VMS */ +#ifdef WIN32 +" -! use privileges (if granted) to obtain all aspects of WinNT security", +#endif /* WIN32 */ +#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 +," -I don't scan through Image files" +#endif +#endif /* ?MACOS */ + }; + + 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'); + } +} + +/* + * 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; + + /* 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", +#endif +#ifdef NTSD_EAS + "NTSD_EAS", +#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", +#endif +#ifdef USE_ZLIB + "USE_ZLIB", +#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 + for (i = 0; (int)i < (int)(sizeof(comp_opts)/sizeof(char *) - 1); i++) + { + printf("\t%s\n",comp_opts[i]); + } +#if CRYPT + printf("\t[encryption, version %d.%d%s of %s]\n", + CR_MAJORVER, CR_MINORVER, CR_BETA_VER, CR_VERSION_DATE); + ++i; +#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)); + } +} +#endif /* !WINDLL */ + + +#ifndef PROCNAME +# define PROCNAME(n) procname(n, (action == DELETE || action == FRESHEN)) +#endif /* PROCNAME */ + +#ifndef WINDLL +#ifndef MACOS +local void zipstdout() +/* setup for writing zip file on stdout */ +{ + int r; + 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 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; + + status = spawnlp(P_WAIT, "unzip", "unzip", verbose ? "-t" : "-tqq", + zipname, 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"); + status = spawnlp(P_WAIT, path, "unzip", verbose ? "-t" : "-tqq", + zipname, NULL); + free(path); + } + if (status == -1) + perror("unzip"); + } +#endif /* ?__human68k__ */ + if (status != 0) { +#else /* (MSDOS && !__GO32__) || __human68k__ */ + char cmd[FNMAX+16]; + + /* Tell picky compilers to shut up about unused variables */ + zippath = zippath; + + strcpy(cmd, "unzip -t "); +#ifdef QDOS + strcat(cmd, "-Q4 "); +#endif + if (!verbose) strcat(cmd, "-qq "); + if ((int)strlen(zipname) > FNMAX) { + error("zip filename too long"); + } +# ifdef UNIX + strcat(cmd, "'"); /* accept space or $ in name */ + strcat(cmd, zipname); + strcat(cmd, "'"); +# else + strcat(cmd, zipname); +# endif +# ifdef VMS + if (!system(cmd)) { +# else + if (system(cmd)) { +# endif +#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); +} +#endif /* !WINDLL */ + +local int get_filters(argc, argv) + int argc; /* number of tokens in command line */ + char **argv; /* command line tokens */ +/* Counts number of -i or -x patterns, sets patterns and pcount */ +{ + int i; + int flag = 0, archive_seen = 0; + char *iname, *p = NULL; + FILE *fp; + + pcount = 0; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + p = argv[i]; + while (*(++p) != '\0') { + if (*p == 'i' || *p == 'x') + break; + } + if (*p != '\0') { + flag = *p; + p = p[1] == '@' ? p + 2 : NULL; + if (p != NULL && patterns == NULL) { + fp = fopen(p, "r"); + if (fp == NULL) { + ZIPERR(ZE_OPEN, p); + } + while (fgets(errbuf, FNMAX, fp) != NULL) + pcount++; + fclose(fp); + } + } else if (MBSRCHR(argv[i], 'R') != NULL) { + p = NULL; + flag = 'R'; + } else if (flag != 'R') { + flag = 0; + } + } + if (flag && (archive_seen || p != NULL)) { + if (patterns != NULL) { + if (p != NULL) { + fp = fopen(p, "r"); + if (fp == NULL) { + ZIPERR(ZE_OPEN, p); + } + while ((p = getnam(errbuf, fp)) != NULL) { + iname = ex2in(p, 0, (int *)NULL); + if (iname != NULL) { + patterns[pcount].zname = in2ex(iname); + free(iname); + } else { + patterns[pcount].zname = NULL; + } + patterns[pcount].select = flag; + if (flag != 'x') + icount++; + pcount++; + } + fclose(fp); + flag = 0; + p = NULL; + } + else if (argv[i][0] != '-') { + iname = ex2in(argv[i], 0, (int *)NULL); + patterns[pcount].zname = (iname != NULL ? in2ex(iname) : NULL); + if (iname != NULL) + free(iname); + patterns[pcount].select = flag; + if (flag != 'x') + icount++; + pcount++; + } + } + else if (p == NULL) + pcount++; + else + flag = 0; + } else { + if (flag != 'R') + flag = 0; /* only 'R' is allowed before zipfile arg */ + archive_seen = 1; /* first non-flag arg is archive name */ + } + } + if (pcount == 0 || patterns != NULL) return ZE_OK; + patterns = (struct plist*) malloc(pcount * sizeof(struct plist)); + if (patterns == NULL) { + ZIPERR(ZE_MEM, "was creating pattern list"); + } + return get_filters(argc, argv); +} + +#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 */ + +#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 a; /* attributes of zip file */ + ulg c; /* start of central directory */ + 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 k; /* next argument type, marked counter, + comment size, entry count */ + ulg 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 */ + ulg *cmptime = NULL; /* pointer to 'before' or 'after' */ + int r; /* temporary variable */ + int s; /* flag to read names from stdin */ + ulg t; /* file time, length of central directory */ + 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 */ + struct zlist far *z; /* steps through zfiles linked list */ +#ifdef WINDLL + int retcode; /* return code for dll */ +#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 */ + +#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 + +#if defined(__IBMC__) && defined(__DEBUG_ALLOC__) + { + extern void DebugMalloc(void); + atexit(DebugMalloc); + } +#endif +#ifdef QDOS + { + extern void QDOSexit(void); + atexit(QDOSexit); + } +#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) + action = ADD; /* one of ADD, UPDATE, FRESHEN, or DELETE */ + 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 */ + 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 + zipstate = -1; + 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 */ +#ifdef WIN32 + use_longname_ea = 0; /* 1=use the .LONGNAME EA as the file's name */ + use_privileges = 0; /* 1=use security privileges overrides */ +#endif + hidden_files = 0; /* process hidden and system files */ + volume_label = 0; /* add volume label */ + dirnames = 1; /* include directory entries by default */ + linkput = 0; /* 1=store symbolic links as such */ + noisy = 1; /* 0=quiet operation */ + extra_fields = 1; /* 0=do not create extra fields */ + special = ".Z:.zip:.zoo:.arc:.lzh:.arj"; /* List of special suffixes */ + key = NULL; /* Scramble password if scrambling */ + tempath = NULL; /* Path for temporary files */ + found = NULL; /* where in found, or new found entry */ + fnxt = &found; + patterns = NULL; /* List of patterns to be matched */ + pcount = 0; /* number of patterns */ + icount = 0; /* number of include only patterns */ + +#ifndef MACOS + retcode = setjmp(zipdll_error_return); + if (retcode) { + return retcode; + } +#endif /* !MACOS */ +#endif /* MACOS || WINDLL */ + + mesg = (FILE *) stdout; /* cannot be made at link time for VMS */ + comment_stream = (FILE *)stdin; + + init_upper(); /* build case map table */ + +#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 */ + + /* 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 (isatty(1)) { /* output screen is available */ + if (argc == 1) + { /* show help screen */ +#ifdef VMSCLI + VMSCLI_help(); +#else + help(); +#endif + EXIT(0); + } + else if (argc == 2 && strcmp(argv[1], "-v") == 0) + { /* show diagnostic version info */ + version_info(); + EXIT(0); + } + } +#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; + tempzf = NULL; + d = 0; /* disallow adding to a zip file */ +#if (!defined(MACOS) && !defined(WINDLL)) + signal(SIGINT, handler); +#ifdef SIGTERM /* AMIGADOS and others have no SIGTERM */ + signal(SIGTERM, handler); +#endif +#endif /* !MACOS && !WINDLL */ + k = 0; /* Next non-option argument type */ + s = 0; /* set by -@ if -@ is early */ + + r = get_filters(argc, argv); /* scan first the -x and -i patterns */ +#ifdef WINDLL + if (r != ZE_OK) + return r; +#endif + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (argv[i][1]) + for (p = argv[i]+1; *p; p++) + switch (*p) + { +#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(&p); + 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 = *p - '0'; break; + case 'A': /* Adjust unzipsfx'd zipfile: adjust offsets only */ + adjust = 1; break; + case 'b': /* Specify path for temporary file */ + tempdir = 1; + if (k != 0) { + ZIPERR(ZE_PARMS, "use -b before zip file name"); + } + else + k = 1; /* Next non-option is path */ + break; + case 'c': /* Add comments for new files in zip file */ + comadd = 1; break; + case 'd': /* Delete files from zip file */ +#ifdef MACOS + if (p[1] == 'f') { + ++p; + MacZip.DataForkOnly = true; + } else +#endif /* MACOS */ + { + if (action != ADD) { + ZIPERR(ZE_PARMS, "specify just one action"); + } + action = DELETE; + break; + } + case 'D': /* Do not add directory entries */ + dirnames = 0; break; + case 'e': /* Encrypt */ +#if !CRYPT + ZIPERR(ZE_PARMS, "encryption not supported"); +#else /* CRYPT */ + if (key == NULL) { + 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"); + } + } +#endif /* !CRYPT */ + break; + case 'F': /* fix the zip file */ + fix++; 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 */ + +#ifdef RISCOS + case 'I': /* Don't scan through Image files */ + scanimage = 0; + break; +#endif +#ifdef MACOS + case 'j': /* Junk path / Store absolute path */ + if (p[1] == 'j') { /* store absolute path including volname */ + ++p; + MacZip.StoreFullPath = true; + } else { /* junk directory names */ + pathput = 0; break; + } +#else /* !MACOS */ + case 'j': /* Junk directory names */ + pathput = 0; break; +#endif /* ?MACOS */ + 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++; 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 'n': /* Don't compress files with a special suffix */ + special = NULL; /* will be set at next argument */ + 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 'p': /* Store path with name */ + break; /* (do nothing as annoyance avoidance) */ + case 'P': /* password for encryption */ + if (k != 0) { + ZIPERR(ZE_PARMS, "use -P before zip file name"); + } + if (key != NULL) { + ZIPERR(ZE_PARMS, "can only have one -P"); + } +#if CRYPT + k = 7; +#else + ZIPERR(ZE_PARMS, "encryption not supported"); +#endif /* CRYPT */ + break; +#if defined(QDOS) || defined(QLZIP) + case 'Q': + qlflag = strtol((p+1), &p, 10); + if (qlflag == 0) qlflag = 4; + p--; + 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; +#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 */ + if (p[1] == 't') { + ++p; + cmptime = &after; + } else { + cmptime = &before; + } + if (*cmptime) { + ZIPERR(ZE_PARMS, (cmptime == &after ? + "can only have one -tt" : "can only have one -t")); + } + k = 2; break; + case 'T': /* test zip file */ + test = 1; break; + case 'u': /* Update zip file--overwrite only if newer */ + if (action != ADD) { + ZIPERR(ZE_PARMS, "specify just one action"); + } + action = UPDATE; + break; + case 'v': /* Mention oddities in zip file structure */ + noisy = 1; + verbose++; + break; +#ifdef VMS + case 'V': /* Store in VMS format */ + vms_native = 1; break; + case 'w': /* Append the VMS version number */ + vmsver = 1; break; +#endif /* VMS */ + case 'i': /* Include only the following files */ + case 'x': /* Exclude following files */ + if (p[1] == '@' && p[2] != '\0') { + goto nextarg; + } + if (zipfile == NULL) { + ZIPERR(ZE_PARMS, "use -x or -i after name of zipfile"); + } + k = 5; + 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; +#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; + if (k < 3) /* zip file not read yet */ + s = 1; /* defer -@ until after zipfile read */ + else if (strcmp(zipfile, "-") == 0) { + ZIPERR(ZE_PARMS, "can't use - and -@ together"); + } + else /* zip file read--do it now */ + while ((pp = getnam(errbuf, stdin)) != NULL) + { + k = 4; + if ((r = PROCNAME(pp)) != ZE_OK) + { + if (r == ZE_MISS) + zipwarn("name not matched: ", pp); + else { + ZIPERR(r, pp); + } + } + } + break; +#endif /* !MACOS */ + case 'X': + 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 WIN32 + case '!': + /* use security privilege overrides */ + use_privileges = 1; + break; +#endif + default: + { + sprintf(errbuf, "no such option: %c", *p); + ZIPERR(ZE_PARMS, errbuf); + } + } + else /* just a dash */ + switch (k) + { +#if (!defined(MACOS) && !defined(WINDLL)) + case 0: + zipstdout(); + k = 3; + if (s) { + ZIPERR(ZE_PARMS, "can't use - and -@ together"); + } + break; +#endif /* !MACOS && !WINDLL */ + case 1: + ZIPERR(ZE_PARMS, "invalid path"); + /* not reached */ + case 2: + ZIPERR(ZE_PARMS, "invalid time"); + /* not reached */ + case 3: case 4: + comment_stream = NULL; + if ((r = PROCNAME(argv[i])) != ZE_OK) { + if (r == ZE_MISS) + zipwarn("name not matched: ", argv[i]); + else { + ZIPERR(r, argv[i]); + } + } + if (k == 3) { + first_listarg = i; + k = 4; + } + } + } + else /* not an option */ + { + if (special == NULL) + special = argv[i]; + else if (k == 5) + break; /* -i and -x arguments already scanned */ + else if (k == 6) { +#ifdef AMIGA + if ((r = PROCNAME("")) != ZE_OK) { +#else + if ((r = PROCNAME(".")) != ZE_OK) { +#endif + if (r == ZE_MISS) + zipwarn("name not matched: ", argv[i]); + else { + ZIPERR(r, argv[i]); + } + } + if (first_listarg == 0) + first_listarg = i; + break; + } + else switch (k) + { + case 0: + if ((zipfile = ziptyp(argv[i])) == NULL) { + ZIPERR(ZE_MEM, "was processing arguments"); + } + if ((r = readzipfile()) != ZE_OK) { + ZIPERR(r, zipfile); + } + k = 3; + if (s) + { + while ((pp = getnam(errbuf, stdin)) != NULL) + { + k = 4; + if ((r = PROCNAME(pp)) != ZE_OK) { + if (r == ZE_MISS) + zipwarn("name not matched: ", pp); + else { + ZIPERR(r, pp); + } + } + } + s = 0; + } + if (recurse == 2) + k = 6; + break; + case 1: + if ((tempath = malloc(strlen(argv[i]) + 1)) == NULL) { + ZIPERR(ZE_MEM, "was processing arguments"); + } + strcpy(tempath, argv[i]); + k = (zipfile != NULL ? (first_listarg > 0 ? 4 : 3) : 0); + break; + case 2: + { + int yyyy, mm, dd; /* results of sscanf() */ + + /* Support ISO 8601 & American dates */ + if ((sscanf(argv[i], "%4d-%2d-%2d", &yyyy, &mm, &dd) != 3 && + sscanf(argv[i], "%2d%2d%4d", &mm, &dd, &yyyy) != 3) || + mm < 1 || mm > 12 || dd < 1 || dd > 31) { + ZIPERR(ZE_PARMS, (cmptime == &after ? + "invalid date entered for -tt option" : + "invalid date entered for -t option")); + } + *cmptime = dostime(yyyy, mm, dd, 0, 0, 0); + k = (zipfile != NULL ? (first_listarg > 0 ? 4 : 3) : 0); + break; + } + case 3: case 4: + if ((r = PROCNAME(argv[i])) != ZE_OK) { + if (r == ZE_MISS) + zipwarn("name not matched: ", argv[i]); + else { + ZIPERR(r, argv[i]); + } + } + if (k == 3) { + first_listarg = i; + k = 4; + } + break; + case 7: + if ((key = malloc(strlen(argv[i]) + 1)) == NULL) { + ZIPERR(ZE_MEM, "was processing arguments"); + } + strcpy(key, argv[i]); + k = (zipfile != NULL ? (first_listarg > 0 ? 4 : 3) : 0); + } + } +nextarg: ; + } + if (k == 7 || k == 1) { + ZIPERR(ZE_PARMS, "missing argument for -b or -P"); + } + +#if (defined(MSDOS) || defined(OS2)) && !defined(WIN32) + if ((k == 3 || k == 4) && volume_label == 1) { + PROCNAME(NULL); + k = 4; + } +#endif + + if (pcount && first_listarg == 0 && + (k < 3 || (action != UPDATE && action != FRESHEN))) { + ZIPERR(ZE_PARMS, "nothing to select from"); + } + +#if (!defined(MACOS) && !defined(WINDLL)) + if (k < 3) { /* zip used as filter */ + zipstdout(); + comment_stream = NULL; + if ((r = procname("-", 0)) != ZE_OK) { + if (r == ZE_MISS) + zipwarn("name not matched: ", "-"); + else { + ZIPERR(r, "-"); + } + } + k = 4; + if (s) { + ZIPERR(ZE_PARMS, "can't use - and -@ together"); + } + } +#endif /* !MACOS && !WINDLL */ + + /* Clean up selections ("3 <= k <= 5" now) */ + if (k != 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, 0) : 1; + } + } + 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); + + /* 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 (linkput && dosify) + { + zipwarn("can't use -y with -k, -y ignored", ""); + linkput = 0; + } + if (fix && adjust) + { + zipwarn("can't use -F with -A, -F ignored", ""); + } + if (test && !strcmp(zipfile, "-")) { + test = 0; + zipwarn("can't use -T on stdout, -T ignored", ""); + } + if ((action != ADD || d) && !strcmp(zipfile, "-")) { + ZIPERR(ZE_PARMS, "can't use -d,-f,-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 (zcount == 0 && (action != ADD || d)) { + zipwarn(zipfile, " not found or empty"); + } + +/* + * 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 = 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 && action != DELETE) { + 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. */ +#ifdef MACOS + PrintStatProgress("Getting file information ..."); +#endif + diag("stating marked entries"); + k = 0; /* Initialize marked count */ + for (z = zfiles; z != NULL; z = z->nxt) + if (z->mark) { +#ifdef USE_EF_UT_TIME + iztimes f_utim, z_utim; +#endif /* USE_EF_UT_TIME */ + Trace((stderr, "zip diagnostics: marked file=%s\n", z->zname)); + + if (action != DELETE && +#ifdef USE_EF_UT_TIME + ((t = filetime(z->name, (ulg *)NULL, (long *)NULL, &f_utim)) +#else /* !USE_EF_UT_TIME */ + ((t = filetime(z->name, (ulg *)NULL, (long *)NULL, (iztimes *)NULL)) +#endif /* ?USE_EF_UT_TIME */ + == 0 || + t < before || (after && t >= 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) : t <= z->tim) +#else /* !USE_EF_UT_TIME */ + t <= z->tim +#endif /* ?USE_EF_UT_TIME */ + ))) + { + z->mark = comadd ? 2 : 0; + z->trash = t && t >= before && + (after == 0 || t < after); /* delete if -um or -fm */ + if (verbose) { + fprintf(mesg, "zip diagnostic: %s %s\n", z->zname, + z->trash ? "up to date" : "missing or early"); + } + } + else + k++; + } + + /* Remove entries from found list that do not exist or are too old */ + diag("stating new entries"); + Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount)); + for (f = found; f != NULL;) { + Trace((stderr, "zip diagnostic: new file=%s\n", f->zname)); + if (action == DELETE || action == FRESHEN || + (t = filetime(f->name, (ulg *)NULL, (long *)NULL, (iztimes *)NULL)) + == 0 || + t < before || (after && t >= after) || + (namecmp(f->zname, zipfile) == 0 && strcmp(zipfile, "-"))) + f = fexpel(f); + else + f = f->nxt; + } +#ifdef MACOS + PrintStatProgress("done"); +#endif + + /* Make sure there's something left to do */ + if (k == 0 && found == NULL && + !(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, argv[i]), "\" "); + strcat(strcat(errbuf, argv[i]), " *.* -i"); +#else /* !VMS */ + strcpy(errbuf, "try: zip"); + for (i = 1; i < first_listarg; i++) + strcat(strcat(errbuf, " "), argv[i]); +# ifdef AMIGA + strcat(errbuf, " \"\" -i"); +# else + strcat(errbuf, " . -i"); +# endif +#endif /* ?VMS */ + for (i = first_listarg; i < argc; i++) + strcat(strcat(errbuf, " "), argv[i]); + ZIPERR(ZE_NONE, errbuf); + } +#endif /* !WINDLL */ + else { + ZIPERR(ZE_NONE, zipfile); + } + } + 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(); +#endif /* CRYPT */ + + /* 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) { + a = 0; + } else { + x = zfiles == NULL && zipbeg == 0 ? fopen(zipfile, FOPW) : + fopen(zipfile, FOPM); + /* Note: FOPW and FOPM expand to several parameters for VMS */ + if (x == NULL) { + ZIPERR(ZE_CREAT, zipfile); + } + fclose(x); + a = getfileattr(zipfile); + if (zfiles == NULL && zipbeg == 0) + destroy(zipfile); + } + } + else + a = 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 */ + 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 + tempzf = y = fdopen(fileno(stdout), FOPW); +#else + tempzf = 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 ((y = fopen(zipfile, FOPM)) == NULL) { + ZIPERR(ZE_NAME, zipfile); + } + tempzip = zipfile; + tempzf = y; + if (fseek(y, cenbeg, SEEK_SET)) { + ZIPERR(ferror(y) ? ZE_READ : ZE_EOF, zipfile); + } + tempzn = cenbeg; + } + else + { + if ((zfiles != NULL || zipbeg) && (x = fopen(zipfile, FOPR_EX)) == NULL) { + ZIPERR(ZE_NAME, zipfile); + } + if ((tempzip = tempname(zipfile)) == NULL) { + ZIPERR(ZE_MEM, "allocating temp filename"); + } + if ((tempzf = y = fopen(tempzip, FOPW_TMP)) == NULL) { + ZIPERR(ZE_TEMP, tempzip); + } + } + +#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 (strcmp(zipfile, "-") != 0 && !d) /* this must go *after* set[v]buf */ + { + if (zipbeg && (r = fcopy(x, y, zipbeg)) != ZE_OK) { + ZIPERR(r, r == ZE_TEMP ? tempzip : zipfile); + } + tempzn = zipbeg; + } + + 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 + w = &zfiles; + while ((z = *w) != NULL) { + if (z->mark == 1) + { + /* if not deleting, zip it up */ + if (action != DELETE) + { + if (noisy) + { + if (action == FRESHEN) + fprintf(mesg, "freshening: %s", z->zname); + else + fprintf(mesg, "updating: %s", z->zname); + fflush(mesg); + } + if ((r = zipup(z, y)) != ZE_OK && r != ZE_OPEN && r != ZE_MISS) + { + if (noisy) + { +#if (!defined(MACOS) && !defined(WINDLL)) + putc('\n', mesg); + fflush(mesg); +#else + fprintf(stdout, "\n"); +#endif + } + sprintf(errbuf, "was zipping %s", z->name); + ZIPERR(r, errbuf); + } + if (r == ZE_OPEN || r == ZE_MISS) + { + o = 1; + if (noisy) + { +#if (!defined(MACOS) && !defined(WINDLL)) + putc('\n', mesg); + fflush(mesg); +#else + fprintf(stdout, "\n"); +#endif + } + if (r == ZE_OPEN) { + perror(z->zname); + zipwarn("could not open for reading: ", z->zname); + } else { + zipwarn("file and directory with the same name: ", z->zname); + } + zipwarn("will just copy entry over: ", z->zname); + if ((r = zipcopy(z, x, y)) != ZE_OK) + { + sprintf(errbuf, "was copying %s", z->zname); + ZIPERR(r, errbuf); + } + z->mark = 0; + } + w = &z->nxt; + } + else + { + if (noisy) + { + fprintf(mesg, "deleting: %s\n", z->zname); + fflush(mesg); + } +#ifdef WINDLL + if (lpZipUserFunctions->ServiceApplication != NULL) { + if ((*lpZipUserFunctions->ServiceApplication)(z->zname, 0)) + ZIPERR(ZE_ABORT, "User terminated operation"); + } +#endif + v = z->nxt; /* delete entry from list */ + free((zvoid *)(z->iname)); + free((zvoid *)(z->zname)); + if (z->ext) + 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 + { + /* copy the original entry verbatim */ + if (!d && (r = zipcopy(z, x, y)) != ZE_OK) + { + sprintf(errbuf, "was copying %s", z->zname); + ZIPERR(r, errbuf); + } + w = &z->nxt; + } + } + + + /* Process the edited found list, adding them to the zip file */ + diag("zipping up new entries, if any"); + Trace((stderr, "zip diagnostic: fcount=%u\n", (unsigned)fcount)); + for (f = found; f != NULL; f = fexpel(f)) + { + /* 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; + z->iname = f->iname; + f->iname = NULL; + z->zname = f->zname; + f->zname = NULL; + z->ext = z->cext = z->com = 0; + z->extra = z->cextra = NULL; + z->mark = 1; + z->dosflag = f->dosflag; + /* zip it up */ + if (noisy) + { + fprintf(mesg, " adding: %s", z->zname); + fflush(mesg); + } + if ((r = zipup(z, y)) != ZE_OK && r != ZE_OPEN && r != ZE_MISS) + { + if (noisy) + { +#if (!defined(MACOS) && !defined(WINDLL)) + putc('\n', mesg); + fflush(mesg); +#else + fprintf(stdout, "\n"); +#endif + } + sprintf(errbuf, "was zipping %s", z->zname); + ZIPERR(r, errbuf); + } + if (r == ZE_OPEN || r == ZE_MISS) + { + o = 1; + if (noisy) + { +#if (!defined(MACOS) && !defined(WINDLL)) + putc('\n', mesg); + fflush(mesg); +#else + fprintf(stdout, "\n"); +#endif + } + if (r == ZE_OPEN) { + perror("zip warning"); + zipwarn("could not open for reading: ", z->zname); + } else { + zipwarn("file and directory with the same name: ", z->zname); + } + free((zvoid *)(z->name)); + free((zvoid *)(z->iname)); + free((zvoid *)(z->zname)); + farfree((zvoid far *)z); + } + else + { + *w = z; + w = &z->nxt; + zcount++; + } + } + if (key != NULL) + { + free((zvoid *)key); + key = NULL; + } + + + /* Get one line comment for each new entry */ +#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->zname); + 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; + z->comment = p; + z->com = 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); + } + + + /* Write central directory and end header to temporary zip */ + 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, y)) != 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=%lu, compressed=%lu -> %d%% savings\n", + n, t, percent(n, t)); + t = tempzn - c; /* compute length of central */ + diag("writing end of central directory"); + if ((r = putend(k, t, c, zcomlen, zcomment, y)) != ZE_OK) { + ZIPERR(r, tempzip); + } + tempzf = NULL; + if (fclose(y)) { + ZIPERR(d ? ZE_WRITE : ZE_TEMP, tempzip); + } + if (x != NULL) + fclose(x); + + /* Free some memory before spawning unzip */ +#ifdef USE_ZLIB + zl_deflate_free(); +#else + lm_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 ((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; + if (a && strcmp(zipfile, "-")) { + setfileattr(zipfile, a); +#ifdef VMS + /* If the zip file existed previously, restore its record format: */ + if (x != NULL) + (void)VMSmunch(zipfile, RESTORE_RTYPE, NULL); +#endif + } + +#ifdef __BEOS__ + /* Set the filetype of the zipfile to "application/zip" */ + setfiletype( zipfile, "application/zip" ); +#endif + +#ifdef MACOS + /* Set the Creator/Type of the zipfile to 'IZip' and 'ZIP ' */ + setfiletype(zipfile, 'IZip', 'ZIP '); +#endif + +#ifdef RISCOS + /* Set the filetype of the zipfile to &DDC */ + setfiletype(zipfile, 0xDDC); +#endif + + /* 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/src/apps/bin/zip/zip.h b/src/apps/bin/zip/zip.h new file mode 100644 index 0000000000..f0c6a97af7 --- /dev/null +++ b/src/apps/bin/zip/zip.h @@ -0,0 +1,559 @@ +/* +This is version 1999-Oct-05 of the Info-ZIP copyright and license. +The definitive version of this document should be available at +ftp://ftp.cdrom.com/pub/infozip/license.html indefinitely. + + +Copyright (c) 1990-1999 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, 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, Christian Spieler, 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 following restrictions: + + 1. Redistributions of source code must retain the above copyright notice, + definition, disclaimer, and this list of conditions. + + 2. Redistributions in binary form must reproduce the above copyright + notice, definition, disclaimer, and this list of conditions in + documentation and/or other materials provided with the distribution. + + 3. Altered versions--including, but not limited to, ports to new operating + systems, existing ports with new graphical interfaces, and dynamic, + shared, or static library versions--must be plainly marked as such + and must not be misrepresented as being 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 of the Info-ZIP URL(s). + + 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," + "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 */ + +/* Set up portability */ +#include "tailor.h" + +#ifdef USE_ZLIB +# include "zlib.h" +#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 + +/* 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 */ + + +/* 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 + +/* Structures for in-memory file information */ +struct zlist { + /* See central header in zipfile.c for what vem..off are */ + ush vem, ver, flg, how; + ulg tim, crc, siz, len; + extent nam, ext, cext, com; /* offset of ext must be >= LOCHEAD */ + ush dsk, att, lflg; /* offset of lflg must be >= LOCHEAD */ + ulg atx, off; + 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 */ + char *zname; /* External version of internal name */ + int mark; /* Marker for files to operate on */ + int trash; /* Marker for files to delete */ + 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 */ + int dosflag; /* Set to force MSDOS file attributes */ + 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_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_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) +#else +# define CRCVAL_INITIAL 0L +#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 */ +#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+81]; /* 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*/ +extern int method; /* Restriction on compression method */ + +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 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 */ +#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 +extern int hidden_files; /* process hidden and system files */ +extern int volume_label; /* add volume label */ +extern int dirnames; /* include directory names */ +extern int linkput; /* Store symbolic links as such */ +extern int noisy; /* False for quiet operation */ +extern int extra_fields; /* do not create extra fields */ +#ifdef WIN32 + extern int use_privileges; /* use security privilege overrides */ +#endif +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 ulg zipbeg; /* Starting offset of zip structures */ +extern ulg cenbeg; /* Starting offset of central directory */ +extern struct zlist far *zfiles;/* Pointer to list of files in zip file */ +extern extent zcount; /* Number of files in zip file */ +extern extent zcomlen; /* Length of zip file comment */ +extern char *zcomment; /* Zip file comment (not zero-terminated) */ +extern struct zlist far **zsort;/* List of files sorted by name */ +extern ulg tempzn; /* Count of bytes written to output zip file */ +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 */ + +#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 zipwarn OF((char *, char *)); +void ziperr OF((int, char *)); +#ifdef UTIL +# define error(msg) ziperr(ZE_LOGIC, msg) +#else +/* void error OF((char *));*/ + void error(char *); +# ifdef VMSCLI + void help OF((void)); +# endif + int encr_passwd OF((int, char *, int, ZCONST char *)); +#endif + + /* in zipup.c */ +#ifndef UTIL + int percent OF((ulg, ulg)); + int zipup OF((struct zlist far *, FILE *)); +# 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 +#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 *, FILE *)); +int putextended OF((struct zlist far *, FILE *)); +int putcentral OF((struct zlist far *, FILE *)); +int putend OF((int, ulg, ulg, extent, char *, FILE *)); +int zipcopy OF((struct zlist far *, FILE *, FILE *)); + + /* in fileio.c */ +#ifndef UTIL + char *getnam OF((char *, FILE *)); + struct flist far *fexpel OF((struct flist far *)); + char *last OF((char *, int)); + char *msname OF((char *)); + int check_dup OF((void)); + int filter OF((char *, int)); + int newname OF((char *, int, 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 *)); +int fcopy OF((FILE *, FILE *, ulg)); + +#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 (.c) */ +#ifndef UTIL +# ifdef PROCNAME + int wild OF((char *)); +# endif + char *in2ex OF((char *)); + char *ex2in OF((char *, int, int *)); + int procname OF((char *, int)); + void stamp OF((char *, ulg)); + ulg filetime OF((char *, ulg *, long *, iztimes *)); +#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 *)); +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 */ +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 ***)); + +#ifndef USE_ZLIB +#ifndef UTIL + /* in crc32.c */ +ulg crc32 OF((ulg, ZCONST uch *, extent)); +#endif /* !UTIL */ + + /* in crctab.c */ +ZCONST ulg near *get_crc_table OF((void)); +#ifdef DYNALLOC_CRCTAB +void free_crc_table OF((void)); +#endif +#endif /* !USE_ZLIB */ + +#ifndef UTIL +#ifndef USE_ZLIB + /* in deflate.c */ +void lm_init OF((int, ush *)); +void lm_free OF((void)); +ulg deflate OF((void)); + + /* in trees.c */ +void ct_init OF((ush *, int *)); +int ct_tally OF((int, int)); +ulg 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 */ + + +/*--------------------------------------------------------------------------- + WIN32-only functions: + ---------------------------------------------------------------------------*/ +#ifdef WIN32 + int ZipIsWinNT OF((void)); /* win32.c */ +#endif /* WIN32 */ + +#if (defined(WINDLL) || defined(DLL_ZIPAPI)) +/*--------------------------------------------------------------------------- + Prototypes for public Zip API (DLL) functions. + ---------------------------------------------------------------------------*/ +#include "api.h" +#endif /* WINDLL || DLL_ZIPAPI */ + +#endif /* !__zip_h */ +/* end of zip.h */ diff --git a/src/apps/bin/zip/zipcloak.c b/src/apps/bin/zip/zipcloak.c new file mode 100644 index 0000000000..883b05e310 --- /dev/null +++ b/src/apps/bin/zip/zipcloak.c @@ -0,0 +1,425 @@ +/* + 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 code was originally written in Europe and can be freely distributed + from any country except the U.S.A. If this code is imported into the U.S.A, + it cannot be re-exported from the U.S.A to another country. (This + restriction might seem curious but this is what US law requires.) + */ +#define __ZIPCLOAK_C + +#ifndef UTIL +#define UTIL +#endif +#include "zip.h" +#define DEFCPYRT /* main module: enable copyright string defines! */ +#include "revision.h" +#include "crypt.h" +#include "ttyio.h" +#include +#ifndef NO_STDLIB_H +# include +#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 name and file pointer */ +local char *tempzip; +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 + +/*********************************************************************** + * 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 */ + char *msg; /* message about how it happened */ +{ + if (PERR(code)) perror("zipcloak error"); + fprintf(stderr, "zipcloak error: %s (%s)\n", errors[code-1], 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 stderr and return. + */ +void zipwarn(msg1, msg2) + char *msg1, *msg2; /* message strings juxtaposed in output */ +{ + fprintf(stderr, "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', stderr); +#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 from any country except the U.S.A. If this program is imported", +"into the U.S.A, it cannot be re-exported from the U.S.A to another country.", +"The copyright notice of the zip program applies to the rest of the code." +}; + +/*********************************************************************** + * Print license information to stdout. + */ +local void license() +{ + extent i; /* counter for copyright array */ + + for (i = 0; i < sizeof(public)/sizeof(char *); i++) { + puts(public[i]); + } + for (i = 0; i < sizeof(swlicense)/sizeof(char *); i++) { + puts(swlicense[i]); + } +} + + +static ZCONST char *help_info[] = { +"", +"ZipCloak %s (%s)", +#ifdef VM_CMS +"Usage: zipcloak [-d] [-b fm] zipfile", +#else +"Usage: zipcloak [-d] [-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 use \"fm\" as the filemode for the temporary zip file", +#else +" -b use \"path\" for the temporary zip file", +#endif +" -h show this help -v show version info -L 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(public)/sizeof(char *); i++) { + puts(public[i]); + } + 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'); + } + + 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); +} + + +/*********************************************************************** + * 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 */ + ulg 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 */ + char *q; /* steps through option arguments */ + int r; /* arg counter */ + int res; /* result code */ + ulg length; /* length of central directory */ + FILE *inzip, *outzip; /* input and output zip files */ + struct zlist far *z; /* steps through zfiles linked list */ + +#ifdef THEOS + setlocale(LC_CTYPE, "I"); +#endif + + /* If no args, show help */ + if (argc == 1) { + help(); + EXIT(0); + } + + 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 + temp_path = decrypt = 0; + 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(0); + case 'l': case 'L': /* Show copyright and disclaimer */ + license(); + EXIT(0); + case 'v': /* Show version info */ + version_info(); + EXIT(0); + 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 */ + + if (zipfile == NULL) ziperr(ZE_PARMS, "need to specify zip file"); + + /* 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 ((tempzf = outzip = fopen(tempzip = tempname(zipfile), FOPW)) == NULL) { + ziperr(ZE_TEMP, tempzip); + } + + /* 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 ((inzip = fopen(zipfile, FOPR)) == NULL) ziperr(ZE_NAME, zipfile); + + if (zipbeg && (res = fcopy(inzip, outzip, 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, inzip, outzip, passwd)) != ZE_OK) { + if (res != ZE_MISS) ziperr(res, "was decrypting an entry"); + printf(" (wrong password--just copying)"); + } + putchar('\n'); + + } else if ((!decrypt) && !(z->flg & 1)) { + printf("encrypting: %s\n", z->zname); + fflush(stdout); + if ((res = zipcloak(z, inzip, outzip, passwd)) != ZE_OK) { + ziperr(res, "was encrypting an entry"); + } + } else { + printf(" copying: %s\n", z->zname); + fflush(stdout); + if ((res = zipcopy(z, inzip, outzip)) != ZE_OK) { + ziperr(res, "was copying an entry"); + } + } /* if */ + } /* for */ + fclose(inzip); + + /* Write central directory and end of central directory */ + + /* get start of central */ + if ((start_offset = (ulg)ftell(outzip)) == (ulg)-1L) + ziperr(ZE_TEMP, tempzip); + + for (z = zfiles; z != NULL; z = z->nxt) { + if ((res = putcentral(z, outzip)) != ZE_OK) ziperr(res, tempzip); + } + + /* get end of central */ + if ((length = (ulg)ftell(outzip)) == (ulg)-1L) + ziperr(ZE_TEMP, tempzip); + + length -= start_offset; /* compute length of central */ + if ((res = putend((int)zcount, length, start_offset, zcomlen, + zcomment, outzip)) != ZE_OK) { + ziperr(res, tempzip); + } + tempzf = NULL; + if (fclose(outzip)) ziperr(ZE_TEMP, tempzip); + if ((res = replace(zipfile, 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 *)zipfile); + zipfile = NULL; + + /* Done! */ + RETURN(0); +} +#else /* !CRYPT */ + +int main OF((void)); + +void zipwarn(msg1, msg2) +char *msg1, *msg2; +{ + /* Tell picky compilers to shut up about unused variables */ + msg1 = msg1; msg2 = msg2; +} + +void ziperr(c, h) +int c; +char *h; +{ + /* Tell picky compilers to shut up about unused variables */ + c = c; h = h; +} + +int main() +{ + fprintf(stderr, "\ +This version of ZipCloak does not support encryption. Get zcrypt27.zip (or\n\ +a later version) and recompile. The Info-ZIP file `WHERE' lists sites.\n"); + RETURN(1); +} + +#endif /* ?CRYPT */ diff --git a/src/apps/bin/zip/ziperr.h b/src/apps/bin/zip/ziperr.h new file mode 100644 index 0000000000..0ca8e6cb1b --- /dev/null +++ b/src/apps/bin/zip/ziperr.h @@ -0,0 +1,67 @@ +/* + 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 +*/ +/* + * ziperr.h by Mark Adler + */ + +/* 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 */ +#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_MAXERR 18 /* the highest error number */ + +/* Macro to determine whether to call perror() or not */ +#define PERR(e) (e==ZE_READ||e==ZE_WRITE||e==ZE_CREAT||e==ZE_TEMP||e==ZE_OPEN) + +#ifdef GLOBALS +/* Error messages for the ziperr() function in the zip programs */ +char *errors[ZE_MAXERR] = { +/* 1 */ "", +/* 2 */ "Unexpected end of zip file", +/* 3 */ "Zip file structure invalid", +/* 4 */ "Out of memory", +/* 5 */ "Internal logic error", +/* 6 */ "Entry too big to split", +/* 7 */ "Invalid comment format", +/* 8 */ "Zip file invalid or could not spawn unzip", +/* 9 */ "Interrupted", +/* 10 */ "Temporary file failure", +/* 11 */ "Input file read failure", +/* 12 */ "Nothing to do!", +/* 13 */ "Missing or empty zip file", +/* 14 */ "Output file write failure", +/* 15 */ "Could not create output file", +/* 16 */ "Invalid command arguments", +/* 17 */ "", +/* 18 */ "File not found or no read permission" +# ifdef AZTEC_C + , /* extremely lame compiler bug workaround */ +# endif +}; +#else /* !GLOBALS */ +extern char *errors[ZE_MAXERR]; /* Error messages for ziperr() */ +#endif /* ?GLOBALS */ diff --git a/src/apps/bin/zip/zipfile.c b/src/apps/bin/zip/zipfile.c new file mode 100644 index 0000000000..bc1a8df08e --- /dev/null +++ b/src/apps/bin/zip/zipfile.c @@ -0,0 +1,1560 @@ +/* + 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 +*/ +/* + * zipfile.c by Mark Adler. + */ +#define __ZIPFILE_C + +#include "zip.h" +#include "revision.h" + +#ifdef VMS +# include +# include +# include "vms/vmsmunch.h" +# include "vms/vmsdefs.h" +#endif + +#ifdef __RSXNT__ +# include +#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)) +#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))} + + +/* -- 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 */ +#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 */ + +#define EXTCRC 0 /* uncompressed crc-32 for file */ +#define EXTSIZ 4 /* compressed size in zip file */ +#define EXTLEN 8 /* uncompressed size */ + +#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 */ + +#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 */ + + + +/* Local functions */ + +local int zqcmp OF((ZCONST zvoid *, ZCONST zvoid *)); +local int scanzipf_reg OF((FILE *f)); +#ifndef UTIL + local int rqcmp OF((ZCONST zvoid *, ZCONST zvoid *)); + local int zbcmp OF((ZCONST zvoid *, ZCONST zvoid far *)); + local void zipoddities OF((struct zlist far *)); + local int scanzipf_fix OF((FILE *f)); +# 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 */ +{ + return namecmp((*(struct zlist far **)a)->iname, + (*(struct zlist far **)b)->iname); +} + +#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); +} + + +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 && + (p = search(n, (ZCONST zvoid far **)zsort, zcount, zbcmp)) != NULL) + return *(struct zlist far **)p; + else + return NULL; +} + +#endif /* !UTIL */ + +#ifndef VMS +# 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 */ +#ifdef __RSXNT__ /* 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; +} + +#else /* VMS */ + +# define PATHCUT ']' + +char *ziptyp(s) +char *s; +{ int status; + struct FAB fab; + struct NAM nam; + static char zero=0; + char result[NAM$C_MAXRSS+1],exp[NAM$C_MAXRSS+1]; + char *p; + + fab = cc$rms_fab; + nam = cc$rms_nam; + + fab.fab$l_fna = s; + fab.fab$b_fns = strlen(fab.fab$l_fna); + + fab.fab$l_dna = "sys$disk:[].zip"; /* Default fspec */ + fab.fab$b_dns = strlen(fab.fab$l_dna); + + fab.fab$l_nam = &nam; + + nam.nam$l_rsa = result; /* Put resultant name of */ + nam.nam$b_rss = sizeof(result)-1; /* existing zipfile here */ + + nam.nam$l_esa = exp; /* For full spec of */ + nam.nam$b_ess = sizeof(exp)-1; /* file to create */ + + status = sys$parse(&fab); + if( (status & 1) == 0 ) + return &zero; + + status = sys$search(&fab); + if( status & 1 ) + { /* Existing ZIP file */ + int l; + if( (p=malloc( (l=nam.nam$b_rsl) + 1 )) != NULL ) + { result[l] = 0; + strcpy(p,result); + } + } + else + { /* New ZIP file */ + int l; + if( (p=malloc( (l=nam.nam$b_esl) + 1 )) != NULL ) + { exp[l] = 0; + strcpy(p,exp); + } + } + return p; +} + +#endif /* VMS */ + +#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->zname); + } + 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->zname); + } + if (z->flg != z->lflg) + { + sprintf(errbuf, "local flags = 0x%04x, central = 0x%04x: ", + z->lflg, z->flg); + zipwarn(errbuf, z->zname); + } + else if (z->flg & ~0xf) + { + sprintf(errbuf, "undefined bits used in flags = 0x%04x: ", z->flg); + zipwarn(errbuf, z->zname); + } + if (z->how > DEFLATE) + { + sprintf(errbuf, "unknown compression method %u: ", z->how); + zipwarn(errbuf, z->zname); + } + if (z->dsk) + { + sprintf(errbuf, "starts on disk %u: ", z->dsk); + zipwarn(errbuf, z->zname); + } + if (z->att!=ASCII && z->att!=BINARY && z->att!=__EBCDIC) + { + sprintf(errbuf, "unknown internal attributes = 0x%04x: ", z->att); + zipwarn(errbuf, z->zname); + } +#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->zname); + } +#endif + if (z->ext || z->cext) + { + 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(stderr, "\tzip info: %s%s\n", errbuf, z->zname); + } +#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) */ + { + fprintf(stderr, "zip info: %s has %ld bytes of %sextra data\n", + z->zname, z->ext ? (ulg)z->ext : (ulg)z->cext, + z->ext ? (z->cext ? "" : "local ") : "central "); + } + } +} + +/* + * 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* + */ +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 */ + ulg p; /* current file offset */ + ulg 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 */ + + /* Get any file attribute valid for this OS, to set in the central + * directory when fixing the archive: + */ +#ifndef UTIL + filetime(zipfile, &a, (long*)&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 (;;) { + 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++; + } + b[0] = (char) m; + if (fread(b+1, 3, 1, f) != 1 || (s = LG(b)) == LOCSIG || s == ENDSIG) + break; + if (fseek(f, -3L, SEEK_CUR)) + return ferror(f) ? ZE_READ : ZE_EOF; + 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; + + 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; + + /* 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) || + (s && fseek(f, (long)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 (fseek(f, -15L, SEEK_CUR)) + return ferror(f) ? ZE_READ : ZE_EOF; + } + s = LG(4 + EXTSIZ + b); + p += s; + if ((ulg) ftell(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 == ftell(f), "bad compressed size with extended header"); + + if (fseek(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 */ + z->crc = LG(4 + EXTCRC + b); + z->siz = s; + z->len = LG(4 + EXTLEN + b); + + 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 (fseek(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 %ld, actual size %ld for %s\n", + z->siz, s, 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 %lu bytes\n", + zipfile, zipbeg); + + return ZE_OK; +} + +#endif /* !UTIL */ + +/* + * 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 */ + ush flg; /* general purpose bit flag */ + int m; /* mismatch flag */ + 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 */ + long deltaoff; + + 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 + found = 0; + t = &buf[4096]; + t[1] = '\0'; + t[2] = '\0'; + t[3] = '\0'; + if (fseek(f, -4096L, SEEK_END) == 0) { + zipbeg = (ulg) (ftell(f) + 4096L); + 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); + fseek(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 += (ulg) (t - buf); + fseek(f, (long) zipbeg + 4L, SEEK_SET); + break; + } + --t; + } + } + } + else + zipbeg = 4096L; +/* + * XXX warn: garbage at the end of the file ignored + */ + if (!found && zipbeg > 0) { + size_t s; + + fseek(f, 0L, SEEK_SET); + clearerr(f); + s = fread(buf, 1, (size_t) zipbeg, f); + 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); + fseek(f, (long) 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; + } + /* 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 */ + } +/* + * XXX assumes central header immediately precedes end header + */ + cenbeg = zipbeg - LG(ENDSIZ + b); + deltaoff = adjust ? cenbeg - LG(b + ENDOFF) : 0L; + if (fseek(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; + + /* 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 */ + /* 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 (fseek(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; + } + } + + /* Check extended local header if there is one */ + 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 (fseek(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 */ + 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->zname); + 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); + + /* Clear actions */ + z->mark = 0; + z->trash = 0; +#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 */ + } + else { +#ifdef EBCDIC + strtoebc(z->iname, z->iname); +#endif + zipwarn("local header not found for ", z->iname); + return ZE_FORM; + } +#ifndef UTIL + if (verbose) + zipoddities(z); +#endif + z = z->nxt; + } + + if (zipbeg && noisy) + fprintf(mesg, "%s: %s a preamble of %lu bytes\n", + zipfile, adjust ? "adjusting offsets for" : "found", zipbeg); + +#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; +} + + +/* + * 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 */ + + /* 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(stderr, + "\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 = fopen(zipfile, FOPR)) != NULL); +#else /* !VMS */ + readable = (zipfile != NULL && *zipfile && strcmp(zipfile, "-") && + (f = fopen(zipfile, FOPR)) != NULL); +#endif /* ?VMS */ +#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 = fopen(zipfile, "ab")) == NULL) { + ZIPERR(ZE_OPEN, zipfile); + } + fclose(f); + /* read mode again */ + if ((f = fopen(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 */ + if (readable) + { +#ifndef UTIL + retval = (fix && !adjust) ? scanzipf_fix(f) : scanzipf_reg(f); +#else + retval = scanzipf_reg(f); +#endif + + /* Done with zip file for now */ + fclose(f); + + /* 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); + } + } + return retval; +} + + +int putlocal(z, f) +struct zlist far *z; /* zip entry to write local header for */ +FILE *f; /* file to write to */ +/* Write a local header described by *z to file *f. Return an error code + in the ZE_ class. */ +{ + PUTLG(LOCSIG, f); + PUTSH(z->ver, f); + PUTSH(z->lflg, f); + PUTSH(z->how, f); + PUTLG(z->tim, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + PUTSH(z->nam, f); + PUTSH(z->ext, f); + if (fwrite(z->iname, 1, z->nam, f) != z->nam || + (z->ext && fwrite(z->extra, 1, z->ext, f) != z->ext)) + return ZE_TEMP; + return ZE_OK; +} + +int putextended(z, f) +struct zlist far *z; /* zip entry to write local header for */ +FILE *f; /* file to write to */ +/* Write an extended local header described by *z to file *f. + * Return an error code in the ZE_ class. */ +{ + PUTLG(EXTLOCSIG, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + return ZE_OK; +} + +int putcentral(z, f) +struct zlist far *z; /* zip entry to write central header for */ +FILE *f; /* file to write to */ +/* Write a central header described by *z to file *f. Return an error code + in the ZE_ class. */ +{ + PUTLG(CENSIG, f); + PUTSH(z->vem, f); + PUTSH(z->ver, f); + PUTSH(z->flg, f); + PUTSH(z->how, f); + PUTLG(z->tim, f); + PUTLG(z->crc, f); + PUTLG(z->siz, f); + PUTLG(z->len, f); + PUTSH(z->nam, f); + PUTSH(z->cext, f); + PUTSH(z->com, f); + PUTSH(z->dsk, f); + PUTSH(z->att, f); + PUTLG(z->atx, f); + PUTLG(z->off, f); +#ifdef EBCDIC + if (z->com) + memtoasc(z->comment, z->comment, z->com); +#endif /* EBCDIC */ + if (fwrite(z->iname, 1, z->nam, f) != z->nam || + (z->cext && fwrite(z->cextra, 1, z->cext, f) != z->cext) || + (z->com && fwrite(z->comment, 1, z->com, f) != z->com)) + return ZE_TEMP; + return ZE_OK; +} + + +int putend(n, s, c, m, z, f) +int n; /* number of entries in central directory */ +ulg s; /* size of central directory */ +ulg c; /* offset of central directory */ +extent m; /* length of zip file comment (0 if none) */ +char *z; /* zip file comment if m != 0 */ +FILE *f; /* file to write to */ +/* Write the end of central directory data to file *f. Return an error code + in the ZE_ class. */ +{ + PUTLG(ENDSIG, f); + PUTSH(0, f); + PUTSH(0, f); + PUTSH(n, f); + PUTSH(n, f); + PUTLG(s, f); + PUTLG(c, f); + PUTSH(m, f); +/* Write the comment, if any */ +#ifdef EBCDIC + memtoasc(z, z, m); +#endif + if (m && fwrite(z, 1, m, f) != m) + return ZE_TEMP; + +#ifdef HANDLE_AMIGA_SFX + if (amiga_sfx_offset && zipbeg /* -J zeroes this */) { + s = ftell(f); + 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 (fseek(f, 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, f); + fseek(f, 0, SEEK_END); /* just in case */ + } +#endif + return ZE_OK; +} + + +/* 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, x, y) +struct zlist far *z; /* zip entry to copy */ +FILE *x, *y; /* source and destination files */ +/* Copy the zip entry described by *z from file *x to file *y. Return an + error code in the ZE_ class. Also update tempzn by the number of bytes + copied. */ +{ + ulg n; /* holds local header offset */ + + Trace((stderr, "zipcopy %s\n", z->zname)); + n = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext; + + if (fix > 1) { + if (fseek(x, z->off + n, SEEK_SET)) /* seek to compressed data */ + return ferror(x) ? 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 = (ulg)(4 + LOCHEAD) + (ulg)z->nam + (ulg)z->ext; + } + + /* do not trust the old compressed size */ + if (putlocal(z, y) != ZE_OK) + return ZE_TEMP; + + z->off = tempzn; + tempzn += n; + n = z->siz; + } else { + if (fseek(x, z->off, SEEK_SET)) /* seek to local header */ + return ferror(x) ? ZE_READ : ZE_EOF; + + z->off = tempzn; + n += z->siz; + } + /* copy the compressed data and the extended local header if there is one */ + if (z->lflg & 8) n += 16; + tempzn += n; + return fcopy(x, y, n); +} + + +#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", + 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", + eb_len, 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 ??? */ + 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/src/apps/bin/zip/zipnote.c b/src/apps/bin/zip/zipnote.c new file mode 100644 index 0000000000..cd79844cdc --- /dev/null +++ b/src/apps/bin/zip/zipnote.c @@ -0,0 +1,500 @@ +/* + 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 +*/ +/* + * 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 + + +/* 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 name and file pointer */ +local char *tempzip; +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)); +local char *getline OF((char *, extent)); +local int catalloc OF((char * far *, char *)); +int main OF((int, char **)); + +#ifdef MACOS +#define ziperr(c, h) zipnoteerr(c, h) +#define zipwarn(a, b) zipnotewarn(a, b) + +void zipnoteerr(int c,char *h); +void zipnotewarn(char *a,char *b); +#endif + +#ifdef QDOS +#define exit(p1) QDOSexit() +#endif + +void ziperr(c, h) +int c; /* error code from the ZE_ class */ +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(stderr, "zipnote error: %s (%s)\n", errors[c-1], 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', stderr); +#endif /* !MSDOS */ + ziperr(ZE_ABORT, "aborting"); + s++; /* keep some compilers happy */ +} + + +void zipwarn(a, b) +char *a, *b; /* message strings juxtaposed in output */ +/* Print a warning message to stderr and return. */ +{ + fprintf(stderr, "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(copyright)/sizeof(char *); i++) { + printf(copyright[i], "zipnote"); + putchar('\n'); + } + 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] [-b fm] zipfile", +#else +"Usage: zipnote [-w] [-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 +" -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", +" 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 *getline(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 a[FNMAX+1]; /* input line buffer */ + ulg c; /* start of central directory */ + int k; /* next argument type */ + char *q; /* steps through option arguments */ + int r; /* arg counter, temporary variable */ + ulg s; /* length of central directory */ + int t; /* attributes of zip file */ + int w; /* true if updating zip file from stdin */ + FILE *x, *y; /* input and output zip files */ + struct zlist far *z; /* steps through zfiles linked list */ + +#ifdef THEOS + setlocale(LC_CTYPE, "I"); +#endif + + /* If no args, show help */ + if (argc == 1) + { + help(); + EXIT(0); + } + + 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 + 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(0); + case 'l': case 'L': /* Show copyright and disclaimer */ + license(); EXIT(0); + case 'v': /* Show version info */ + version_info(); EXIT(0); + 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"); + + /* 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 (getline(a, FNMAX+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 (getline(a, FNMAX+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(). + */ + getline(a, FNMAX+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 comments"); + getline(a, FNMAX+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 (getline(a, FNMAX+1) != NULL) + if ((r = catalloc(&zcomment, a)) != ZE_OK) + ziperr(r, "was building new comments"); + zcomlen = strlen(zcomment); + } + + /* Open output zip file for writing */ + if ((tempzf = y = fopen(tempzip = tempname(zipfile), FOPW)) == NULL) + ziperr(ZE_TEMP, tempzip); + + /* Open input zip file again, copy preamble if any */ + if ((x = fopen(zipfile, FOPR)) == NULL) + ziperr(ZE_NAME, zipfile); + if (zipbeg && (r = fcopy(x, y, 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, x, y)) != ZE_OK) + ziperr(r, "was copying an entry"); + } + fclose(x); + + /* Write central directory and end of central directory with new comments */ + if ((c = ftell(y)) == (ulg)(-1L)) /* get start of central */ + ziperr(ZE_TEMP, tempzip); + for (z = zfiles; z != NULL; z = z->nxt) + if ((r = putcentral(z, y)) != ZE_OK) + ziperr(r, tempzip); + if ((s = ftell(y)) == (ulg)-1L) /* get end of central */ + ziperr(ZE_TEMP, tempzip); + s -= c; /* compute length of central */ + if ((r = putend((int)zcount, s, c, zcomlen, zcomment, y)) != 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/src/apps/bin/zip/zipsplit.c b/src/apps/bin/zip/zipsplit.c new file mode 100644 index 0000000000..2937b76cc4 --- /dev/null +++ b/src/apps/bin/zip/zipsplit.c @@ -0,0 +1,810 @@ +/* + 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 +*/ +/* + * 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 + +#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(char *c,char *h); +void zipspliterr(int c,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((ulg *, extent, ulg, ulg)); +local int descmp OF((ZCONST zvoid *, ZCONST zvoid *)); +local extent greedy OF((ulg *, extent, ulg, ulg)); +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[] */ + + +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 */ +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(stderr, "zipsplit error: %s (%s)\n", errors[c-1], 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', stderr); +#endif /* !MSDOS */ + ziperr(ZE_ABORT, "aborting"); + s++; /* keep some compilers happy */ +} + + +void zipwarn(a, b) +char *a, *b; /* message strings juxtaposed in output */ +/* Print a warning message to stderr and return. */ +{ + fprintf(stderr, "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(copyright)/sizeof(char *); i++) { + printf(copyright[i], "zipsplit"); + putchar('\n'); + } + 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 [-tips] [-n size] [-r room] [-b fm] zipfile", +#else +"Usage: zipsplit [-tips] [-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 +" -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(copyright)/sizeof(char *); i++) + { + printf(copyright[i], "zipsplit"); + putchar('\n'); + } + + 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) +ulg *a; /* items to put in bins, return value: destination bins */ +extent n; /* number of items */ +ulg c; /* capacity of each bin */ +ulg 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 */ + ulg 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 **(ulg **)a < **(ulg **)b ? 1 : (**(ulg **)a > **(ulg **)b ? -1 : 0); +} + + +local extent greedy(a, n, c, d) +ulg *a; /* items to put in bins, return value: destination bins */ +extent n; /* number of items */ +ulg c; /* capacity of each bin */ +ulg 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. */ +{ + ulg *b; /* space left in each bin (malloc'ed for each m) */ + ulg *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 */ + ulg **s; /* pointers to e[], sorted descending (malloc'ed) */ + ulg 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 = (ulg *)malloc(n * sizeof(ulg))) == NULL || + (s = (ulg **)malloc(n * sizeof(ulg *))) == 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(ulg)); + 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 = (ulg *)malloc(++m * sizeof(ulg))) == 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)((ulg huge *)(s[i]) - (ulg 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; +} + + +local int retry() +{ + char m[10]; + fputs("Error writing to disk--redo entire disk? ", stderr); + 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. */ +{ + ulg *a; /* malloc'ed list of sizes, dest bins */ + extent *b; /* heads of bin linked lists (malloc'ed) */ + ulg 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 */ + ulg 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) */ + ulg *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 */ + ulg 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 + +#ifdef THEOS + setlocale(LC_CTYPE, "I"); +#endif + + /* If no args, show help */ + if (argc == 1) + { + help(); + EXIT(0); + } + + init_upper(); /* build case map table */ + + /* Go through args */ + signal(SIGINT, handler); +#ifdef SIGTERM /* Amiga has no SIGTERM */ + signal(SIGTERM, 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(0); + case 'i': /* Make an index file */ + x = 1; + break; + case 'l': case 'L': /* Show copyright and disclaimer */ + license(); EXIT(0); + 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 '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(0); + 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"); + + + /* 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 = (ulg *)talloc(zcount * sizeof(ulg))) == 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; + t += a[j] = 8 + LOCHEAD + CENHEAD + + 2 * (ulg)z->nam + 2 * (ulg)z->ext + z->com + z->siz; + if (a[j] > c) + 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 = (ulg *)talloc(zcount * sizeof(ulg))) == NULL) + ziperr(ZE_MEM, "was computing split"); + memcpy((char *)p, (char *)a, zcount * sizeof(ulg)); + 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 (%ld%% efficiency)\n", + (ulg)s, d ? "ould" : "ill", ((200 * ((t + c - 1)/c)) / s + 1) >> 1); + if (d) + { + tfreeall(); + free((zvoid *)zipfile); + zipfile = NULL; + EXIT(0); + } + + /* 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, "/"); + name = path + strlen(path); +#else +# ifdef RISCOS + if (path[0] && path[strlen(path) - 1] != '.') + strcat(path, "."); + name = path + strlen(path); +# else /* !RISCOS */ +# ifndef QDOS + if (path[0] && path[strlen(path) - 1] != '/') + strcat(path, "/"); +# else + if (path[0] && path[strlen(path) - 1] != '_') + strcat(path, "_"); +# endif + name = path + strlen(path); +# endif +#endif /* ?AMIGA */ + } + + /* 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: + + /* prompt if requested */ + if (u) + { + char m[10]; + fprintf(stderr, "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, "%5ld %s\n", a[j] + 1, 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 ((f = fopen(path, FOPW)) == NULL) + { + if (u && retry()) goto redobin; + ziperr(ZE_CREAT, path); + } + tempzn = 0; + + /* write local headers and copy compressed data */ + for (g = b[j]; g != (extent)-1; g = (extent)n[g]) + { + if (fseek(e, w[g]->off, SEEK_SET)) + ziperr(ferror(e) ? ZE_READ : ZE_EOF, zipfile); + if ((r = zipcopy(w[g], e, f)) != ZE_OK) + { + if (r == ZE_TEMP) + { + if (u && retry()) goto redobin; + ziperr(ZE_WRITE, path); + } + else + ziperr(r, zipfile); + } + } + + /* write central headers */ + if ((c = ftell(f)) == (ulg)(-1L)) + { + 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], f)) != ZE_OK) + { + if (u && retry()) goto redobin; + ziperr(ZE_WRITE, path); + } + + /* write end-of-central header */ + if ((t = ftell(f)) == (ulg)(-1L) || + (r = putend(k, t - c, c, (extent)0, (char *)NULL, f)) != 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", stderr); + tfreeall(); + + RETURN(0); +} diff --git a/src/apps/bin/zip/zipup.c b/src/apps/bin/zip/zipup.c new file mode 100644 index 0000000000..b0782a6bda --- /dev/null +++ b/src/apps/bin/zip/zipup.c @@ -0,0 +1,1176 @@ +/* + 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 +*/ +/* + * zipup.c by Mark Adler and Jean-loup Gailly. + */ +#define __ZIPUP_C + +#include +#include "zip.h" + +#ifndef UTIL /* This module contains no code for Zip Utilities */ + +#include "revision.h" +#include "crypt.h" +#ifdef USE_ZLIB +# include "zlib.h" +#endif + +#ifdef OS2 +# include "os2/os2zip.h" +#endif + +#if defined(MMAP) +# include +# 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 __human68k__ +# include "human68k/zipup.h" +#endif /* __human68k__ */ + +#ifdef MACOS +# include "macos/zipup.h" +#endif + +#ifdef DOS +# include "msdos/zipup.h" +#endif /* DOS */ + +#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 */ +local ulg filecompress OF((struct zlist far *z_entry, FILE *zipfile, + int *cmpr_method)); + +/* 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; /* 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 FILE *zfile; /* output zip file */ + 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 DEBUG + ulg isize; /* input file size. global only for debugging */ +#else /* !DEBUG */ + local ulg isize; /* input file size. */ +#endif /* ?DEBUG */ + + +int percent(n, m) +ulg n; +ulg m; /* n is the original size, m is the new size */ +/* Return the percentage compression from n to m using only integer + operations */ +{ + 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; +} + +#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, y) +struct zlist far *z; /* zip entry to compress */ +FILE *y; /* output file */ +/* 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. */ +{ + 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 */ + ulg o, p; /* offsets in zip file */ + long q = -3L; /* size returned by filetime */ + int r; /* temporary variable */ + ulg s = 0L; /* size of compressed data */ + int isdir; /* set for a directory name */ + int set_type = 0; /* set if file type (ascii/binary) unknown */ + + z->nam = strlen(z->iname); + isdir = z->iname[z->nam-1] == (char)0x2f; /* ascii[(unsigned)('/')] */ + + if ((tim = filetime(z->name, &a, &q, &f_utim)) == 0 || q == -3L) + return ZE_OPEN; + + /* q is set to -1 if the input file is a device, -2 for a volume label */ + if (q == -2L) { + 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; + } + 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 */ + 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 */ + + /* 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 */ + } +#endif /* !(VMS && VMS_PK_EXTRA) */ + l = issymlnk(a); + if (l) + ifile = fbad; + 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 ((ifile = zopen(z->name, fhow)) == fbad) + return ZE_OPEN; + } + + 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 */ + +#ifdef MMAP + /* Map ordinary files but not devices. This code should go in fileio.c */ + if (!translate_eol && q != -1L && (ulg)q > 0 && + (ulg)q + MIN_LOOKAHEAD > (ulg)q) { + 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 */ +# ifdef BIG_MEM + /* Read the whole input file at once */ + if (!translate_eol && q != -1L && (ulg)q > 0 && + (ulg)q + MIN_LOOKAHEAD > (ulg)q) { + 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 /* BIG_MEM */ +#endif /* ?MMAP */ + + } /* strcmp(z->name, "-") == 0 */ + + if (l || 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. + */ + + /* 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) + 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 FAT file system, we cheat and pretend that the file + * was not made on OS2/WIN32 but under DOS. unzip is confused otherwise. + */ +#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 */ + z->crc = 0; /* to be updated later */ + /* Assume first that we will need an extended local header: */ + z->flg = 8; /* to be updated later */ +#if CRYPT + if (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; + } +#endif /* CRYPT */ + z->lflg = z->flg; + z->how = (ush)m; /* may be changed later */ + z->siz = (ulg)(m == STORE && q >= 0 ? q : 0); /* will be changed later */ + z->len = (ulg)(q != -1L ? q : 0); /* may be changed later */ + z->dsk = 0; + 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 */ + z->off = tempzn; + if ((r = putlocal(z, y)) != ZE_OK) { + if (ifile != fbad) + zclose(ifile); + return r; + } + tempzn += 4 + LOCHEAD + z->nam + z->ext; + +#if CRYPT + if (key != NULL) { + crypthead(key, z->crc, y); + 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"); + } + + o = ftell(y); /* for debugging only, ftell can fail on pipes */ + if (ferror(y)) + clearerr(y); + + /* Write stored or deflated file to zip file */ + isize = 0L; + crc = CRCVAL_INITIAL; + + if (m == DEFLATE) { + if (set_type) z->att = (ush)UNKNOWN; /* is finally set in filecompress() */ + s = filecompress(z, y, &m); +#ifndef PGP + if (z->att == (ush)BINARY && translate_eol) { + zipwarn("-l used on binary file", ""); + } +#endif + } + else if (!isdir) + { + 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, y) != 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, y) != k) + { + if (ifile != fbad) + zclose(ifile); + free((zvoid *)b); + return ZE_TEMP; + } +#ifndef WINDLL + if (verbose) putc('.', stderr); +#else + if (verbose) fprintf(stdout,"%c",'.'); +#endif + } + } + free((zvoid *)b); + s = isize; + } + if (ifile != fbad && zerr(ifile)) { + perror("\nzip warning"); + zipwarn("could not read input file: ", z->zname); + } + 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 != (ulg)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) */ + + /* Try to rewrite the local header with correct information */ + z->crc = crc; + z->siz = s; +#if CRYPT + if (key != NULL) + z->siz += RAND_HEAD_LEN; +#endif /* CRYPT */ + z->len = isize; +#ifdef BROKEN_FSEEK + if (!fseekable(y) || fseek(y, z->off, SEEK_SET)) +#else + if (fseek(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, y)) != ZE_OK) + return r; + tempzn += 16L; + z->flg = z->lflg; /* if flg modified by inflate */ + } else { + /* seek ok, ftell() should work, check compressed size */ +#if !defined(VMS) && !defined(CMS_MVS) + if (p - o != s) { + fprintf(mesg, " s=%ld, actual=%ld ", s, p-o); + error("incorrect compressed size"); + } +#endif /* !VMS && !CMS_MVS */ + z->how = (ush)m; + z->ver = (ush)(m == STORE ? 10 : 20); /* Need PKUNZIP 2.0 unless STORED */ + if ((z->flg & 1) == 0) + z->flg &= ~8; /* clear the extended local header flag */ + z->lflg = z->flg; + /* rewrite the local header: */ + if ((r = putlocal(z, y)) != ZE_OK) + return r; + if (fseek(y, p, SEEK_SET)) + return ZE_READ; + if ((z->flg & 1) != 0) { + /* encrypted file, extended header still required */ + if ((r = putextended(z, y)) != ZE_OK) + return r; + tempzn += 16L; + } + } + /* 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=%lu) (out=%lu)", isize, s); + if (m == DEFLATE) + fprintf(mesg, " (deflated %d%%)\n", percent(isize, s)); + else + fprintf(mesg, " (stored 0%%)\n"); + fflush(mesg); + } +#ifdef WINDLL + if (lpZipUserFunctions->ServiceApplication != NULL) + { + if ((*lpZipUserFunctions->ServiceApplication)(z->zname, isize)) + { + ZIPERR(ZE_ABORT, "User terminated operation"); + } + } +#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; + +#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) { + /* Transform LF to CR LF */ + size >>= 1; + b = buf+size; + size = len = zread(ifile, b, size); + if (len == (unsigned)EOF || len == 0) return len; +#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 { + /* 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; + 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); + isize += (ulg)len; + 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(stderr, + "\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"); + } + } +} + +#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 (zfile == 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, zfile); + if (ferror(zfile)) 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(zfile); +} +#endif /* ?USE_ZLIB */ + + +/* =========================================================================== + * Compression to archive file. + */ + +local ulg filecompress(z_entry, zipfile, cmpr_method) + struct zlist far *z_entry; + FILE *zipfile; + 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 + +#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, zipfile) != 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) + while((unsigned)(zstrm.total_in / (uLong)WSIZE) > mrk_cnt) { + mrk_cnt++; +#ifndef WINDLL + putc('.', stderr); +#else + fprintf(stdout,"%c",'.'); +#endif + } +#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, zipfile) != 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, zipfile) != 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. */ + zfile = zipfile; + 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; +#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 */ + zfile = NULL; + 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, NULL); + 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)(DEFLATE & 0xff); + tgt[1] = (char)((DEFLATE >> 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 */ +#endif /* !UTIL */