summaryrefslogtreecommitdiff
path: root/macos
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 19:30:57 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 19:30:57 +0100
commit04664087ad66f5614f82a2cfba3ae4eda15e792b (patch)
tree332090b15fd2db1b93abf40dccf06211d9aba297 /macos
downloadzip-04664087ad66f5614f82a2cfba3ae4eda15e792b.tar.gz
Tarball conversion
Diffstat (limited to 'macos')
-rw-r--r--macos/Contents63
-rw-r--r--macos/HISTORY.TXT600
-rw-r--r--macos/README.TXT569
-rw-r--r--macos/ZipLib.h166
-rw-r--r--macos/ZipSx.h167
-rw-r--r--macos/ZpPrj.hqx455
-rw-r--r--macos/osdep.h118
-rw-r--r--macos/readme.1st16
-rw-r--r--macos/source/VolWarn.h69
-rw-r--r--macos/source/charmap.h380
-rw-r--r--macos/source/extrafld.c920
-rw-r--r--macos/source/getenv.c398
-rw-r--r--macos/source/helpers.c479
-rw-r--r--macos/source/helpers.h57
-rw-r--r--macos/source/macglob.h86
-rw-r--r--macos/source/macopen.c363
-rw-r--r--macos/source/macopen.h21
-rw-r--r--macos/source/macos.c1079
-rw-r--r--macos/source/macstuff.c1724
-rw-r--r--macos/source/macstuff.h18
-rw-r--r--macos/source/mactime.c451
-rw-r--r--macos/source/mactime.h61
-rw-r--r--macos/source/pathname.c726
-rw-r--r--macos/source/pathname.h64
-rw-r--r--macos/source/recurse.c442
-rw-r--r--macos/source/recurse.h129
-rw-r--r--macos/source/unixlike.c313
-rw-r--r--macos/source/unixlike.h86
-rw-r--r--macos/source/zip_rc.hqx43
-rw-r--r--macos/zipup.h25
30 files changed, 10088 insertions, 0 deletions
diff --git a/macos/Contents b/macos/Contents
new file mode 100644
index 0000000..3aec069
--- /dev/null
+++ b/macos/Contents
@@ -0,0 +1,63 @@
+Contents of the "macos" sub-archive for Zip 2.3 and later:
+
+
+MacOS:
+
+ Contents this file
+ readme.1st Instruction to unpack mac specific files
+ README.TXT Dirk Haase's infos on updated MacIntosh ports of Zip/UnZip
+ HISTORY.TXT Dirk Haase's MacOS specific ChangeLog
+
+ zipup.h MacOS
+ osdep.h MacOS specific configuration and declarations
+
+ ZipLib.h used to build a static library, global to the project
+ ZipSx.h used to build a standalone App with MW Sioux, global
+ to the project
+ ZpPrj.hqx Metrowerks CodeWarrior pro3 project file (BinHex)
+
+
+ source/ subdirectory containing all sources:
+ a) Zip specific code
+ extrafld.c contains all code related to the mac extra field
+ extrafld.h
+ macglob.h
+ macopen.c replaces fopen() and open()
+ macopen.h
+ macos.c Macintosh-specific routines for use with Info-ZIP's Zip
+ MatWild.c Pattern matching function
+ recurse.c Functions to go through the directories
+ recurse.h
+ unixlike.c This file provides a unix like file-stat routine
+ unixlike.h
+ VolWarn.h contains the warning message, about volumes with the
+ same name
+ zip_rc.hqx resource file for Macintosh unzip (BinHex)
+
+
+ b) general utilities shared between Zip and UnZip
+ charmap.h character mapping tables ISO 8859-1 <--> MacRoman
+ helpers.c some helper functions
+ helpers.h
+ macstuff.c Mac filemanager routines copied from MoreFiles 1.4.8
+ macstuff.h
+ mactime.c replacement for broken Metrowerks RTL time functions
+ pathname.c functions for handling MacOS HFS path- /filenames
+ pathname.h
+
+The new ZpPrj.hqx project file should be "un-BinHex'ed" into ZpPrj,
+which builds the following targets:
+ - Zip Lib (68K) -> static library 68k
+ - Zip Lib (PPC) -> static library PPC
+ - Zip Sioux (68K) -> MW Sioux standalone App, good for debugging
+ - Zip Sioux (PPC) -> MW Sioux standalone App, good for debugging
+
+
+The resource files and the compiler project files are in BinHex form because
+they contain Macintosh resource forks. The resource info cannot be
+maintained when handling (e.g. repacking) the master source collection on
+non-Macintosh systems. The BinHex form is the traditional way for
+transferring such files via non-Macintosh systems.
+It's also the safest since it uses only printable characters. The ".hqx"
+files must be converted with StuffitExpander or BinHex 4.0 (or equivalent)
+on a Macintosh system before using them.
diff --git a/macos/HISTORY.TXT b/macos/HISTORY.TXT
new file mode 100644
index 0000000..3a14a02
--- /dev/null
+++ b/macos/HISTORY.TXT
@@ -0,0 +1,600 @@
+A free Macintosh Port of Info-ZIP's
+Zip and UnZip
+By Dirk Haase, d_haase@sitec.net
+Home page: www.sitec.net/maczip
+Mirror page:
+www.haase-online.de/dirk/maczip
+================================
+
+
+
+
+
+Release MacZip ver1.07 beta 1
+22. Februray 2001
+-----------------
+
+1) CHG: {unzip} switch to latest final release
+ unzip 5.42
+
+2) CHG: {zip} switch to latest beta release
+ zip 2.40a
+
+
+
+
+
+Release MacZip ver1.06 final
+22. Februray 2001
+-----------------
+
+1) CHG: {unzip} switch to latest final release
+ unzip 5.42
+
+2) CHG: switch to latest release of Apples
+ Universal Interfaces 3.3.2
+
+3) CHG: switch to latest release of
+ Morefiles 1.5
+
+
+
+
+Release MacZip ver1.06 beta 2
+02. August 2000
+---------------
+
+1) CHG: {unzip} switch to latest beta release
+ unzip 5.42d
+
+
+
+
+
+Release MacZip ver1.06 beta 1
+27. July 2000
+-------------
+
+1) CHG: {zip} switch to latest beta release
+ unzip 2.30
+
+2) CHG: {unzip} switch to latest beta release
+ unzip 5.42c
+
+
+
+
+
+Release MacZip ver1.05 final
+27. July 2000
+-------------
+
+1) CHG: {unzip} switch to latest final release
+ unzip 5.41
+
+2) FIX: {unzip} Fixed "unique unzip folder" foldername handling
+
+3) FIX: {unzip} added prototype crc32() in macbin3.c
+
+4) CHG: {unzip/zip} added exported Codewarrior project-file in xml-format
+
+5) ADD: {unzip} added extra-field recognition for Mac SmartZip in
+ zipinfo.c and unzpriv.h.
+
+
+
+
+
+Release MacZip ver1.04 final
+25. January 2000
+----------------
+
+
+Final release of MacZip. All parts now
+in final release state !!
+
+1) Switch to MW Codewarrior pro 5.3
+
+2) CHG: {zip} switch (back) to latest final release
+ unzip 2.30
+
+3) CHG: {unzip} switch (back) to latest final release
+ unzip 5.40
+
+
+
+
+Release MacZip ver1.04 beta 3
+05. October 1999
+----------------
+
+1) CHG: {zip} switch to latest source level
+ unzip 2.30o beta release
+
+2) CHG: {unzip} switch to latest source level
+ unzip 5.41c beta release
+
+3) ADD: {console} added menu to print the license
+
+
+
+
+Release MacZip ver1.04 beta 2
+02. June 1999
+--------------
+
+1) FIX: {unzip} added one more criteria to make the recognition
+ of macbinary more save.
+
+2) FIX: {unzip} sometimes, archive entries without any extra field
+ caused problems; the default setting of the extra field
+ was not set back to 'unknown' properly.
+
+3) FIX: {zip} Archive filename with invalid characters like '/' gets
+ renamed. However, I do not check the complete path - needs
+ some more work here.
+
+4) FIX: {zip} Filename match was case sensitive.
+
+6) CHG: {zip} switch to latest source level
+ unzip 2.30m beta release
+
+7) CHG: {unzip} switch to latest source level
+ unzip 5.41b beta release
+
+8) FIX: {zip/unzip 68k only) I have found a wrong compiler setting
+ for the 68k version. Because of this wrong setting the 68k
+ version crashed.
+
+
+
+
+Release MacZip ver1.04 beta 1
+30. March 1999
+--------------
+
+1) CHG: {unzip) switch to latest source level
+ unzip 5.41a beta release
+
+2) ADD: {all} Added message logging support for Syslogd
+ by Brian Bergstrand. Syslogd can be found at
+ http://www.classicalguitar.net/brian/apps/syslogd/
+ This feature is 'under construction'.
+
+3) FIX: {all} many small fixes and code cleanups
+
+
+
+
+Release MacZip ver1.03
+27. March 1999
+--------------
+
+1) CHG: {console} Like Stuffit Expander MacZip quits automatically when
+ used with drag'n drop or as Helper App (Web-Browser).
+
+2) CHG: {console} Since Macintosh users are used to be guided by their
+ software in order not to do something stupid, I added a check
+ to post an extra warning if the options -m and data fork only
+ are both checked.
+ This behavior can be disabled: See Applescript example and
+ "maczip.env".
+
+3) CHG: {zip} switch from immediate deletion to moving to the
+ trash. Immediate deletion is now an option in "maczip.env".
+
+4) CHG: {zip} enhanced progress display.
+
+5) CHG: {zip) switch to latest source level
+ zip 2.3l beta release
+
+6) CHG: {unzip} The zip archive contains file names greater than
+ 31 characters. When MacZip tries to unzip the file, the
+ FSpCreate command fails because the filename length is to
+ long. MacZip correct this problem by trying to truncate
+ the file names to the 31 character limit.
+
+7) FIX: {zip/console} A couple of minor fixes
+
+8) CHG: {zip} Switched file-globbing to the Info-ZIP version.
+
+
+
+
+Release MacZip ver1.02
+14. February 1999
+-----------------
+
+1) CHG: {zip} Changed the rule of file inclusion if switch '-X'
+ is set. Following conditions are checked:
+ a) if length of resource-fork is equal zero *and* the
+ length of data-fork is equal zero include the file.
+ b) if length of resource-fork greater zero *and* the
+ length of data-fork is equal zero don't include the file.
+ c) if length of data-fork greater zero include the file.
+
+2) CHG: {Console} Some users are very confused by the buttons "START PATH"
+ and "ZIP ARCHIVE". Somehow, it wasn't clear what the intended
+ meaning was. I changed the buttons to more clear labels on
+ them like: "file or folder to compress" and "location of
+ compressed file"
+
+3) CHG: {Console} I changed the menu structure to be more intuitive.
+
+4) FIX: {Console} Found a nasty bug which sometimes caused crashes
+ when the Zip / Unzip Dialogbox was used.
+
+5) CHG: {Console} Handling of file dialog is now a bit more restricted:
+ e.g: it's not possible to select a file if you have to select
+ a folder.
+
+
+
+
+Release MacZip ver1.01
+30. January 1999
+----------------------
+
+1) CHG: {console} The use of the "Current App" mechanism was clumsy
+ and forces the user into the Zip or Unzip modes. This kind
+ of modality is not so good for the command line. It's now
+ neccessary to enter zip or unzip to choose the action.
+
+2) FIX: {console} When Applescript sends quit to MacZip the script
+ that is running shows a spinning cursor and MacZip
+ does not quit.
+
+3) FIX: {console} MacZip gots accidentally the wrong creator code
+ (from BBedit)
+
+
+
+
+Final Release MacZip ver1.0
+---------------------------
+
+Released 21. January 1999
+
+
+
+
+9. Beta release 06.December.1998
+---------------------------------
+
+1) CHG: {console} The checkbox of Filedialog (for extract path and file path)
+ "Show all files" is now selected by default.
+
+2) CHG: {unzip/standalone} changed prototypes of mac[f]printf() to return
+ an int number (better ANSI conformance);
+
+3) FIX: {unzip} repaired "stdout/stderr" mode of macwrite(). So func
+ MacMessagePrnt() is now obsolete and removed.
+
+4) ADD: {zip/unzip} Compressed Mac3 extra-fields are now supported
+ (Thanks to Christian Spieler)
+
+5) ADD: {unzip} Extraction of ZipIt archive are now supported. This support
+ is not complete: Filenames are correct but folder names are only
+ restored with the public directory names.
+
+6) ADD: {zip/unzip} Improved documentation.
+
+7) FIX: {unzip} Function isZipfile() is completely rewritten.
+
+8) CHG: {zip/unzip) switch to latest source level
+ zip 2.3i beta and unzip 5.4 final release
+
+9) ADD: Applescript event "do_cmd".
+
+Unless there are big bugs found, this release will be the last
+beta release. The final release will come out in January 1999.
+
+
+
+
+8. Beta release 20.November.1998
+---------------------------------
+
+1) CHG: {zip/unzip) switch to latest source level
+ zip 2.3h beta and unzip 5.4 final release
+
+2) ADD: {zip} Zip finds "namelocked" files also, if switch "-S"
+ is set.
+
+3) FIX: {unzip} Function isZipfile() fails if the zip archive
+ has a comment.
+
+4) CHG: {zip} added some small speed improvements to pattern matching and
+ isZipFile() function.
+
+5) FIX: {unzip} Display of comments is fixed.
+ UzpMessagePrnt() is replaced by MacMessagePrnt(). I do not care
+ about ansi-bombs. I'm not sure, so this fix may be changed later.
+
+6) RMV: {unzip} Buildin More capability is removed since it's already built
+ into the GUI-App.
+
+
+
+7. Beta release 09.November.1998
+---------------------------------
+
+1) CHG: {all} switched to Metrowerks Codewarrior Pro 4
+
+2) FIX: {unzip} Display of comments stored in the zip-file is
+ now fixed
+
+3) FIX: {zip} Fixed display of the zip help-screen.
+
+4) CHG: {zip/unzip} Changed special dir 'Re$0urce.Fk' to 'XtraStuf.mac'
+ (see entry at 13.June.1998 item 3). I found it more descriptive for
+ users outside the mac-community.
+
+5) CHG: {all} switched to MoreFiles 1.4.9.
+
+6) CHG: {console} changed behaivor of the file open dialog: The select
+ button is now always enabled.
+
+7) ADD: {all} Environment variables are now supported.
+ Basically, it is possible to add timezone (= TZ environment variable)
+ support here, but it's not yet implemented.
+ See "MacZip.Env" for further info.
+
+8) RMV: {console} Targets "zip only" and "unzip only" are removed.
+
+
+
+6. Beta release 09.September.1998
+---------------------------------
+
+
+1) CHG: {Zip/Unzip} Metrowerks Standardlibrary time funktions are
+ rather broken and incomplete so I was forced to rewrite the
+ funktions: mktime(), localtime(), gmtime() and time().
+
+2) ADD: {Console} Added Pause Funktion for screen output.
+ The Pause-Function is selfadjusting: Count of lines is depending
+ on the window size.
+
+3) CHG: Extra-Field layout is changed: All datas are now in little-endian
+ format (see appnote)
+
+4) ADD: {Console} Added an option to test the archive automatically
+ after zipping. This option is only via Zip-Dialogbox available
+ because it needs the unzip-module also.
+
+5) CHG: {Zip} code is now up to date with the latest beta 2.3f.
+
+6) ADD: {Console} Added (drag'n) drop support. Drop on the MacZip icon.
+ The following situations are supported:
+ 1. drop of one or more zipfiles (action = unzip)
+ each archive will be extracted in a separate folder
+ 2. drop of a folder (action = zip -r )
+ The complete folder (inclusive sub-folders)
+ will be zipped
+ Not (yet) supported is currently: dropping more than one file
+ to compress. Workaround: Put all your files in one folder and
+ drop that folder on MacZip.
+ MacZip recognize zip-archives automatically.
+
+
+5. Beta release 21.Aug.1998
+----------------------------
+
+
+1) ADD: {Console} Userinterface has now a Statusbar to show the
+ Progress.
+
+2) ADD: {Console} It's now possible to stop the run of Zip/Unzip
+ with the well known shortcut [Command] + [.]
+
+3) CHG: {Console} Improved user-entry routine.
+
+4) ADD: {Zip/Unzip} Crypt-code added. It's now possible to
+ encrypt/decrypt archives.
+
+5) RMV: {Unzip} Removed the warning of PKZip/Mac archive.
+ Unzip gets confused with the extra field of PKZip/Mac. So I assume
+ the extra field isn't compatible with Info-ZIP's definition.
+
+6) CHG: switched to Metrowerks Codewarrior Pro 3
+ this includes:
+ - new Universal Interfaces 3.1 Headers
+ - improved codegeneration
+
+7) CHG: {Zip} code is now up to date with the latest beta 2.3e.
+
+8) CHG: {Unzip} changed function names wprintf, wgets .. to macprintf, macgets ..
+ to avoid naming conflict standart library.
+
+9) ADD: {Zip/Unzip} FXinfo, Mac-Pathname, file-dates and Finder-Comments
+ are now stored in the extra-field. Extra-field layout is
+ changed accordingly. Unzip uses now the filename stored in the
+ extra-field when unzipping.
+
+10) CHG: {Unzip} code is now up to date with the latest beta 5.33g.
+
+11) CHG: {Unzip} code is (again) up to date with the latest beta 5.33h.
+
+12) ADD: {Unzip} following switches were added:
+ -J [MacOS only] ignore mac extra info. All macintosh
+ info are not restored. Datafork and resource-fork
+ are restored separatly.
+
+ -i [MacOS only] ignore filenames stored in mac extra
+ field. Use the most compatible filename stored in
+ the public field.
+
+ -E [MacOS only] show mac extra field during restoring
+
+13) ADD: {Zip/Unzip} Charset MacRoman to ISO8859 Latin and vice versa
+
+14) RMV: {Zip} -N option removed. This MacZip crashes using this option.
+ I will fix it later.
+
+
+I think I'm very close for a final release of "MacZip 1.0" :-)
+
+
+
+4. Beta release 27.June.1998
+----------------------------
+
+26.June.1998
+------------
+
+1) FIX: {Zip} extra field size value was wrong.
+
+
+
+25.June.1998
+------------
+
+1) CHG: {Zip} code is now up to date with the latest beta 2.3d.
+ So both modules, zip & unzip, uses now latest beta.
+
+2) ADD: {Zip} added a UT extra-field for better compatibility.
+
+3) CHG: {Unzip} changed the code to find the mac extra-field.
+ Unzip has to look for a mac extra-field because
+ mac-archives has now two extra-fields (UT + M3).
+
+4) CHG: {Unzip} changed the method to move extra-field data to
+ the internal extra-structure.
+ Old method was just BlockMove of the ef_structptr to ef_memptr.
+ This method was dangerous because not all members of the
+ structure seamless aligned. There are may be some fill
+ bytes in the structure depending on the compiler setting.
+
+5) ADD: {Unzip} added a warning if unzipping a ZipIt/PKZip archive.
+ ZipIt/PKZip archives are usually additionally coded somehow.
+ InfoZip's Unzip will *not* decode the files. So extracted
+ files are may be not decoded. (see also 6. and 7.)
+
+6) ADD: ZipIt (the Shareware Tool) has now a new extra-field signature:
+ 0x2705. Found in "ZipIt 1.3.8". I added a new macro: EF_ZIPIT2
+
+7) ADD: Added PKWare's extra-field signature: 0xCF77.
+ Found in "PKZIP v2.03". I added a new macro: EF_PKMAC
+
+8) ADD: {console} It's now possible to save all screen outputs
+ to the disk.
+
+9) RMV: {console} this is the first beta without expire-date.
+
+
+16.June.1998
+------------
+
+1) FIX: {Unzip/console} Extract path now defaults to current-dir if
+ no path is given.
+
+2> CHG: {Unzip} creates now a extract-folder by default. This behavior
+ differs to the commandline tool of Unzip on other platforms.
+ However, for a mac-user is this behavior more convenient.
+
+
+3. Beta release 15.June.1998
+----------------------------
+
+15.June.1998
+------------
+
+1) CHG: {unzip/zip} I changed the layout of the extra field
+ to support more data.
+
+
+14.June.1998
+------------
+
+1) FIX: {Unzip} adjusted time_t value with an correct offset value.
+
+2) FIX: {Unzip} removed all unused code based on unfinished ideas by
+ former porter(s).
+
+3) CHG: use of shared code izshr 032.
+
+13.June.1998
+------------
+
+1) FIX: {Unzip} Filenames are only converted when needed. When zipping
+ with the switch 'datafork only' the filenames are shorted which
+ was wrong.
+
+2) CHG: {Unzip} code is now up to date with the latest beta 5.33f.
+
+3) CHG: {Zip} Changed the naming rule of filenames from old Johnny Lee's
+ to my implementation. Johnny Lee's idea is based on change of the
+ filenames which cases several problems when unziping on a non mac
+ plattform. My idea is to add a special directory: 'Re$0urce.Fk'.
+ For the future: Zip will create archives according the new nameing
+ rule. However unzip will be compatible with old nameing rule.
+ See also 4.
+
+4} ADD: {Unzip} Added a new nameing rule for resource forks filename.
+ Resource forks are now stored in a special directory: 'Re$0urce.Fk'.
+ This naming rule make it easier to for other platforms to use
+ mac zip-files.
+
+
+
+11.June.1998
+------------
+1) FIX: {Zip} Internal file attribute is set to BINARY by default
+ when zipping resource forks otherwise Unzip will create
+ sometimes wrong resource-forks.
+
+2) CHG: {Unzip} code is now up to date with the latest beta 5.33e.
+
+
+
+
+2. Beta release 10.June.1998
+--------------------------
+
+1) FIX: {Unzip} Long pathname fix solved. Unzip is now able to extract
+ archives with path longer than 256 chars.
+
+2) CHG: {Unzip} removed all conversion from c-style string to
+ pascal-string (see fix 1)
+
+3) ADD: {Unzip} Finderinfo of folders are also restored.
+
+4) ADD: {Console} Added info about current path in the command-line box.
+
+5) FIX: {Console} Construction of the command-line of the unzip-dialog
+ box fixed.
+
+
+
+First beta release 06.June.1998
+-----------------------------
+
+no history.
+Just to many code was neccessary to build the first mac-port.
+
+
+Start of the port MacZip
+February 1998
+
+
+--------------------------------------------------------------------------------
+Legende:
+
+FIX: fixes a bug
+CHG: inform about changed items.
+ADD: added feature
+RMV: removed Item
+
+{Unzip} -> only related to the Unzip-module
+{Zip} -> only related to the Zip-module
+ These are just libraries and are linked into the console-app.
+
+{Console} -> only related to the Userinterface (not SIOUX)
+ MacOS has no tool like a command-line. So it's neccessary
+ to write wrapper around the command-line tools.
+
+
+
+
+Dirk Haase
diff --git a/macos/README.TXT b/macos/README.TXT
new file mode 100644
index 0000000..839658d
--- /dev/null
+++ b/macos/README.TXT
@@ -0,0 +1,569 @@
+A free Macintosh Port of Info-ZIP's
+Zip and UnZip
+By Dirk Haase, d_haase@sitec.net
+Home page: www.sitec.net/maczip
+Mirror page:
+www.haase-online.de/dirk/maczip
+================================
+
+
+
+Abstract:
+---------
+MacZip is a cross-platform compatible tool that includes
+both Zip (for compression) and UnZip (for extraction).
+
+Zip is a compression and file packaging utility for Unix,
+VMS, MSDOS, OS/2, Windows 9x, Windows NT, Atari, Macintosh,
+Amiga, Acorn RISC OS, and other systems.
+
+UnZip unpacks zip archives. The Zip and UnZip programs can
+process archives produced by PKZIP, and PKZIP and PKUNZIP
+can work with archives produced by zip. Zip version 2.2 is
+compatible with PKZIP 2.04.
+
+If you are new to MacZip please read first the file
+"ReadMe.1st".
+
+
+
+License:
+--------
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in unzip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+
+
+
+Requirements
+------------
+MacZip requires at least System 7 and a Macintosh with a
+minimum of a Motorola 68020 or PowerPC 601 processor. Other
+configurations may work but it is not tested at all.
+
+The application is distributed as a fat binary with both
+regular 68K and native PowerPC versions included.
+
+
+
+Installation
+------------
+Move the executable(s) somewhere--for example, drag it (or
+them) to your Applications folder. For easy access, make an
+alias in the Launcher Control Panel or directly on your
+desktop. The GUI is very simple. It was not my intention to
+make a full-blown GUI, however I think it is comfortable
+enough to use it as regular tool.
+
+This port supports also Apple-event. So you can install it
+in your WWW-Browser as a helper app.
+
+For more Info about the contents of this package, take a
+look into the "macos/Contents" (or :macos:Contents) file.
+Some notes on how to rebuild the Macintosh applications can
+be found in INSTALL.
+
+
+
+Usage:
+------
+
+Basically there are four ways to start MacZip:
+
+a) Drag'n Drop
+b) using the Dialog box (Menu: File -> Zip/Unzip):
+
+Please read the file "ReadMe.1st"
+for the description of the items a and b.
+
+c) Using the Command line (Menu: File->Command Line):
+ The Zip & UnZip tools are command line tools. So the
+ behavior is exactly the same like the Zip & UnZip tools on
+ Unix or Windows/DOS. This means, if you want to zip some
+ files, you have to write a command line like this: "zip
+ [switches] path_to_zip_archive path_to_files_folders"
+
+ - Go to "File", select "Command Line" and the
+ "MacZip Entry box" Dialog Box appears.
+
+ An example:
+
+ a: your zip may be created at
+ Macintosh HD:applications:archive.zip
+
+ b: your files may be found at
+ Macintosh HD:somewhere:my_folder_to_archive:*
+
+ Note: At the end of the path there must be a filename or
+ a wild card !
+ (see Footnotes: 1 wild card, 2 Mac path names)
+
+ So the command line should look like (one line!):
+
+ zip "Macintosh HD:applications:archive.zip" "Macintosh HD:somewhere:my_folder_to_archive:*"
+
+ - Click on "Enter" to start the task.
+
+ Since you can not set a default folder you have to enter
+ always a full qualified path names. Full-qualified path
+ names are path names including the Volume name ! (see
+ Footnote: 2 Mac path names)
+
+
+
+d) Using Applescript:
+
+There is only one additional event defined: "do_cmd". You
+can enter every valid command line. The first word must be
+"zip" or "unzip" to select the action (compress or
+extraction).
+
+See sample Applescript:
+
+ tell application "MacZip (PPC)"
+ activate
+ with timeout of 90000 seconds
+ do_cmd "zip -rjjN Volume:archive \"My Volume:*\" "
+ end timeout
+ end tell
+
+This script opens MacZip, brings it to the foreground on the
+Mac, starts the zip action with the command line: zip -rjjN
+Volume:archive "My Volume:*" .
+
+
+A short introduction is also available online:
+http://www.sitec.net/maczip/How-To-Do/
+
+It's possible to stop the run of Zip/Unzip with the well
+known shortcut [Command] + [.].
+
+
+---------------------------------------------------------------------------
+
+There are some Mac-specific switches available.
+Zip Module:
+ -df [MacOS] Include only data-fork of files zipped into
+ the archive. Good for exporting files to foreign
+ operating-systems. Resource-forks will be ignored
+ at all.
+
+ -jj [MacOS] record Fullpath (+ Volname). The complete
+ path including volume will be stored. By default
+ the relative path will be stored.
+
+ -S [MSDOS, OS/2, WIN32 and ATARI] Include system and
+ hidden files.
+ [MacOS] Includes finder invisible files, which are
+ ignored otherwise.
+
+Unzip Module:
+ -E [MacOS only] display contents of MacOS extra field
+ during restore operation.
+
+ -i [MacOS only] ignore filenames stored in MacOS extra
+ fields. Instead, the most compatible filename
+ stored in the generic part of the entry's header is
+ used.
+
+ -J [MacOS only] ignore MacOS extra fields. All Macin-
+ tosh specific info is skipped. Data-fork and
+ resource-fork are restored as separate files.
+
+
+Select [File]->[Get Help on Zip/Unzip] for a complete list
+of switches.
+
+
+
+Limitations / Problems:
+-----------------------
+
+ - Aliases are not supported. I tried, but I got broken
+ aliases. This port will silently ignore all aliases.
+ It's on my to-do list for future releases.
+
+ - Zip needs much memory to compress many files: You may need
+ to increase the 'Preferred Size' in 'Get Info'. Values of 12
+ Megabytes or more are possible
+
+ - Unzip needs about 500 Kbytes of memory to unzip no matter
+ how many files were compressed and expanded.
+
+ - and finally one big macintosh-related problem:
+ This port has one weak point: It's based on path names.
+ As you may be already know: Path names are not unique on a Mac !
+ The main reason is that an attempt to implement support exact
+ saving of the MacOS specific internal file structures would
+ require a throughout rewrite of major parts of shared code,
+ probably sacrifying compatibility with other systems. I have
+ no solution at the moment. The port will just warn you if you
+ try zip from / to a volume which has a duplicate name.
+ MacZip has problems to find the archive or the files. My
+ (Big) recommendation: Name all your volumes with a unique
+ name and MacZip will run without any problem.
+
+
+Known Bugs:
+
+ - crypted files in a zip archive are sometimes corrupt:
+ I get an error message: invalid compressed data to inflate.
+ Appearance of this error is purely be chance: I did a small
+ test: Unzipping an archive containing 3589 files 56 files
+ fails to unzip, so about 1.5%. Root cause is completely
+ unclear to me :(
+
+I strongly recommend to test your archive (e.g. unzip -t archive).
+
+
+
+
+
+Zip Programs / Macintosh Extra-Data:
+-----------------------------------------
+A brief overview:
+Currently, as far as I know, there are 6 Zip programs
+available for the Macintosh platform. These programs build
+(of course) different variants of Zip files:
+
+ - Info-ZIP's first Port of Zip. Ported by Johnny Lee
+ This port is rather outdated and no longer supported (since 1992).
+ 68K only. Only minimal Mac-info is stored
+ (Creator/Type, Finder attributes). Creator/Type: '????' / '????'
+ Until year 1998, only UnZip 5.32 survived.
+
+ - ZipIt by Tom Brown. This is Shareware and still supported I think.
+ ZipIt has a nice GUI, but I found it can't handle large Zip files
+ quite well. ZipIt compresses Macintosh files using the Mac Binary
+ format. So, transferring files to other platforms is not so easy.
+ Only minimal Mac-info is stored (Creator/Type, Finder attributes).
+ Mac filenames are changed to a most compatible filename.
+ Creator/Type: 'ZIP ' / 'ZIP '
+
+ - PKZIP/mac v2.03/210d. This is Shareware.
+ This Zip implementation for the Mac can be found on ASI's web site
+ (http://www.asizip.com/products/products.htm). The name of this
+ program is misleading, it is NOT a product from PKWARE. ASI's last
+ release version is v2.03, and they also offer a newer beta version
+ PKZIP/mac 210d. But even the Beta version is rather outdated (1995).
+ Only minimal Mac-info is stored (Creator/Type, Finder attributes).
+ The Zipfile format looks like incompatible to other platforms.
+ (More details about the compatibility issue can be found in
+ proginfo/3rdparty.bug!). Type: 'PKz1'
+ Mac filenames are restored without any change.
+
+ - Aladdin DropZip 1999, This is Shareware. Aladdin chose
+ the format of ZipIt. Therefore, it has the some drawbacks
+ like ZipIt.
+ Creator/Type: 'SITx' / 'ZIP '
+
+ - SmartZip 1.0 1999 - by Marco Bambini Vampire Software.
+ This is Shareware. SmartZip compresses Macintosh files using the
+ Mac Binary. Therefore, it has the same drawbacks like ZipIt.
+ Creator/Type: 'dZIP' / 'ZIP '
+
+and finally:
+ - Info-ZIP's latest Port of Zip. MacZip 1.0. Ported by me :-)
+ It is supported (of course) and up to date. Full set of macintosh
+ info is stored: Creator/Type, Finder attributes, Finder comments,
+ MacOS 8.0 Folder settings, Icon/Folder Positions ...
+ Mac filenames are restored without any change.
+ Creator/Type: 'IZip' / 'ZIP '
+
+
+Compatibility of my port; Extraction:
+ - Archives from Info-ZIP's first port (by Johnny Lee) are
+ still compatible.
+ - Extraction of ZipIt archives is supported. This support
+ is not complete: Filenames are correct but Directory names
+ are sometimes mangled to a DOS compatible form. Segmented
+ archives are not supported.
+ - PKZiP/mac archive files are extracted without resource-forks
+ and without any Finder info. I have no information about
+ that zip format.
+
+Compatibility of my port; Compression:
+ - My port supports only the new Info-ZIP format (introduced
+ with this port). Therefore archives created by MacZip 1.0
+ (March 1999) must be extracted with this version or later
+ releases of Info-ZIP's UnZip to restore the complete set of
+ Macintosh attributes.
+
+Note: This port is complete unrelated to the shareware ZipIt.
+Even more, handling of special Macintosh attributes is
+incompatible with ZipIt. This port (MacZip) may be used to
+extract archives created by ZipIt, but make sure that you
+get the result as you expected.
+
+
+
+Macintosh Files; File Forks:
+----------------------------
+
+All Macintosh files comprise two forks, known as the data
+fork and the resource fork. Unlike the bytes stored in the
+resource fork, the bytes in the data fork do not have to
+exhibit any particular internal structure. The application
+is responsible for interpreting the bytes in the data fork
+in whatever manner is appropriate. The bytes in the resource
+fork usually have a defined internal structure and contain
+data object like menus, dialog boxes, icons and pictures.
+Although all Macintosh files contain both a data fork and a
+resource fork, one or both of these forks may be empty.
+
+MacZip stores data-forks and resource-forks separately. The
+Zipfile format does not allow to store two archive entries
+using exactly the same name. My solution is to modify the
+Path name of the resource-fork. All resource-fork names are
+prepended with a leading special directory named
+"XtraStuf.mac". So, when extracting on a Mac, you should
+never see this directory "XtraStuf.mac" on your *disk*.
+
+On all foreign systems that support directories in filenames
+(e.g.: OS/2, Unix, DOS/Windows, VMS) you will get a
+directory "XtraStuf.mac" when extracting MacZip archives.
+You can delete the complete directory "XtraStuf.mac" since
+Mac resources do not make much sense outside the MacOS
+world.
+
+
+
+Text encoding; Charsets of the Filenames:
+-----------------------------------------
+
+The following information is only important if you plan to
+transfer archives across different platforms/language systems:
+
+A typical Zip archive does not support different charsets.
+All filenames stored in the public area (= accessible by
+foreign systems other than MacOS) must be coded in the
+charset ISO-8859-1 (CP1252 in the Microsoft Windows world)
+or CP850 (DOSLatin1). The latter should only be used by Zip
+programs that mark the archive entries as "created under
+DOS". Apart from Macs, the commonly used platforms either
+support ISO-8859-1 directly, or are compatible with it. To
+achieve maximum compatibility, MacZip convert filenames from
+the Mac OS Roman character set to ISO-8859-1 and vice versa.
+But not every char of the charset MacRoman has their
+equivalent in ISO-8859-1. To make the mapping in most cases
+possible, I chose most similar chars or at least the MIDDLE
+DOT.
+
+Mac OS Roman character set is used for at least the
+following Mac OS localizations: U.S., British, Canadian
+French, French, Swiss French, German, Swiss German, Italian,
+Swiss Italian, Dutch, Swedish, Norwegian, Danish, Finnish,
+Spanish, Catalan, Portuguese, Brazilian, and the default
+International system.
+
+In all Mac OS encodings, character codes 0x00-0x7F are
+identical to ASCII, except that
+ - in Mac OS Japanese, yen sign replaces reverse solidus
+ - in Mac OS Arabic, Farsi, and Hebrew, some of the
+ punctuation in this range is treated as having strong
+ left-right directionality, although the corresponding
+ Unicode characters have neutral directionality
+So, for best compatibility, confine filenames to the standard
+7-bit ASCII character set.
+
+If you generate a filename list of your archive (unzip -l),
+you will see the converted filenames. Your can also extract
+the archive with the switch '-i' (= ignore mac filenames),
+and test your result.
+
+This MacZip port uses its own filename stored in the
+archive. At the moment, the filename will be not converted.
+However, I'm planning to add support for Unicode.
+
+Currently, the following Mac OS encodings are NOT supported:
+Japanese, ChineseTrad, Korean, Arabic, Hebrew, Greek,
+Cyrillic, Devanagari, Gurmukhi, Gujarati, Oriya, Bengali,
+Tamil, Telugu Kannada, Malayalam, Sinhalese, Burmese, Khmer,
+Thai, Laotian, Georgian, Armenian, ChineseSimp, Tibetan,
+Mongolian, Ethiopic, Vietnamese, ExtArabic and finally:
+Symbol - this is the encoding for the font named "Symbol".
+Dingbats - this is the encoding for the font named "Zapf Dingbats".
+If you extract an archive coded with one of these
+charsets you will probably get filenames with funny
+characters.
+
+These problems apply only to filenames and NOT to the file
+content.
+of course: The content of the files will NEVER be converted !!
+
+
+
+File-/Creator Type:
+-------------
+
+This port uses the creator type 'IZip' and it is registered
+at Apple (since 08. March 1998). File types can not be
+registered any more. This port uses 'ZIP ' for Zip archive
+files. The creator 'IZip' type should be used for all future
+versions of MacZip.
+
+
+
+Hints for proper restoration of file-time stamps:
+-------------------------------------------------
+
+UnZip requires the host computer to have proper time zone
+information in order to handle certain tasks correctly (see
+unzip.txt). To set the time zone on the Macintosh, go to
+the Map Control Panel and enter the correct number of hours
+(and, in a few locales, minutes) offset from Universal
+Time/Greenwich Mean Time. For example, the US Pacific time
+zone is -8 hours from UTC/GMT during standard (winter) time
+and -7 hours from UTC/GMT during Daylight Savings Time. The
+US Eastern time zone is -5 hours during the winter and -4
+hours during the summer.
+
+Discussion of Daylight Savings Time
+-----------------------------------
+The setting in the Date & Time control panel for Daylight
+Savings time is a universal setting. That is, it assumes
+everybody in the world is observing Daylight Savings time
+when its check box is selected.
+
+If other areas of the world are not observing Daylight
+Savings time when the check box is selected in the Date &
+Time control panel, then the Map control panel will be off
+by an hour for all areas that are not recognizing Daylight
+Savings time.
+
+Conversely, if you set the Map control panel to an area that
+does not observe Daylight Savings time and deselect/uncheck
+the check box for Daylight Savings time in the Date & Time
+control panel, then time in all areas celebrating Daylight
+Savings time will be off by an hour in the Map control
+panel.
+
+Example:
+ In the case of Hawaiians, sometimes they are three hours
+ behind Pacific Standard Time (PST) and sometimes two hours
+ behind Pacific Daylight Time (PDT). The Map control panel
+ can only calculate differences between time zones relative
+ to Greenwich Mean Time (GMT). Hawaii will always show up as
+ three hours past the Pacific time zone and five hours past
+ the Central time zone.
+
+ When Hawaiians are not observing Daylight Savings time, but
+ the rest of the country is, there is no combination of
+ settings in Map and Date & Time control panels which will
+ enable you to display Hawaiian local time correctly AND
+ concurrently display the correct time in other places that
+ do observe Daylight Savings time.
+
+ The knowledge about which countries observe Daylight Savings
+ time and which do not is not built into the Map control
+ panel, so it does not allow for such a complex calculation.
+
+ This same situation also occurs in other parts of the world
+ besides Hawaii. Phoenix, Arizona is an example of an area of
+ the U.S. which also does not observe Daylight Savings time.
+
+Conclusion:
+MacZip only knows the GMT and DST offsets of the
+current time, not for the time in question.
+
+
+Projects & Packages:
+--------------------
+
+A Note to version numbers: Version of MacZip is currently
+1.06 and is based on the zip code version 2.3 and unzip code
+version 5.42. See About Box for current version and compiler
+build date.
+
+Because of the amount of sources I splitted this port into
+several projects. See http://www.sitec.net/maczip for
+updates.
+
+- core source parts:
+ unzxxx.zip
+ zipxxx.zip
+ These archives contains the main parts of the port. You can
+ build libraries and a standalone App with Metrowerks
+ standard console SIOUX. They contain only sources, no
+ executables. These archives are exact copies of the standard
+ Info-ZIP source distributions; they were only repackaged
+ under MacOS using MacZip, with one minor addition: For those
+ files that are stored in BinHex'ed format in the Info-ZIP
+ reference source archives, unpacked version that are ready
+ for use have been added.
+
+- additional source part:
+ MacZipxxx.zip: contains all the GUI stuff and the project
+ files to build the main-app. Only sources of the GUI, no
+ zip or unzip code. To build MacZip successfully you will
+ need to also download the zip and unzip packages.
+
+- executables:
+ MacZipxxxnc.hqx: contains only executables and 'README.TXT',
+ This version is without en-/decryption support !
+ MacZipxxxc.hqx: contains only executables and 'README.TXT',
+ This version supports en-/decryption !
+
+- encryption sources:
+ zcryptxx.zip: To build crypt versions of MacZip.
+ download from ftp://ftp.icce.rug.nl/infozip/ (and subdirectories)
+
+- documentation:
+ MacZipDocu.zip: contains some further docus about the algorithm,
+ limits, Info-ZIP's appnote and a How-to-do Webpage.
+
+
+Credits:
+--------
+
+Macstuff.c and recurse.c: All the functions are from More Files.
+More Files fixes many of the broken or underfunctional parts of
+the file system. Thanks to Jim Luther. (see morefiles.doc)
+
+
+
+
+---------------------------------------------------------------------------
+Footnotes:
+
+1. wild card:
+ The '*' is a wild card and means 'all files'
+ Just in case you don't know wild cards:
+ '*' is a place holder for any character.
+ e.g.:
+ "this*" matches with "this_file" or "this_textfile" but it
+ doesn't match with "only_this_file" or "first_this_textfile"
+ "*this*" matches with "this_file" or "this_textfile" AND
+ matches with "only_this_file" or "first_this_textfile"
+
+
+2. Mac pathnames:
+The following characteristics of Macintosh pathnames should
+be noted:
+
+ A full pathname never begins with a colon, but must contain
+ at least one colon.
+ A partial pathname always begins with a colon separator except
+ in the case where the file partial pathname is a simple file or
+ directory name.
+ Single trailing separator colons in full or partial pathnames
+ are ignored except in the case of full pathnames to volumes.
+ In full pathnames to volumes, the trailing separator colon is
+ required.
+ Consecutive separator colons can be used to ascend a level
+ from a directory to its parent directory. Two consecutive
+ separator colons will ascend one level, three consecutive
+ separator colons will ascend two levels, and so on. Ascending
+ can only occur from a directory; not a file.
+
+
+
+
+
+---------------------------------------------------------------------------
+
+Dirk Haase
+==========
diff --git a/macos/ZipLib.h b/macos/ZipLib.h
new file mode 100644
index 0000000..e3dacf3
--- /dev/null
+++ b/macos/ZipLib.h
@@ -0,0 +1,166 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ ZipLib.h
+
+ This header-files is global to the project ZipLib.
+
+ ---------------------------------------------------------------------------*/
+
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+#define MACOS
+#define MACZIP
+
+#define OLDROUTINENAMES 0 /* use new function names only */
+#define OLDROUTINELOCATIONS 0 /* use new headerlocations only */
+#define SystemSevenOrLater 1 /* Runs only on System 7.0 or later */
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c) */
+#undef getc
+#undef getchar
+#undef putchar
+#undef putc
+
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+#define NAME_MAX 1024
+
+
+/*****************************************************************************/
+/* Includes standard headers */
+/*****************************************************************************/
+#include <ansi_prefix.mac.h>
+#include <stdio.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Aliases.h>
+#include <Resources.h>
+#include <Gestalt.h>
+#include <Traps.h>
+#include <Processes.h>
+#include <MacWindows.h>
+
+
+/* Many things are different for mac-users, so we need
+ special mac functions :-) */
+int Zmacstat (const char *path, struct stat *buf);
+#define stat(path, bufPtr) Zmacstat(path, bufPtr)
+#define lstat(path, bufPtr) Zmacstat(path, bufPtr)
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+
+
+
+/*
+#define MAC_DEBUG 1
+#define DEBUG 1
+ */
+
+
+#ifdef MAC_DEBUG
+#define LOG_DEBUG 7 /* debug-level messages */
+int Print2Syslog(UInt8 priority, const char *format, ...);
+#include <ctype.h>
+
+
+#define Notify(msg) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG, "%s (file: %s line: %d)", \
+ msg, __FILE__, __LINE__); \
+ }
+
+
+
+
+#define Assert_it(cond,msg,kind) \
+ { \
+ if (!(cond)) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG,"%s failed: [%s] cond: [%s] (file: %s line: %d)", \
+ kind, msg, #cond, __FILE__, __LINE__); \
+ } \
+ }
+
+
+
+
+
+#define AssertBool(b,msg) Assert_it (((b) == TRUE) || ((b) == FALSE),(msg),("AssertBool "))
+
+
+
+#define AssertStr(s,msg) \
+ { \
+ int s_i = 0; \
+ Assert_it ((s),(msg),("1. AssertStr ")); \
+ while ((s)[s_i]) { \
+ Assert_it ((!iscntrl((s)[s_i]) || ((s)[s_i] == 0x0A) || \
+ ((s)[s_i] == 0x0D)),(s),("2. AssertStr ")); \
+ s_i++; \
+ } \
+ }
+
+
+
+#define AssertTime(t,msg) Assert_it (((t).tm_sec >= 0) && ((t).tm_sec < 62) && \
+ ((t).tm_min >= 0) && ((t).tm_min < 60) && \
+ ((t).tm_hour >= 0) && ((t).tm_hour < 24) && \
+ ((t).tm_mday >= 1) && ((t).tm_mday < 32) && \
+ ((t).tm_mon >= 0) && ((t).tm_mon < 12) && \
+ ((t).tm_wday >= 0) && ((t).tm_wday < 7) && \
+ ((t).tm_yday >= 0) && ((t).tm_yday < 366),(msg),("AssertStr "))
+
+
+
+#define AssertIntRange(myvalue,minimum,maximum, msg) Assert_it ( \
+ ((myvalue) >= (minimum)) && ((myvalue) <= (maximum)), msg,("AssertIntRange "))
+
+
+
+
+#define AssertStrNoOverlap(str1,str2,msg) \
+ { \
+ long s_i = 0; \
+ AssertStr((str1),(msg)) \
+ AssertStr((str2),(msg)) \
+ if ((str1) < (str2)) \
+ { \
+ s_i = strlen((str2)); \
+ Assert_it ( (((str1) + s_i) < (str2)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ else \
+ { \
+ s_i = strlen((str1)); \
+ Assert_it ( (((str2) + s_i) < (str1)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ } \
+
+
+
+
+#else
+#define Assert_it(cond,msg,kind)
+#define AssertBool(b,msg)
+#define AssertStr(s,msg)
+#define AssertTime(t,msg)
+#define AssertIntRange(myvalue,minimum,maximum,msg)
+#define AssertStrNoOverlap(str1,str2,msg)
+#endif
+
diff --git a/macos/ZipSx.h b/macos/ZipSx.h
new file mode 100644
index 0000000..d2b9ae8
--- /dev/null
+++ b/macos/ZipSx.h
@@ -0,0 +1,167 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ ZipSx.h
+
+ This header-files is global to the project ZipSioux.
+
+ ---------------------------------------------------------------------------*/
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+#define MACOS
+#define USE_SIOUX
+#define MACZIP
+
+#define OLDROUTINENAMES 0 /* use new function names only */
+#define OLDROUTINELOCATIONS 0 /* use new headerlocations only */
+#define SystemSevenOrLater 1 /* Runs only on System 7.0 or later */
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c) */
+#undef getc
+#undef getchar
+#undef putchar
+
+#ifndef ZCONST
+# define ZCONST const
+#endif
+
+#define NAME_MAX 1024
+
+
+/*****************************************************************************/
+/* Includes standard headers */
+/*****************************************************************************/
+#include <ansi_prefix.mac.h>
+#include <stdio.h>
+#include <TextUtils.h>
+#include <Folders.h>
+#include <Aliases.h>
+#include <Resources.h>
+#include <Gestalt.h>
+#include <Traps.h>
+#include <Processes.h>
+#include <MacWindows.h>
+
+
+/* Many things are different for mac-users, so we need
+ special mac functions :-) */
+int Zmacstat (const char *path, struct stat *buf);
+#define stat(path, bufPtr) Zmacstat(path, bufPtr)
+#define lstat(path, bufPtr) Zmacstat(path, bufPtr)
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+
+
+
+/*
+#define MAC_DEBUG 1
+ */
+
+
+
+
+
+
+#ifdef MAC_DEBUG
+#define LOG_DEBUG 7 /* debug-level messages */
+int Print2Syslog(UInt8 priority, const char *format, ...);
+#include <ctype.h>
+
+
+#define Notify(msg) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG, "%s (file: %s line: %d)", \
+ msg, __FILE__, __LINE__); \
+ }
+
+
+
+
+#define Assert_it(cond,msg,kind) \
+ { \
+ if (!(cond)) \
+ { \
+ (void)Print2Syslog(LOG_DEBUG,"%s failed: [%s] cond: [%s] (file: %s line: %d)", \
+ kind, msg, #cond, __FILE__, __LINE__); \
+ } \
+ }
+
+
+
+
+#define AssertBool(b,msg) Assert_it (((b) == TRUE) || ((b) == FALSE),(msg),("AssertBool "))
+
+
+
+#define AssertStr(s,msg) \
+ { \
+ int s_i = 0; \
+ Assert_it ((s),(msg),("1. AssertStr ")); \
+ while ((s)[s_i]) { \
+ Assert_it ((!iscntrl((s)[s_i]) || ((s)[s_i] == 0x0A) || \
+ ((s)[s_i] == 0x0D)),(s),("2. AssertStr ")); \
+ s_i++; \
+ } \
+ }
+
+
+
+#define AssertTime(t,msg) Assert_it (((t).tm_sec >= 0) && ((t).tm_sec < 62) && \
+ ((t).tm_min >= 0) && ((t).tm_min < 60) && \
+ ((t).tm_hour >= 0) && ((t).tm_hour < 24) && \
+ ((t).tm_mday >= 1) && ((t).tm_mday < 32) && \
+ ((t).tm_mon >= 0) && ((t).tm_mon < 12) && \
+ ((t).tm_wday >= 0) && ((t).tm_wday < 7) && \
+ ((t).tm_yday >= 0) && ((t).tm_yday < 366),(msg),("AssertStr "))
+
+
+
+#define AssertIntRange(myvalue,minimum,maximum, msg) Assert_it ( \
+ ((myvalue) >= (minimum)) && ((myvalue) <= (maximum)), msg,("AssertIntRange "))
+
+
+
+
+#define AssertStrNoOverlap(str1,str2,msg) \
+ { \
+ long s_i = 0; \
+ AssertStr((str1),(msg)) \
+ AssertStr((str2),(msg)) \
+ if ((str1) < (str2)) \
+ { \
+ s_i = strlen((str2)); \
+ Assert_it ( (((str1) + s_i) < (str2)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ else \
+ { \
+ s_i = strlen((str1)); \
+ Assert_it ( (((str2) + s_i) < (str1)),(msg),("AssertStrNoOverlap ")); \
+ } \
+ } \
+
+
+
+
+#else
+#define Assert_it(cond,msg,kind)
+#define AssertBool(b,msg)
+#define AssertStr(s,msg)
+#define AssertTime(t,msg)
+#define AssertIntRange(myvalue,minimum,maximum,msg)
+#define AssertStrNoOverlap(str1,str2,msg)
+#endif
+
diff --git a/macos/ZpPrj.hqx b/macos/ZpPrj.hqx
new file mode 100644
index 0000000..5bb3da0
--- /dev/null
+++ b/macos/ZpPrj.hqx
@@ -0,0 +1,455 @@
+(This file must be converted with BinHex 4.0)
+:#9T`8(*U,R0TG!"6594%8dP8)3#3"&66!*!%Ip96593K!!%!!&66FNaKG3)!N!3
+@!*!$$39DF&"bDJ#3!aEf1!,VX93!6&MU!*!$J!#3"!,cIF3NA3#3'[q3"%e08(*
+$9dP&!3b[H&ZZXklEb3#3"3,E[3#3"P40!!$hQ!#3"L8D"RMDS*NlIS6ISVG-[(8
+R+hBY21RaEd$i`XJbN!"bQK8YHRN,mmTE("$HbP6f+lXeRq'lH*3I@AbbH%Ef3E+
+Yif3KHp54hE%@hq8Fj,%GAml1RLpN-E,i(GQARdH@0q0,K(GffT%p5)X[RVFF@D4
+BKrHBaXd@6VD,AXpZB5d!C#'6K@abQi`@mJ[Cj$MPC!8iDT2X[EaXE0rjRCHM[$`
+Ej#4Rp[RPjG6VcFj"ITHAR9DQepPe(-SAiAji1arZ(-5ApPP[lbMciLAdmP)if0m
+4Z#m[-q'q["cNPGI1p`,!!JLip@eQPi2X'farqH4p"**I)T!!,ckH3A`!+i#AjfI
+6V9BMbl,P@GDh0P[fhKZcCArkf5`lka2F0rFYkb28qpDfD[R@DP(8@d9PSQMYcUH
+l#l&K+CqqV@b6b'8EXQaE[)pm16Za$2kVE&Ajrhr50p-icq)mQh-k-9rKr#ThirR
+rPjaIiecK!m`jJh-@jcQFFcJAF-lMl1)dliLFcVQ"F`IR*Xk0R"GcEZCFalQ0mbl
+1fcR[i$c+q@,1jh$HcAQBm`MR4C`2FElF9MERGNj6amLPR&XjIj*c$@F2jmXiAm$
+j*XlAFlk"mi@FrjhcMcNrbIN*cSpcISVc6cMr,HHpR$r0q3#eRXTrcYrLI$mR'2-
+,R+rKI"hRIH3Bb9R2#IC-iM3GT%lK(-,CcQPUVdlJ(-lCbMQ1Xi(6p)BkME10Xj%
+c+PDCdr561TN6d2S-jjpa'Lb,I*!!mcpbrKVR@cNIiIaPcSFjIjhc9cKrNI2GR'r
+Mr#$RKcMIc[R[1Aq9mbfFlq6m*Fi,1*Ga,Z@mKI0IFGl*#5!Dh)bmK[09R,GaAX,
+j"jarb2RI1(q(FaIR4cJrb[Nqc[Gb(Z#mQA-Ijhl1Jp4a$2rr-qGri@idr`pa2Tr
+c#j`c1@GcRXXjPh-Kjha1dcX4X#IbK!KDTSmLi&#%2SXmRI-QcLq9Z!9QHAK&RJp
+`lZ(FbhNGjrfFi0ZA1@rJr$6RRh*qP[1jR(r"H68Rb4GarLERAh1H6mK%r[mHjqp
+bAXYTHM*b(ZI2F2iXj`61[`QF)`)'4&l"HCccMCcrM[2R16r(qAR1Rq!dI4jj2HF
+pR$r&qmEbrbAmTmDmG5@R`BL)@2XZiLEchf"#j+Fj$@j%`)h)-cJ0YN6%B*!!fZ"
+0"!b*Q-YJ5Z6l13f@4"l,H6RRrq,m"ZHMR,r0#FVclQpbISXh8X0[Fcl'q6MRDNj
+kp$ZFEqEm1FlAFVk)df"Bj'l1*Cc,1EXjRmhj4Fi(1@rN[*lcMcMr0HFV1DrKT2p
+IcEQEmcpaIScc2h$Zj2`0c[G`AX&j+HFl*#EQK*KF5AfSiiFjrbYhe2BUcZFYQ8#
+8`"SqHK"mJ1I3kr3C28Brd%[d&(J&2Y#Ep#9p$1pa'!D(S)I"!2UBIUI2k&ekQ$k
+NTkNhA)PD1m`$$m!AqJL1"DHLhq&FB#FB#Zm#3m%Rq0Hr%%46EGlDqbRHVF#K%H!
+jCH(Hi#JG!5E6*4lH8SZ90Sij`3pl6lJjll@6MSXbZAq0&J$qBllBSmf01Ffr4[l
+C`lkV[XcL4ASG'Uq6pdGP+lLTLlHfZ[CGhY-)T@1p"c3qUpkHR1ZA["4,,hRFkea
+YBX@*hcX-dG"#+9Im%9i"mj8`IdC`pR"ZifcRl1$Xj"c&1CTc$1GBcR'FNcQl1'G
+`VZ*FcEQ@Fb2R*XiYR$GclZHmKI0@cJ1F"cN2F4lQ[)hc+1IYR(G`2Src(Xjl19r
+!q41F@f-(QGk,(-FjM(-iCbXRM$VH@aj#JTLJCcJ!8S+3!+!HU!JLJMDJ)qJ*@MT
+N"$e"8C!!&83&)8&+Kk"K"%KC3E!i)0$PJemF2ha%-$h8ZV&k4A@S8HedmNlrlUV
+k4r+lI'5L-VEe@@SUj"`H)5q"0Af[ML&D&MAMJ*Q(BUqXb8H5K0BVJkB$kF&FTK+
+E1,G`MZBF`cQ@Fa,R+-j1cKXiEq5mQA-NjdE1rCbhF0l+HC!!Xiec'fF2Cc[R#-j
+9R$GacZ$FblQDFbhR2Xl*R)FjEq-mbRNAjpfFcq0m2ZFpR&XjQcLE1BG`YR!1j4`
+QQE%pEq+fM@mD("[Z(pkQ6*ArB1m@(2NMrbrTZlE[a'9UA)NZ-1G*h2#q2MlNie#
+FlAKr`'(q0ph`MVp(96SX3dYqJ(B)h'F3ShNX,hEQPI(CraA+,q4E26%a@U*4G2h
+S*GZQpp4VDZqA6Ni-IBGlai[LEVbSIX8L6)&*mGBRF[Cp'P`'R8-#ZKG'%!T3Na#
+3!-m)-8N-L68ZIi`Zd6(CV9@'cMfh-Y4UGPU0[2,dLj`Tq,X[KR+QI5p6KIl4ahY
+LPcQ1D'%LG1"lQRGkkX`5C4jc2[L!DZG,#8B,5U,`Fq[1G#3r8(Mci'9Ud,jSF#T
+ciQZmAjrirRI0jCeZYIacC+Q'iD#62CM9E%`2YX+JZLEVVGQjbYU*LD&c+[cadf`
+LhS-SY$AS24*%1!"B$AaU%FbHEZBiI&Le*&2dm*m[h!(MBQeX&DQ`Q-m4dY!$bD8
+kHP%6%rda"hqX)Y,(1*GLV%NarU3BRe1-mLR'G"6MGiV4*m@3!)"LY%a"B48MHSS
+40SAJU"bI-b0DLV%IaELIFKb+X6Xc5U8Bhe115CP42-9iN@)m66&kT4ME8S`!+ND
+`&'1!bP%MmhBlHQAHENIq6!ilBQEHEJF8c*[YH+'TL4e&-HqfSf(QcBaJ-HTRalI
+-QaR0XZ0rjXefp0#0fM&5apJFihD-d6&kamJGih@-",S41aQYXQ09M1SaQXGB%f0
+hCUc,MZFamX5i(102M-iaYZG'X%`IfUkLVScJ-8E&'"jMCi`p-N,'Q#)M9BcX-BV
+'Q"BMLBaU-CE)q"NMMibJ-IE)5"TMN!#-G$%qb@JJif#-"c++a@JM)f+-p6(ZaTJ
+KSh#-26)#akJG)cf-J$+'b"JAii#-CXPS(b0DGM63M36#+mfiD'a8e)cUfE&(4Kd
+CKh5MMSa1-LV*b#0MNk!-Sj!!M&'kN8P'*"Q9G118M&bD)4$'`aJTC265MR%bcZP
+'1aP9C066MABbqXIS'D10M!$+f+!Gph0MPS`&-QVTa[BB(@4-N4%h4J8CE@2Ncih
+9-3l(i)SE-Q%iaBfmqX-Q$+-`f-)J#i-SE[L%N8I'C"PjC'5@m8FcHQK(%4PcC%5
+6F6X'BaM6C151N8h'laK*C-54N6Y'(XfiR"fhBr5488I'm4LVBlb4F8Q898Bc'FY
+Nh*049XBecBLQ(FQ%Kc2UL6M+q#hFJh%l0j,,+#lMSCR"(KP@53lhm0'6rT!!Ma[
+UBD#(34i'HKMHBCL(34i'HK"a'44#hN"HmSGk'1Y&cf"FQ2N+aL@4LKMrCE5BN@,
+'N4QbB-5Bd@)h&X`i-#2'M!XMmM*kc2JK)kb-*6,HbYJK+J9ML)`I-YTS4LJ91+[
+!9`@q+["9JFF+r&AJV!*R&6LV`'N&,L[`9S(h#Xa9B+i#Fa@iVm"G"8G3F!F&eLZ
+iJS*$+,L&JPXSZ)@#@bK`AX%V&,a#`5Z8I)+4BS-IGPcBi!!MbBb1-Tl+q'Cb60[
+d$q2CGJcCi*%Ge6-iT-!K"3iTm%H"2`Vm8H#2!Rm8q+2!(`Aq+2$(MLFcrQS`5)&
+"#Ja5i)S#Ea4iSm!E4@mSX%%jSQQ`4i%j#Xa4p)d#Fa5BSm!I"HiSF%H"1`VF8H#
+1!RF8Z+-F$6DiSm!G"HiSF%H"1mUH-pLM`"d&lLK`4p'AM"`UqPf"!`SX925k!JF
+9Q+$!"!8Q+,"5JBm+E&$JJJ)A&,LJ`!-&(LM`3)%(#Ma3i)%#$a4iS-!$"4iSm%#
+"X3T-8'##!K-8H+$J&!T1SH!5#LkKY"8`A%2"+44F3X%I&0a!`8%82%,")a3m3X%
+M&$a#`5-82%,")a3m3X'R&(a+`DH8)r@')bNiNS+[+(Q5i5E+N@E$663pT1NK63p
+THNM6EjVHd[55TTFd[D6T58hrDAT+de1DRY,dP+DR0$fPk5G02fRk5G02'KcAm'%
+06dC@e["L63pVkUDTQkCZQVTTq,1'2f[iS)C$DlLcKQYV1,D'3fXiY)C$DlLfT[i
+D,00`F!fHDALeKMYUZ,@'-fViYBCIDrLeKPpVq,@'[fTiVBD6DMLPKXYUH+@'9fT
+iTBE[DRL`"PmeZ+[Kq"UFe'#N"L-eA&1$NaUFe25LTKFe[DMT3Dd8ErTF`fXe[Dl
+TG3d@D$"!dr1DRYId[!BM0&a4Jp%DM0$JY!B(0"aCJ`-DRUc"!Jd@D,"!Jh%Dr02
+JP!EV0"LSiG%D204`D3f(eR"S$3CUF&1$QaVFe'#3!!Er0IL[`Am09pC`!#d(-"U
+!JQmVH,L#0bXd!S8fS1$IL[STDU%F#6HDJD)HL[FUhUTiUq+YL[j8p*ULca4pT1J
+K43mTHNJjGXriY(Q[3RG3p)b#RbZiX,,Z"XXdZ+2",JfQDEL!KJYSY!X0(p"`!3e
+Id2!%$5I3F!)0*p$`#-dl0*a&`b-dr%H$[aVqSm&RMHDK`9)0(QY`@S2A'Pc@B,N
+'bc9BVZ&''McAe&C6Fdep0(LZ`A-0RQX`A-060(a,`m-d2%a66`dAdh!a$5jVF&Q
+$baTFe[")$Br8p)Q'#fPiNSCVDMLQKYGSZ*''-fNiU+Eq'JkRiD!D(UIK8jUHdh!
+R66pU1*H'FfNiPiCcDAL@KQGTH*D'@fRk9F1[0$fVk9P0VfUiPSCVDEL@KQYT1+k
+'(fTiSBB6D[T3``Ze[*!!mAZM%5Pd(iAZSp!8&0U43[qaNaMS)%CV8'J-QJ!0RpE
+`E!hre["[$Ir@m'm0lpE`EJh[e["Y$Gr@m'd0hpEU*ZJ8B3GIH-fNB'1B3JRj'%8
+aRe@'`bJ'fdl93qCGKdIr(k0G&iF0[#%M-bGm-JqU9h[+JqSeiaYjr%&'P,'fP!I
+eE&M+JlTf@5p2X8P-&!VFXe-H9,V,8aj8[#Y6(T5qUe)He-#V8ai8`fY5(P6&De-
+H9-IV8Ki8h4Y6(Y6JQe)HP12l8Kl8cGHP2#LMVdTj8&6IP2+JVViQj8&jI8A+Jc,
+l`T3(pIDG[6c*-6!Ipe"iVdM[339qIXU$8[lbP!FerD'8"mApH-U$+[r6+3r+rBG
+5(Y6p$kBm6!$X6AQB%VJKj@'5i2U8KdQ$25N28`L[6hQB9(K$bX-Nd'G5(UDD4U8
+m6$f05hQBL*U8mM#jp2k8KmNUjfrAPiGTUkRIb12M+00CAFIbK"Kqp3Y@*5%[Rr2
+%D'*LHfYpqd1Q'%8rU[TPTCU9!ZrB&'H)J%d0cjQiHAcFqDRB&leNmjEJSQ'UecM
+CQLfQFbPHr@*FabPMeHRc*Y[jG(e(hFQek)D4d@'j&[q0Q2c#a@3MMkmhTaZc05I
+D'Q*m6rbr,IjI&Iq[MIpAarm[@Ra(jh'GXKM83X+ha2rhaIpharmEirp0LqRE9p+
++ebL#f'+Ck)liId6m2b2qEer-fV*LI2YZEIKFj6VMre(arqMiIdcm2cEq(lIiL+%
+q!PP&aq$*mArABT+aChCf9BZm9TR'hl5,@R8pUE+P'BEVKm9m,ieYpS,irfL-Zcr
+H(iVr$mIr0mIrpmErqq2r@q,r@q2r!r(r`F9kk-F-ETSFU3"H4kT&[B5!ZXA`qZA
+"AU-ZTQk0riI(rif,Z4U@"am$Q`X(*[RI&2rEmX+B%cR9+L!QqAUp'"dpr(VhhhD
+Tq6pX-9IMiGF2MIq(a2mYLlQ'R,!jAd!C&4qcGAjq[ZpAGXmfpecHfH(mT08%'lH
+MKZq)!"i#`hK'VKNDAcqmTV*QrH$8)(phM!a0+BL'U(aQTLGV3*0flr!0CV`6RKD
+ki0la6eC+49ZBd)TjNY!!CKar%am6&-kZK6RZZZ9Mch%qRrR`k,*p'r84B-kl2PX
+jV[V,2,2PlqCM2YNce[6Q[CXDkY+HUZXC0R[cfUi,m$j`mpI-q60rcBFRJ*P)DG)
+I!4m#TNliQ1e[rGV0jF`imqpYfhGlCEd)4Q3ri%JrmrTf@S3lTLJk-KL00dmF1D0
+9*Q3fedk!N!#$'@ZQ2,KM*Ye-FYKm+19MXTHeR"p'(4lE,LHDm)H`8aIFiA(!c$G
+hq"G-D&3P8ma'-`1q`RPL2"-Q26Bl9DN)$i2*`IQ,qGY)KBHD'M&V5kpCc`J6BQI
+[D82QckGP0kiQMPR!b1Vjq6ZG'fAqRKPqFY"rdaR5CDD1qINC38KKKYEdE11ERB2
+%0i,CIZBBm@%i9e6dCP-Mj`C2'qC1lD`rZI%LB1DI1fScKrFaPiL2`0b!&(91$-d
+,MKpeeSZDF-Im2pi!h$(PJ%F!GbJRH!9`"kpF&0K"R6i@LhAm-(Gi3P`3H%5G1,0
+Nf6lEUNlI"r`%$"1Ydb-"A`(Lm(GBPYei0VQLBYCbqX2d@p4T('EVJ5`m$&C52p0
+,8AR"KF("*5T@@A`dG`K@6+"`"c)bZmmGRKV#DU*k5c$,cahH$!+j8AZ#(J35`8&
+QqlPMAKm"KMY`%NQ%1l`pQ2AR$Qm-XHfUelH$k4(Z!$*kKcZm+*J#!@EaD3#[Z+-
+(K-Nhk!H#4`"hH(2`GZl`bU$1h1&p)GTAJpL$K`"hH%hJ*F!GrK(i#A$(Zr%9i)i
+DibrJi"f0L$X`(FcKMNNZm*-lqJm["ZlJ%(JkF!F'iIR!(4J"4q#1hXBEJM[k$Bm
+)lZJ0F)-lkQM"hYcaCN3,lSM"1i)lH!EH%G`a@5&#C+2H+Ki6L4b[M`VBcKfq+8b
+kF)GR#Ah+(6iN6+a`KhF+lq)1la3Q6lM$"d@mS"VY-cJ#GhL,#-YXe,X$0BFlq)V
+-4$EU6m+%#(IiH9!Vl["6`EF#kX58UUHr4%k3!*2K"m-GrK,iaA#(PiF`Z5Ca6Ub
+QQm4FDXiGrK[icA!(IZ%l`adi!VrLMMk(Lh&(2m&aZ+2ZBTMEC)h!,ZjiJaK`0ZN
+PJcm0Gr3(rF8GILc`$ZlS$haVZ-0r"EcL$Jm8m*ml2%c`Xq%1(aCmEEM$Xi3q09q
+c&"C-jJjZK*m-Gr!aZ"Khm#+i*(IiPH!h`aeiL4m0Gr3"IMAFd3IieR!(VZ&I`af
+B!LC`4fq$eGc49rMCF%HYi92Fm@CmEEMM2A!ClZ$1q0a`"jE!EER$CiGBlP"&)$V
+F`A("(ql`Im%2KcY`'PmFl["h`4q(1caKm-RK$Zj)2jT[L2L"p`phm'&i!AId"pi
+rh)'le)3lZ!FFK$Y`'3mKlX![[)5iSmrKM0c4*h!dlRJRhN,Fi4-%$R"(Vq-*`Kf
+H0IJ,FBFR$I8hAiXF!VmKlZKMq$jhm!EmKlL$@q*$a"eiKKm4Gr!LhXXGh!1Zc4f
+B$Mjc"fk#4Gb"4hJ(F3F@L"V9BKhKGp`4!aIQ$Tk(pa"hq1R!hlQMcq#NjKZUPJ'
+qFBH4-jj%h+%hi%h%(AS*(NAF`62TFHlJBrJ6F3F[`UH)1hS1[b,Z`'@i'hIJ(6h
+&(4J%eq!1,)!cFNFIiQ[%(If![a&h["1I)ql`(!*EZ--R#El2(9J,0c6I-2%$rX)
+G@![[jJj0"GcQMKVMBF3G(MqmLc[k%NmMlUJVRNEF`CI!-HlJ'23AGr3L(NIFJBP
+J"AGJ%lb*1rS5[b2ZU#1q4pca(VJ$GhJNiB0N[Z&b"IJXGfJpk"MFJArJ*hG`82U
+D1cJr[)`lH$9p`4dm&Tf"1cJKh)3lF!@[+1lJ-r"PlZ!9V(R!(CK16EJ$Bm"UlX!
+JH"phB!Gib"hp$0IQM[i4,i6KeS,Hj!kY#mmZml@+2AKhFBH'KBFAGiM4j1'1'X-
+VZB-$@IFdFiIIM(F9q6jpC15bPAVMFfA[m,U4dHe@*rGNR,99rb"C0k"9Mb$4reV
+eqa$pVe92$h&DD0@$4[5r9[eM42r$q"SI,AZ(4jESIfek"(Q,A841eGG(p,mfrA'
+B,1F1hae`L6[mHG!IZ'1b8I5r0MhAi-lFi@&KhQM[m$J5rDp0,a,4rpVd(8'li!j
+[($(TEG-M"pcM$KmFdIrDp-!3r@m%pEAV+A#(Ra%H80cK833[i!lr(bDaZF26KfP
+Vl[!KNY8K4ZJj*2VI#,hMd(bi`fF1[XmG[NkLrih3I`N[,qlS[j!!P8'%N!#!ch5
+Zld9UKQh3UIlaLhZ90LfCB+HE04Mpm4GQjPMU'f(#A*C+bmcjdR*"KRLhZmQ08,H
+[Ch*Nq,54CMF[QRQh-McAEV5+r0pRT[Ur6AP)1bHILaTp'0X(QAcISH&iEi$ZScF
+mlc8)0G[Md%K)frGH9Emd,R`-A'LIRcm3"c&#fVlId9NjM3XIZD(i+B6ERML)&Y,
+frD(ZffPFq+-ELX(2N!0r1!irK,&p''UB[j[90TPU,PNEQM`-RQb*HFS@L#B23bP
+EBakcfP!j$`-V25N2`bcE8Ki'AEDRqM$XXMrQDAM31X[NB4$QPT5()CPE8ak'CJk
+Q2!c8(%Tj',BjR2)`L(0EbX13!-k4P)F"RU-T$m-kGkBm$2,FPI)`N!"cImT$ql2
+pLMH9AXQ$UAKGbS24H%[+Jq&i8mU$+IQ3!*3(dr,QP!GMmk'p2%@V4*1(3IJ$k6d
+-(Gk6mQ!!-5cP`FKKH-U$FAaVbS-C4&[+J`(pL*3(NrVfP)GKpcX5rM!dqjb8Kb(
+jBbN2`q1hTc`-'ADN1Q+k2c,P`C5r)H9KkBXa+3p,B)a2H9JJBh,+``$j"hTmVj`
+(+mI1p"i'(UI&2%1qPBGP0kBFHdq)i4H'X#E+2fr"9&SEjIYlr)6!I@'"`h2@5$@
+XVIAp,b53!%`d$*`dZh&N+M[`fHJ8C,BRr2`AhD$'h(AM3,CdGYQ"6pqFII`(Vqi
+krM+"V@0DaSBhE8%[[(kU@ZLPGYrNe1BRF[r3a)4HL*&hEklAp)TkY*Th4C82%iq
+2bFIE4DjReZFf0+VQrIV8Q(iBNDpGN4FG&*8KkiZ@8Zr8dQe2[QLp((qaRR$4hHA
+)KqGhG@rTUfMpEp565cp'kX-@1$-VjIicGLXF['%mMl&l5cA9mjfk9hqpPZKCC6h
+[6NY#rZjHS44HRrA9rYB4iH`*Vmmc#!5CUV+8f6pZ!a"Ep$)@PCJ$HhV$[hmbHml
+YhaU[c1RhKTR3a&4,B%(QHX@DbarGGB)p"0dhPY!2ZK)B9TMe*`h@Y!r&JV*KSYl
+8KKClZmEU4%[l9@chQXC'P!fX09ac&`0kX5`E-TBhAD%+Qpb@,UELh[T9N91i-[9
+NrEE)UPBRjrfXU49j6,h4m!j,aYE*A5hAVX)HX1fCGCF[X$E+)mCD9h$('N4Qci%
+EZZ4MIDE)k9bCfV#H915-Ur)K9j!!`TkdXe'h0U`&&APXc)GYiZMZd"6eBmfSb&R
+GaQ9BeGCTIcHfhKbL0R9DXBdEkMDB$+l6&RKmBcCRkVK1'@4#im4*hP5RGHE%UEa
+M2Q`m*kd[P%RUY*HF2&98XEQYdj+aka3#c4f@J&K#QqQZU"1i8jZeR0k+ZQVCY,V
+2L+a3fMKVfEihB+-B&H[%%XlD&SXPA&3l5,'%LfSTLBdhGr3L0QG'ZUNAJE"bT)A
+j2f[C[YFbE9b[*H,Xl,JDr91[*DKB3YFl`5Dlb0CVIcShi%'ppTlc!Kl8Db-j2q"
+"[6,1JS!($8lK,Jaid1$+D1F(2'M3i@&4`)-'LlXii%'$0V!A"$aSd,Cd5F#$"Ud
+eP`BmD,![Z`-H0'T&Z#cJ3D1iY6cJ3D0fDLX#(M4U&ESbp,He"Vi`i%'MY9`9m+"
+4kd`QE8hr0@TaZ5EQ`iCaEF#$*LHCe`8mD0,fqU+!"dhfjIU!"deDafi)H0#N4Hh
+'J!G0pZ@QJ!G0@S0Z$RM3T(hPPS!(eZjfDm#$CLd"QB3e&U$0@U!bl@TUhDbe-KD
+fc&GKb`XZQhkfYV2)C)DR0@Z&#KBE'd9V)iZ9XTN5EpBpJ9SCI"NLaQ!*E55i)GU
+YBJR08$a[`a,D@"X1dIlbXN[c+qR4)IDPXB51JK0$l-[,4fEDp-d3mIk+LDd9F(b
+)eTeAATTG62eDV199MEBeE,'@9iHG&PVN%pFd@&r6h#%[AVZK-X)l@qJl,+(T[aD
+YG+m2q0HLGHDHJ(mYpZAH)&1fL$&Q1I)ZV(f(1K&qif6H*FP3qr+Q#TIQMYlBPdp
+@i5e$R8k&NaJq0&3,BV'%(UT0VPK#$p8'9LbKKfSh+TE3`m5BJjplRQX3$"0E$l(
+&P*%kKr(f52YMChH`A"dQ0lTYjlS+9Uc@k[3)2U1Q"iD*-8GG0X,FB@plM0+Ep`l
+6J[9fHX[JeM"Y3ZmBBE-#dl,djA2fV"X%$iEEPhIZkSK,`m@#Zpbl`0a4ZqHLjCL
+q(QjIhKhH0e`Hmlc`2QXYq[afZdlGKfY9HSpl'aMUK&[!mBYRkp5j94jhEdCbF`F
+ZL#9dUpa#,+&Ea6#aK'l9fPFXS9[P,Q)*MF@RXi4Zdkj6,+(EY(mA5qJf-88XSGZ
+dXaC,k$CYPX85ZNhF%N[S0RYG,+(Ej%CL#6e#e`'aK"iK0a*,k"&LQ9K#Mp"'@bb
+K4fMT,*E3f'8k5qJ4@YH+*I3)E96&LDKG'9SXSG[P%')*hDiYV&K#YfZl,CE3l9S
+pLb9dZdD3!')*hDjPVPK#Yf[I+TE3(ES)L#9dKha,,+%lP0A%%VV$(K0,k!kYPX8
+5ZN1X&8[S$Zeca4,DZTb+*I4)TAQaK"iTpaG,k*(DUSXPp%Ml@5bK4jTA,+&(DQ8
+XPY!Mj59L#GdTrSQmhLPI&%[S6ZhZa4+k8qiVPY#GpVPB3RIk0V'%lY4#@5bK1m9
+AXB3H*4m95qK4FNkaK"iPISXPp#KYf-85HT6p,*E3Shbc@%+2dNjC,+&(DI-VPY#
+MGI!35qM4fUD,*I4ShbIQRD2&2,'%(QhrLbAdD0mTPY#Ma3baK"kYhDjB3Sq4GiS
+Pp"MjM9K#Me%E%8[S-H+J@%+2XFI%%RU-m@)*28D1,TE3Bm9TXB3H+fm@5qLa1UQ
+**I4BF8J'2FD+&f)*2GEDL5Ad@2QI@%*E&eZaK"iR*a0,k((b','%(LG(%N[SFH+
+b@%+2Xmr&%RUFla&,k((D'SXPp(MjX9K#MpFH@LbKamZra4*k[2aE,+((LhGL#6h
+HAK*,k2(q&d[S#GUML#Ad",&(,+%Rb&2&%RU#j&!XS5H)k@)*28&F%%[S#GC),+%
+Rb"h&%RULqS4B3Nq8CiXPp%6aALbK*fUR,jE3%m9VXB5H+,k)*I4%DbD@d1`$l5b
+K*pPRBJNp5@`35qK*BS0B3Nq51iNPp#5aALbK*iNMBJNpb6U+*I4NY65aK*kXTL1
+Z5*2&Bl'%RU`++jE3Nm9lXB5H,'F35qM*B*Q6r#E6Efk5QT@pR59dPfXDLN90&qp
+cFQfA&XaL#GhP'K0L#GhP@SJbG0)&6MK,k#jUjbbKTp"ccK*kLZX-LLAd&0Fb&%[
+S+DlP+CE38l3r&N[S+DkI*jE38qKcC`NpPEc1%RUUkb++*I48ebB85qLTV[JTPY"
+6A@94,+'RZK+M@%*2"3HG*I48HXpC3Npcl85aK*lQqSCL#6h0e42&%RSDIHBXSDI
+4Cmi5HTUVm)NPp$4`bPP#RdAr1%[SXeb285bKch)94,'%2N[A$l'%2X[e3m85qLc
+AmK2plbcAk"2plba`c9P#RdeIX9kM[@1e4V%j2PXR&Y(rcYCp"%l%(DZ-bNSBCp[
+(S[qGE8q)rRFf1-9DMRc6U6[V1GSlqPK@`TMZ@SUb%XCd9f58P6#QZjUNV)3ahA8
+"iHrFXDSL()FlJf@Xp-Jh`jj$cq'1pl'q!(IJK+b%-81A#h#E1pDDK(G`a`U#XK,
+'$([1p#cI6(#+G4hY(6dR+f(-G$e(@3PMTUY!bNSB-qdj@3PMTUY4bNSB-eeM8&E
+#Q+R&ZDb%F3kiaPU2pSkHNj8`cY%P4eE#1-F9)f8PM(0F+e9@`MM(05YP*BacA)G
+39X)iajk6P6$1"DIX#L2FQEUc(U5p`ajG9X)iejk6P6$1eETG9X)i9aYd@3RMA&H
+%P*8`cVARC#@-@IDdV)3abji6*ljC[Np@`TLP8iQXK$(,062&hA1@Db$+5KLcA#p
+59X+BEFr*5KLcj41b%XCXHdj@`TLYKLmVBFc@qPa@`TKYcmP+',1eETH9-'DlSU5
+-)ThR#UDb%XCji"TVAGSlHNkQ8Fl6CPe@`MM2e9e&rcY21h[4rmjc*8A4rmjcc8R
+4rqEBFl)5aKa`LV8`lCfT1qYKfMZXff8PM$RfR-bLc(&e@&N*BiiV@-UXaKbjKDb
+%-GHHNj8`jYV6XK,'A(Y19X+BkrYN*BbjmL&C#@1Z+cR+*-GFEHYP*BajFJYC#@1
+H25FVBFac$3"C#@1H25%VBFbcjd6rQqIkRk,rcG2@Ar5rHDk"+IVII,Q&k(rcAGP
+6p,rjFJ[4rqE,%8ArQbq1L[ihhe9#4IqE,dF8r@qqp[ULrbe`E9E4raCSSbrkh`*
+l6[5r"Fk!L2kh3'iKqYm#ZBASI`YF@92d[`@ZXbMkhd*A%aApEk%p*rVI3YmRqYp
+#ZBASI`YGT96d[iAbCY(r&XSY42mlhp9K4Imlhp9'4Imlhji3rHpmHdld[r1T1bZ
+DfMZ`Ar5rmee,325rmm8jdIm@ZA+Xk(q,A*&8p,p&VJSUqYmLZB[SIi[NjD,r,A+
+PAG(r&SRpS[mY%SG%re[XbUDLrbffjd6r@qbk!U,r,CC$LrkhQ(jJ(94laqU@S[m
+YGK94dIm@ZckNk(mAf(1LrehJqd6rZd!q*rVI"ESELIjh!E9QV8alaaUCS[pGi&U
+MS[pGJ)E#fTPm5q`2dIq@Z&+#k(p,A,Y8p,mPpU,SId[N(+,r,E'ZS[mYN4q)rVG
+%6LRkha*V,2VI%VQ)k(p,A,Y8p,mPVN8UqKqqkkbrDHrS,G(rPMV',2VI8PFm&Ie
+[UBjKS[mY&AY%re[U@JZLrbf9pi[qYe6X&re[+6'Xd@R[i!'Lrbfe[dArklBr42r
+VGL9AdIqkl3r4rlVP6+,rGDYYL2lA,GD+rYGYIiMqeff2L[lAEAq)rYGY286rklB
+HS[peLm'Lrbf6YiRqYmaq&Ie[QEa6p,pPVViUqYmb9h`9r@qCXf1Lrbd64dAr@bB
+I&Ie[QCJRqYmbqEVSIm[%E0(rPVRDTZKrbq9jS[mYPdH+rVIFZ624rjDVEBMqYe`
+R10(rPX[242pElMV)S[mYYcp%re[ZZJkLrbfh2d6r@klf*[VIFVQqk(mVe"*%reX
+K4a6pEi9VdBVqYm+C*G(r9UKeLIkh`M@'42pEBHq+rVI#PCC&re[KfUVH9H3RAIY
+8p,m9VKNUJ5[!-PElY(F'#eMadpkCrQ(96hYRDX(+Rh`VAI06p,q9VLJUqYp+-)p
+931dGUkD+rVI5Y94&re[TUV#LrkedY9I4reDkJU[SIbYGV96d[j@ZmbVkhdVA(4A
+pEb@pa9UPpXld-'Z1mPe),9LRe0ka)URSIaHkiURSIaGD$p(r,U4[@028hY%VS[p
+Gk)U[S[pGk1UaS[pG#+k`[LRI+RU'P8hYRAN$Dj[D1eC@&Ie[P5ZrL[khbRP$dIp
+@ZFUXk(qVA-e8p,p9VJSVqYmUed)5r@m9[Fh+ThbVID[SIkYGJeAd[p@Z&#[khfT
+`La93l4hVd)VqYpS99NAr@qekV+,rVAD09Y(r9S0pV02+YiEqC1e@HfIHCYG8iSl
+e@%Ar@q1DXD,rVA%0@p(reYK2S[qYF9eDdIr@Z&kYk(pVa"M4rpD!@DcYbVH@hQ0
+e9hYRmV,#UlfMaU,rVAApA0(reVVUVHKrDm8jdIr@LQfLrkeeV9c4rpEk9Y(reY'
+hV2aUlqJRdIr@ZEUYk(rVA)&Ap,peiTESIq[%+Y(reVNqV1KrkebY9[5rGI!+9Vl
+PBpNeeX+eG`B,@!rAhTQkXb+Z[@20@p(r,K)[4Iqlb09h4Iqlb(9K4Iqlb&9M4Iq
+lb,9e4Iqlb29j4IpE$qkc2Ukp-aM('VRfc[3`kq6D1r0qeXUeGkce+rVIHYIV&Ie
+[[D[$L[khAJiKqYpkelF9r@mpI)QeFrNfZ#kXk(mE`%h@d,9hF!A4rcEiEY(r0[K
+ZdImfZ0U[k(mEd%&B1GMHXHDXk(mEA,p@p,m0m#T@&1EEk,UeS[pY"0GB9GMHQ9j
+PC@&lCpl'kX,fMTi@r@qMDrk+rVI4eAj&rpYSEiRqYa(1b@V$I*[N!D,rEE+R4Ir
+E"0D`mV#p-rh!kX2f$S`8r@q6EaApEj0i,2VI*[Q0k(qEa#h4rcD*@k,rE4BM4Ir
+EE$q*rVFCM'"0BAYRHS"eL1dGka+,rVGCr"$pEl1i*IVICYI$&Ie[XlJPqYm@9li
+9r@q,DqU+rVI&GAY&rpX#"YQCDqlJ(k,rED%@V&jXleM49r5r,Dj2,2VI&YFd&[e
+[Laa,p,qYiSISIeYGK9Id[kfZmb[kheE`MV@0lChT6eBfYRIJPZKr@ehE9r5rVDi
+9,2VI9VQ)k(pEIEISIcfq@r5r(R&,p,mHF9Vd[alV,ITI$lh01X$fcY51YAlY(9a
+%p,mHZBMSIcfZ#LckA`pmRY9mqEDj2V$SIpYmUqKrfjaY&re[QaJTqYmfDbckhcE
+HcfV(pSkH&[e[QcdYqYmf0![@2HEElYUqS[pY&lG%rp[ZQX5LrffhaU,rE3FI@AR
+ChS%PS[pYTaDX[fc[i1LLrfehY@24rlDl3V$SIc[N(k,rlA!eBp(rGXJM4IrE)@D
+)rVH$AQ+GBR[(UX1Lrqe`c@E4rbjf2@(4rbjf4@,4rbjfY@E4rbjfK@R4rbkfEd6
+rZjMqBG9QH`IA&rh[B[Q6k(mlAA9Bp,qGVPJXqYp1hbIkhdljK1Kr1m&69SqfGh!
+QdIpfbZp&rpYTr86rfb@(%2e[PkXHLrkh5b0ddIpff4qLrqebr@R4rhEj2Y(rGP%
+[9Q+fGq#Ck(qla@r4rhEE(k,rlCDML2khfrH*rVGEc8$d[peb"G(rGSXVS[rYMUX
+[fc[d#G(r,T&2LrjhLAaDp,p,A&GDp,p,A2YDp,p,`&r@TEChk#kLree#h9N&fpl
+"+8ArHjDV*B[qpbaAB4Ep,r6Q-`KQ0P,F2ZP@IfB[aB0l[QX3&!Eka6G#-KJB+AG
+F$&YT!11#*+*UL0YR"d$-'%Km(8V-im,H--&Bk"cVYYF0$1c'Dfe1ClEC2pfD'@J
+AVGVXG,FcX,ZfCq##rJX'DUhTcN#eABqc)5%MAh&&Mj!!PXqbJ[!DZfUfq3L&@E-
+K$'(eJhT(&G1pPQimQGZcBF`b-KX)MM1rb0`LmiV-+9TI3R-bMmM-),1)c!XbHmJ
+X)[1#GJPkFc*hb'`JXi,-!M)rb"bJc2q&+Rb0#j`NJcFRh62rH@q'TpdjRmU6UQS
+)h"F@D&CX#&efAfA2Ir,[2RqIjE#%$3rr$f1UIBdPaIZAa9rX2S2K$NX0"N5h8Y"
+-T-NGqZ,XE0FFGa$B-p[SeYF0cADkVCQ+hU1(LKVZSVN8UkGCLreSCD,DeAdd&im
+(+rkMaR,ejZE1"e+XVhYeR3kNa34iN!$ZKH%G+kS2a"Zm0K&lmd[bjS2KkqSGVEm
+2E'p!%AYcb$"EEc5+NR'4,E6*h-!H$V5TC1%"ASC,UdAc`4U[h6!QlFK(EYTF'@p
+hkc2eUrlME4LE)jmG"J*+iGALfIKRMAdpe*[cmr5j(G9Qh[KkNKh9cR5eFD6kNU+
+[r!`69PZBm-%@6X`MpNE['0l`8'LP38cikXl-0aYJChl9NHTILVXeaDeNZ21LThq
+lq)4A#NZdUjlmlbS4GDY@b-Q%aZkh(p**8!&dSQY`6S)UQ"0HJA+Lbd$ZJLXBi$)
+%MH*L#deZQk)+i2(i)RlCq$ai%eH"EU,,`"d,,KHX!0S%$N!f+@U!R8K3+AFCV&e
+`IjZ@J0V&CQ%k&PKUK`T%%ed"D+,li*Ri-MLli&)TI@"1"TYUpF-`#5S`6(30KNP
+3K@(#+c"-G"Q'AA#P[ef'S#PFE+8TUM!FMbrLNSh2`c"a&4JQZJc$XH"b`3S`61!
+!$*1L"X1*"*9bPf(B"IHhD3Q'A@`@KQ1"TADS`$$4&4JQZJq'L5r$X!XZPE)-`qX
+(Til#-!NU-%ad$BC*8)9K`LX`6(3CKPe`TEpGKU!TA'bP+DS`()m[iT+0cm-`F48
+B*VS-`l(JFX%+-%cJ!!b6SJE$L359FTGKf!AhYfN*KPeX&SCMJD9fU-!`d48B*VS
+2KSN[`l!,,T8b"m1RC+P"BHU80(9#R"U8T`B%UY-59Ep)05"6R45U6NT9&E&U8+l
+kVVKd5Pik*6!05%bR4DCqQDNU0!e)6B0Ldk$FG%Vk'44r6XNr*`5J33PS3!3k,32
+e#d%$8Y"*-HLN(&34K!BPSHm+1+FNR&-LcS#-FeV)kCGbUQ,1J*`c+1J-5MURj*9
+"JH@8a(*#C"Q8@3D%PY055lrB-L#hR"4F6NSZ&G&P8(EjVNKb5LBj*C3-5#@RaC*
+qZD3UQ!a)*S1LbD"XNT`B,8NBk54jZ%YR+!*H1NN!HHN8HG",CmM"AMj"[Krc@C)
+GQBp209kQF3,i+q4)BdXQK`q"kGJm#+BcP'!`RDB)K-8NrHA+J@%q`FRfb`*L2Mi
+1L8&`AfrQB6'GS4mB+i*(1NNr-&C%Mh55!@$X&6l5'@V!@"8rmPP+R9N83$+0-`#
+-C4%NNk-A'(Z&N!"dKP2!@"&$LNRkbe8$aUSNNXr5ehjPB#`+)lN%9@$X&8I5d*N
+EH3J5e2!j0IU3!!iZL2RT($P"2jqJMerNK2ed(p5Uh$YM&@3)UPbH(%VRU&@j-%'
+8MkqU"lND$ik[9!GB6JjN$)aNp!pP$)aP*!TINI$55IV*@dA'5bFC)'qp8Pik3if
+m9H@mI*B5)"3P[8cM$*!!Yl+XPmR45pjkTEedKP2NV5,[&C2dPkY'hUSLAcj,ArZ
+9b9Y4kXXPU*+hV0bApiI*iQ+3!#-*Ld'#$#S'19+J''4)BQ)K`FfG9M0@Zr$%@h1
+XE-[K2U+@iT-GA8SL$9d+GbeED,F8QPC5a0#TN!$#`p)J0!QP33+IiTAMqdVS5&i
+3Qi2T)%X'TDXjDQhJBh3TrN4$*a#k&!j!Pf1VRC+%jb$"#A41XqBJK8qE5r(9q[V
+%14-IL*j"MKSr##62)%Fr2mJ+RS8%9AjJReMK"aQjY"4IJj1d@&S+Vl9E2cr)+k@
+&&%9qN!$95B-%II`JUh+9%q6j39'$$E)-mS0!J5hNU2+$J[jD5P*Yk")rb)L[[I%
+9IT!!P9k$"!2m)#-CPZ+VpHhM"i'Z&Z5SmB0!93Ybp21$V+C@5&$P"rD*&Ak3!&(
+N5[%e1%RVFDA`@V[emi1m'&G)8H3(@5NZ50$($l)DF6P"RKm8CEiJbb!r#%5q3Si
+U2bK)I+8NeBBZmB1-[YFEAq%(*p5p[1SHT1MM"fRG[46ZDJKiTA0Nq8'3!#2*$i)
+%'Ai3j%MaJb"$NKm%#Ab!,m8RmD#842UP&&lVPa6!9e,%N!#YN!$#!rJJ0!R`33)
+Ii-[aI59d!"r%jJ!qb*)"q'U1@K[i!&q+2p(3#B![K32`jGKUTb3"2NL3!!6i)%%
+Di)-82X#AiU[e6IVbQAS1!Rb3!#-*m%'#$-!(19)!(f4)!Rb3!-!(q&*m%Jp+5D4
+I5Z'eINN"I#9&$0N++6b!$d+6!"mNm!'q(0pA3JI`3@`1i)-X'B#[jULeJ3r`TIJ
+6$Cd!q&)i!&q1VAC+%Z#$"%Q!$a+N!6j)i30m+EjDhd%'ElYpDl@jFlDk-rmQ(X3
+bP0k`VMAp-+Vi1GK1*CK!F(&*8Z'#-N6#aDA)JiY+%JBAj*-%2bD*)hkJp*BINUe
+K#[46B6'%Li9ji1kZNi$ZJP)pPi`5D%r'C!T5DVBFI,[)$'5Ril*&p+(CMbQd83+
+#r4"J0hQIVPB5APe3%P*G8"T'ACJ2RAj-ZKBq4")6f'5iZ#`X"@BB,Li(5eR,#aH
+8JD@#XB8IQ+KKaViL9X-F,190+Q*KF9M+@P'iS"`XC3E%Nc'CJJ5`9$5eF*%",!A
+@&E'i0#`9$#Vm`(3EqE#8FCj)a+4J+HX[iB,bX*3CC[GMdV9)`e)!59Ni#U!S"d0
+C#-V!6`&kdV#6JC`mh15K*J%c@BM*`8X'@V+`%N"+%8i#+!PJ*!-K"IK)3iF2'aR
+)b-*&$LTL5aS9@%Fm1XXpiU%"!iP(jhK)2$E,4Z+K'8k5LXa#DLSm!@DT3"p1%jA
+2FC9-F",X%m&ahK)2bV+AH'L1`k4M%d`Q(9NXAF"UiY&&EK12$aK10VUhp"QfNiU
+X0QLDqD3#(Ip*4a@UQq9#mG"HQ#Z4khKd,mb9L(BmZJ4c"G)G$bh#A*Q!Tm+cA45
+3!2&%j8X`ed[-%m%CQ#Z3!24iD!RQ!X+HMLb@VJ*c&3SIMkr!A)R1*k),-&HQpUR
+`3S2QB#iJqmR)!1B+a(pVIIY$A-l&CL(1"3B!jf*cm1BLXq$Q!M23jXGPqmB26R5
+0(qCh4kc118K,K5Dl1KBDKc-ANJ8c&jL$XQ4N!XL5F8'a!K"cX88)Fp%"J+9M#iA
+1J*FI9fl"0($jB3kfNM(jDQBKb`9Q!@[Gk'KP,C(R2!"CmHJXD-9$!pL+4qH!+ak
+EKDjiD!Dm8T(ChNQ&*lSR&HMh5U,b14$,"#Hl1a%F"l*i8"E+iU%j-%[(*Z!X(9N
+XA3"TmHJLU-AM!eM,4[H@2J0YUFKUJkEK,4AS!#iG9DKZ&Z6LS39H9K)IA'b"Pj@
+%"aGEj'8&dF%&"VbX,$Mi`@P5%)J0X6SAH9Q[d"!,6I'bJXMJ!SZm,"!BNR&"X8U
+mV#)YZ1J5,b[*#V(B2#mV5`TqF,i&-l`X%"-5F6PH9K!5iKV$ZRcll-kGH9%*-*5
+1AMmemB!bNCmqL!GRCK"5N4I06HHd["RG+V`X2Db3!!SX#S@9%K)GP,"hVLFHA#b
+KLkb@-$m'P!S-q(433"HE+Tq,bKI2K@C+jmF9#ZFRb!X$3G&+`"'M,GQLpB+'#`f
++9J--2d%H0BYJi5M0KNCV1pKGNcG0Q3j8Qc8I9j!!1$hQd+X@!p!$Mb5&HF1qmmD
+rT6p+JV,1+2%&h"XSG%c+kLed,,jFD+F3$6bb9ZKdJ[,F3+l3[R4BU%"5VmX@14Q
+G,l%[JG@Hee[HI(L[k&BXE3fUNT5h80SqQ2*CC1ejeG*@!#SIA@#@)23!FT46q05
+N9X'"4bCTc-lC*KNb%&J)cr+f62$!``LI[k"ZP%M%JV,VZQLl'iUUr#FG[r$"QBE
+c+i1e@Yf-8RG$RG*PlAmp'ITH6hcKp35@AqqkT[4f&epmZBY1[pZ&e9lGefmZ[[,
+UI+qjX-+V`lbqh'j4N3heSU-fHp0-hZaQkm+DBE6rTTPfUqL@Ll,e6'bpjhT0YG&
+Si4Df-@qdXl'YPD#)fN5ASQ"BfC!!@b2+49$fr05C$BV-CYAQ,CHfLNDYIjTellC
+@K[TPKHZVDjpD[rbLfMRpP-,'#FN``9k)8CR0reLZZIIN-Z8)AJ&6R01)1AD0M'r
+CCKBEQeNT*l,Z[SK-Aj!!*&ClZC6DFqXTPC&Y3q-E&KV!aXAl`5D9D[(!@29LYhE
+c[4ZVdrPLaIeQm,0kpA34UI+C4V2PbfcX%PRA@m`aPG%%jc)@RZ&D)p13!,'fNiF
+PZciINNP$Gq4$-QQSBMl%KjA$"j1QA-d,9ZIj92&#T)0bUH,&5!GYU-lN*IXb3AI
+N"9eYeLE(81p)cZUNM%dF+V*S`HH(G(ppEEdJ*TZ)!J8af858*iM*@jAi26lc`[V
+pH*X+5SANE8dLk`Jm8LhUH@GG4$6hhh2-cF&q)U-Rr-5FG5f`'a[$JfAD&,Th(iD
+$iL0FE40AA@[(k0TE+j[bDZ%i8+lmX4GRHb!H@BT,i(iL@5`N8b9dX%20GBG)35Q
+*)`[9$V06HcNZN@kKFM91p-ck`bf6CJ@C[LQ&ji2&HL5blZ#&Q$ji!F$KFq[YrU*
+66*FAqrah3e&`FDaDCa9)Fh'S8mYMT1'GjYq0+2EHcHe'F(ecLi[EZr8'IfmU0ED
+Mh1`TVQahqAqXHf@CB%marC3,`rpMeHeFl-eh0+TG(h1Xb(06APr[qVGlS5VfCPr
+jekY,pd*KZJp@aZE`8NPYZ,,&k9kS6RFX6hH[2Yd(#p4pX%)Q`LX4&ek0ZRY&kMj
+BTHjBTKZVHmSiqHmpfUZ([6K3RHjdChIX)0CFlDfA98X%FHG&QBY$jFYL&h%3-E-
+,92&)8)RPdS(0NIb+HJHTLCFPlVc+QKKhBGj&!ab0&A"h8S"i+@bP[2ViY6*iF+M
+9f0kD+pXJGV82@H1'SUaAr-VGQ2caUpZEpEP'2E4,iLjfCC)PlZblVbX,',mbL'A
++[@Hfk*5[L&qj'pX#lST'1TbcFkrA8pk9Zr(H*9IQ"Nb3!##j1Pc8Qpfb4q-hZeU
+c"@`cNGS2L6@0LdQ8aBAijABaLAC*[-C9a)A%X-i&a-!Q8j98S@*3NkP+)X6[c8a
+9dQ8R`'*c)NlZ$AqjP$&%2f-m*,8MYL8ImHZNBZd(`dr@6lB[hh'`X0!F`kRNJGh
+ha1i*4(N1"Eqq,&Xk9bEq-(6V)&U$Akp%61`Ud@'*Q)6Fl"A-A@l)ZaYDphC"2)3
+E#)VI2BQBj'#TpkciYHQbJke!3e*A4pZ0ZL3QF4@V51)PANI0T+95!6C$3XG1*,H
+j2'S%lh)APY6k!1%&q"#BM["ca&Sj'4$,kEGP1Q*IPM[KZQF([54hA#9kbBp2"AQ
+*BPG"q,kib(YLr$@lfAYfr3YrMMFcZjZDedh1k'EQj6+@X9NhdB5cTKYP5mrGTQG
+YCEif2RbAmR2-'#HQ"eLcIS+q-@$@#6(K#ZJF$K-1II%Te$flUX9-p4"T@8Z)DC&
+i5*iLq5hU3V,FbQpc&j*P*$Rb%qIEQHFR8k6BQ'-mlMV,i(,X+8r&mTc4alTXL%P
+mY&Fc3G&dK%NV%I&H-h#qDblm0kK1#KI"K4GLmL0XT9iN%BA*Xm+mQ%'b'jTA,$i
+L&R"J@X3i8K*kpm"ib!'(*2CFAK-824DH[!qQGA)61SQTR0#a5Cc3KUq*A@,VbSf
+RSb`-fl*dh*Ehhq'c#q5#"k&[J*!!`)1'J!IGpDXkZiUJ+R4RJHQ'XH'"q9[(AXZ
++QF&M4H[jHE'R`d#A'FbrVR!fRm'1ZdTpfNb`l3Nbfej'4+qVjF85BfL4i!Ierid
+(4X)00k-,#6aJ(ra6H""f4Ki6H+!#(RJ1,EHhRAS2Ba1A%RMJk3FKE!K3a!0lUE-
+60l@`GHVlkXE'*ST(ASfk[AYife4rifLHR#e$kV[hi$[Z1[U1[*P$pKfH"D3hCeE
+i4Je16)`q8[PV19HhfrpCpbIHXAEmQMh(mKJI&!TEbl'fdAPiH1Rd1cE[,REdFcj
+6elEbV@[A,`h3(cXR0`mY$I!1Lc$AlcU+-,i,6qpRhh(6p*&hj,e*NPm-1IGeCai
+"%IZ1r8HlqR6IK``JqB([`8Hm(J-F"6HNlliM&)"CA$ib86RfeX%qSqr0,1Ak4pl
+"YlFe2IY)Mi',eMdM&1!GI(1Q'`aVrV#ZpKhlUppMThEZLRHB!G`IpePff$[cG5d
+p`5KlaNB[2TBRl8C@V2b1dBH4kV[[#!eJJYX[h[KI#*bb95Ym1dCEfjF'U%G)"6-
+G`2+NY9cY(E21A5VJ(Id&qIYhe)$mIlpMN!!422'1'qD1&Z68&cDJ*2b`le&X3JB
+8J)(Z5,ND9[[M-#iB)3([f(1N3`El)elA2EZqMBarril$4pMlB&eMl`J28%L1jMZ
+A#-#c8!#P*Aa#f6LkUr%`AdalFKBq()A#!Gl"0iFQHDDZ1`kqidG0B[@'q$i%a54
+$PTj35%*101A`!!BA+U'pKLXJqHN[krH8q5BYqD%*QY,f9[jT6E$bMR#6kC!!Tc5
+iFRGm6i-lmBiR0EJ6lhK5Jc[jMLFdZ-&hK&*SF29lEpR2"&iNHrc@ekeF1hBUpar
+)([r'IGRM2RA0SET1ZR9p0VlbcK9hR2abiq[hhPCEU%F)J`CADE5R0EM"GcbT`I8
+qi`FDh)Ph2+A"&4m54U$"pHF3rr16l`J&B0bBV!r@,'[%R[p#2l5m-U"p6mZV-TQ
+`!#f[jb%T3VlfSG%YNipd%%`RI'+k+$aJ+LMXC(VQeU--cKKh-VNApr*-I6'Q%ci
+aK@-mYhq-DGilISM!XHQCJ5QF[kY(q-hdc,'P!(`kc@)j#bqX,+k#NrP'ISF4Q)I
+81[ST4R$L(8mbJK2[H",*6llM#53II%Gi!*+(,mc6pGBec''HVY*S6c1#`AFmb3K
+kRr%$4R$L(8pTHF@(a0ia)$1CGpL0P%lJd*(m5*raL"Xk8C6SHdFSJ*E(&b)`,mC
++'08[SGK8%Gqmip$fhGpqarEYZapqKdc[XkCANF)0r4p[&I1+5Sjrm&DT[H2dY-U
+J@Ka#-+hb)`q5'00j`S1NeKrK!@Vk2hKeP1[a2Dq1@Pe2UpHRqjl[5Bq0@MhX1jl
+`aULp3hCeUJc#G5cj-3IR&6LSr02UGH8Gi44cF%pTAP5eGl,K(c@[%qpi8[-kmBi
+R0Dq6lhK#maTm4hM!r0T6@P9[2@)-lLP0TrFG2p"d"YpaNJP@J&@qN!!+Pk4`!#d
+QYAA!d%H")&X(0#DRj0$6,l@HR,H1BmM+&`ShJf5r-lL,$65L0chhr0,pHY+CFbZ
+ZZI[*h+r+6RrarZa(VQXFUZ[%keGRQfjrdiTRAhfAmG'EUTpCU-FCIm8''Xr80Fc
+"YIS-h@8$M4#iVfGbC2LdN5BDpX'm@aQHDcGDaAGpIcI"38KVZ%MSLPeUD-cA-($
+5l-D4UHc!THH(!'-frrR*Di1rG$IFDHRXXJ22I%Efm4qmZ[0f3LEdEFa1(K[HY!@
+RSHZRUS@Z-IG06Qeq)[F268b8cPV[f&b[UISm@XflSXU(L8H2qhLl++Fm2VHK86A
+[ekH3!&(-rmHCa$LDpI@GY,jS`BM9MkjBj+(4HVD+[pH8GrZc-rRlKM,`hZb(q2H
+0XQDcpF&@*j9hFl+ePDc[CmUlml+RmHr&-4p@qQq2GjZcl14ha#IZjY6Bjr,C!*!
+!0A`-k,lrlHYffqX'"P5ejh4QQrhXiM'A)BZpXp2GcX$ZfTk"#rS[')$*(afSYZX
+$5j)dJ%CS-+"SIk%[hmJe3q2VKpG8eU`IR"VNlik4SDNe5kXd3#-l*hKI$![-mN-
+)KrZP60k1-d@B-(P'm2H@P+HG[lHQ2#2jHc$PkH6[SC4R&(m2Tca`cpY5RM(m2C,
+bM1A[dC4R%Rr[6(NQmrHZP!ISZMrPJ5rAaccQUTaR0F&e+Fp'JTY5RNebq90jc)b
+`1M(PkH([JC4R'hr[5AQB+AX6JS'(Kj8mGa2HN!$HFar"Be1HPa!m-Z9jJ1#1P1H
+Pr,dqeI&"`M[6Hhk+i#NTcrd%Mcq@j``)i8[YF0EbD"*NKl2UAJ'KTamlR1'D9E2
+,$MIj3Z0QN!$1j#jf1(ZQVQ%11bHFD96XF&DrpjEpj4k9NlHqEZADX91jrd$fq$I
+ZbalhU@X1eAA5VHZcmC9hVVMMj*FEAlrhYYT#2Fk-AhBiLpiA&3kd#FXePhHkeBI
+dZ*!!K)qp3N*N2SYTCb!)fmVpMiq'!,D9q`UEbrREbRhQCVH91qBfF'(UfmU&ebJ
+-pGRb93GYp@FLe*jcIiS,iaI#8"Zeq1T`Z@hckS'!8"JT[2NHk$E6p(RS([c#"k!
+pqCC,qUlY1h%C5mkj,k5JCbZ2!L8F8X6%N!"5eH`3'cQLkdF[f6DpTekE+&UlYdi
+bZK*G%U"`q[jKM[pAm1+kK6fFQcLhFDlLA-fjNA-,jpfFScR(F)lPR-3jQA-8CbG
+R1fFEj`M1NC`c1'rK[)rc*C`2F,k8md&i01XDARCX,6b6Kh80RjhbG2$hmT5(G3f
+[6(PBer#UP!IalHU8Kh80VdPj@0I`fT4R((q[5hPBer$'P!FamUD8"ijiAmV$91c
+V8KkceQ(NG5N2`emReL%dHFckKj%hT$aQrF2)De)Hl%9HQ2+`rZ%9+3rV(cirjB(
+aI#EPH5(KSe1H&r(h$5Q2@4-aFPh+BpBV2,R@SFPMeMp8I5N2DbGf(FYcjSh`SA2
+!$H&pjQcRl1$Xj"c&1CTcM*`I2JpAKiI$XH(2F'0i,j`@[JSAK4I#qH"cF$9iQ19
+BU686KckD"&NcXES19HMTjiEU&erdX,0`@-NA#MH$C,m`932+-&V$Y-B!KXm`2XY
+d3L(S6ZScQaX0f65qDA"XZ(pifcG`hNlH@[CVrXMrV*d4,hRb`C%$R(rqD1jLEG2
+S6Fmp[p3"*jdjYq+DZjr-rDVXp"I[chlNZXDKZNkmIR@fkIBhVAMfeAFC(lfTqTQ
+&HTca9kaYqNaG`aa@[6XMGeREp!`%BCR0,5b`bFFbQlZZ[AHCcBh2F*R0SfmR*,a
+NQFd`Qp8G)kG2GQYZmm,-c0&@)lp[QM@ffCieRq+NdbllNb83DK0HYlTM+!`'K-4
+mBET,iRA'T461l"1B8qN,SpMX08aJ1BNcq35qH(+YNc2["8BCEX)+``MH-j(c#h&
+$V5r'kGqrF#mpmhdTX[-[Pa[c4V)[aXlkDScrbh#[IMM'I5h'ICeYfIRqUTaBMQ4
+ha[ar(E[UEf+qEf52+IrrEAcR0m0rY6UqkqciIhVm2b2Qr9CmclGMh-3BpeKmrq1
+aMYm*HEb1#G9P8Q&RAi`(0@qmZ$AEV'%T9NaNA38`46*XLSdP[c1rG@66qZCXB`N
+!"l,3d!r"+DA6%f#$E(4LU6FAP2P#!0Ce-kqUVrDhC[r[%H"mcf$T31-@KJSGk*2
+HZc1lK1q-*81&5Ba0Kq'S-'Gf#9p)mIa,b)ZbmVekrYqlm,E[c(3"!cc"4B`(*55
+FaVR90SPDJ3fI$!,92Y4HqDVf`#@a+a`#&d*PqMl4UfG5%MJCl`SDZCd6Kfq'mh(
+%EZ$%+4ZAl$'FZ(@c-eJ(j`M1PSJ&Z(HhFJlPC0q`8C`iGSrN(-[Cb6PZ+BIb[Qf
+1lESL-jhZi9hIM[eUPUdf,MdK1KERmk('(6cF*M2j-j1iQqm0Dq"p)q2lkQlV"AD
+r`VE`hZI(+4E5Uir[mq0QdLI0qfHkjHD1#D4U)&rN,Z,BBM)4erK-rR60G$Z(mc@
+k$CV8bArIX"qMc@I2Y$Z(ihEF4)[[RHRZ2&bR4VCDLjc+ZkPhiRe0lqI2Vmed'ke
+liaEZ*IqULG&10e[q"AGIQacL1Rq$2h2+AGEU2[3HlXi,F3HI$p4X#R([(65(&cI
+bAm8J,qjAAX$Gh""hP(k0V!jahcR("T2hI8aFmZ)qi@k$bf+q4rRc8"NAIHSRZ9X
+Hqjlpe6D(I!ql41D+%0IbjX9q5K#ECc1('1[,4&bcZ9eI*Z)Dpbhf65+ZjAf,IC1
+)fr2V[IlirFZiNeeqphbdeam(a9AC$(1IQ#Vpm4XIjUiRa"e`efhTM`FrapeP-Hj
+RH[eal58@91*H[G!IGDqmNl[,Ber5Rejr4+IXb5Y#A)Fpj08TqT+riNj`m"G@,p3
+THVUB)CZUYPqd8+IS#phD8RC,I35mP$T&Alk&ZcXLlKVmN!!k45rl-qi-2YKm2pI
+Vil2&0[+$kp4'k[4+0d58h9mll$q[6[T*Rq)12+&pIRDK6VV2A[pfL"[bSB8kkCF
+kFrTBL*Yaad+Gp-@rc0hMXBrT6kp1H[LVh*PGk[L@[R1K6ZV2k5d(MGeLQeFRYCq
+P&Kh$(Q+0Qd,rIH9hL9XCFAU5A-UVklV2%bFlZcA*2b6IPrqCZ+YM(*[SHIRUAJY
+h8qAZGbD1hHfmI0'9p*EbAB5mTjI[VKF6*cMG4"p,(far#RdJHq"&6KBc[,KYY3Z
+)Hh1Xhk[i-cA8pHh'I65q!kiRrG&XAF&R)2'qKIl3,`*Ve0q%Z+%Z-1ReKci$6U6
+q0[)!qY*lRck0RPIr&2[l&EhhcB5R+V',IUAZdRm["`m82@*j#FZmbIZ@`@r99b*
+1rc*raT9aNAH!P9VqDm,(mGDfDd2FErdLFI"Gmld+rY%3qLEb02L`PYqDI,2Jah0
+[$A&AITBiq+lj4T!!3adIiUk&HfKj-Hrq2B[VaGh`am5"lF4pDU'ZN5IF5KbFQcJ
+ifA$MMXrrfpR%JIrJUhQ61LlNqp3r%LFFZdQHXc,%(3*lY([rm3lUEYpKS28"iLC
+%r[3R[%0f$A`aNp[DA4piKmNK1"(jrp4'4r`B$BG6TiDii@ka*rJa",i5Z6$%IC'
+HeR'Rf(fmThiLe1qVD!Mk#5(ZY@q&,lD(I!rF6Gc8%0FU"lSqa+hm#q+Q44b#-bd
+*F4I6NeUmSNlS&F0Lhm`Qc[5)M3-RT-q@fdr6Babm6ITXrkZ*NfA[4UTcr(D)H`p
+[dq+YqFj'$e"RKEK4p,D@Hj)2h(mia!eP0d)0[lCi4RpErR&mrN[`84ehqecm,Zk
+NRbDq4#iZIB-Z)6Md+*a@"hkXR[A&(Jlp+9a,"hkXpVb`Kd26fDT9"hkXpY+[$SI
+Qd%-kEUJi(plTF1J&Vb,1B,AY*lLAp-HGRb"Z3Dc(bhVpd3'2e%q*G@9h4-'26R"
+D2cA%E8,RF$Kd%Ea(Xd1LlH0hpA$SCA"F(IF5(UDZ*1qiiUA%A4$L0X06(3jp4*b
+!2e)RH+h8qe*Lp)q(Z0Ir83q(ERdpFD)(Y)Q$JN-cl$p2$e$Ai4cLiC!!@9'$r[$
+d!(8pQaFk(2ShD"XkkJ&M`"k(3epq*A(#cpVNiB*$M@#"M[bXaIF,$Mh(ZSTr3E[
+i+(dfrAELi)1d'$a-qZc2i-BkEPSl(ClUF1Kcm%XGYdImHIL3!-1KYlfE10Q%GXQ
+024cDLGDLikSI(El(im'4#ATBK`eXe9XqeX1Kc3HiJpp42rLcdcqmc6PX[VGm'Fc
+m303riR'40kZ2I6VU(iQi$KeDR2i4Mp1VA(GiAp3r%[R'LSq#IbhL)VU@HIH[`9m
+GrVd@(Up(3Yb(U+Z(ImIRri%lc@k5a2hqTKlqADA@*6V+'cl6`lpAQdpdP!jjTr6
+P#ML%MMV+-(QGlF[MmhI"QcA[XR@LVi5(I84H*AZd[J9mF[MhN!$i,FXr,j!![`V
+qAB9fSXXG+mdlf#YIm1qem'1p1G6[@q#T`lqAL+qbIhi,f1EKhr(j[r`)FHKA*Y9
+MD+`1rqTrMMM`h(a,h5&6m'mY'S'@6jP8Mm2I(!rl@lL3!0iDqV*1(9,`le+iVik
+kdI9I1SKraqFr)$m6h@L2pE,iGhcqGM"H4peS*(c&iGp9k-3kkNB,ZA0pGJ303$m
+RpJ&i)(hfQ(Km9BKlUhJLq(H*20[61I4ap+Z(ImIRhb0HHMU(2PiG3["[S4a,&SF
+p+Mm8([B&qEfhEV-q!9cfm1rir#I4)(6Fd,VeAaEa,llITPi&$fLk,H*I)Zj4GCc
+24[b,ad9'hD$@i9mLhbKU%m1r4,iMERlTi9rG(iKcKYq4Ec3mAr![qMbd62fL%$I
+M,3[mVqjkZ)F15f[VTi'TJRpe0mK6Aa$LKS"hJRr4Xq`ESrPBR(MP3Pp'XlmMcQ#
+[VCr*iI6#0m+9pG8acR!D`DhSFm3RlXhI&R"+m#pk$KLKeAQS+hUKKhr4&k$&k*G
+&r%"AN!"hX$QT$MU62NqYb-1rZLqK9HMr&h%DMG29qeH*)cqdefJcJRr4R`!l0$c
+8pMhij1&Ip!`d"5fI0Arh`Q@&rp@pPEN'$DFMEYk[,H"Ih4[T-Id,i4e[**r`[qK
+b0!r0HrRHl2XprKGYJR&DcC0hdbFHrNA24[[3kUl`*(L&p0RH$a,h81`$F%[dc[2
+3ZE@m$lS06RMi&jeKGe-0CbGZ2ca@q&rGAm1400S&FEI)%ccmLfk&BfYe$qU%rLf
+kmLr"bEAp6MkMK`VrUrX!ZE9e-(m2fK1HAKKj#4LQj4hQlf&Q1qSLRhL1ld!,jAe
+SXCiq&aN&Fl9kX[NHNFm,hSpr'h(SYm6"ai6RAI%QiPi6hMId$rRRkAD4[@J6@Th
+Ir$hI2[0dZmLBZSlT8q+1bVfN6S[S#DhHDrlH$MpdGET'r[(kq!jd5DR6@,LG9Qq
+(ek+h5CfDj8RHRUakcXehT%j[KPYVDQAMk$HTdb'iR9C$0Rr[kZQ,NBYqM`"2(p9
+AbKfP6K2JkYSj#22hERLfUe1RrIe`L,Z(A[(UC2LCd@)d1'rj4a`r)Um'1c5kQFh
+h"ldkGGe-!2Q*-jcHeHQ2k@hY,!Ed!Aj[kh4mrJjjfb-alS1p1Vd0E8@(29reci0
+9VNl23S28kY[d2Ea3k[40Z,j@4b81RLae@Lm2"XISEhLMe1R6B)%11mAUUpACT8k
+[&+F0YK2h)R&@qZNAdBVdlm3q0K`dFXS-HjV(Z40apkR(I@QQHYr'fir)JcfFDhi
+E'V5'Aj!!lhki8AfSGr-Pe%kMT4$h-R6+ZX!2QRm*,926bm3pf01IQYk2VUc9YBL
+MRlak0rmQ'V4fYS8iH-A9)@kRZLNk$h(`L6H'Z!I%!h!2qN#pjAh[rJ)"4YHbF3C
+2ACeZG6NKG"jJhf#'e+RTYp'U0"SbFDp5(jGk2b`rH(q-3kH81Xf#NqL`DDaq[EU
+fe1P+HPZr0mBaKq(9UHNVmM0i",#2VLh[Hm"h'pb`F8E2P6SeI36Xdmie!0HQ,ed
+rrD5D%r-[`#pp)rAq1*U)GTk)12LN9kHQVm)9p3GL($c%Ue26qq3I[a[MQ,f3!$T
+p5pd4[3iHKQiZGCU#4U$9Bi(hH$mel9HI0[K'h-1pIQVq@IX!hBCh`0qN6Tm8bm&
+Em!bq,rh8U2i02`9qk6qTdjqM9@Zd'Z,HUZiMIIm+Z)K@*`GqdF'ppcAHBTfBU5%
+1r9IH[3*ZS1NG'iIZ+A'2q1k24(k*VL&a9cPRi-eKk0qbYlbjMBEIK`2V-)HKhiP
+1*('0Tk(Yk6#(SGmPGjGmAd-ld'%13pmJYjDicm*&0&SaFEr1ZpAji4hhUQ-C$B'
+iGpJhZd2F,(NB1J"aCMBLmUS3plKkkLG#h$["!q(aM4H+LfBHMEKh`IrGqckYR[(
+*%2GZF9EHph*a&ai(c$+(+1qE3UpUjKTXR1'"lRdcl32$PBKl,rc%[HpCkVl-#J'
+rr*IhVD8(p+G$h2[8YH9pCm%4p5dacZ#1Hpm'iicH50a[dJrZIBqTVe0ri*Fj5RR
+I+p&H0E-*0Jlp5plh#E"!bq1)-h0)lRd2b*rXM0lr"`#3!edP!!!:
diff --git a/macos/osdep.h b/macos/osdep.h
new file mode 100644
index 0000000..5a69033
--- /dev/null
+++ b/macos/osdep.h
@@ -0,0 +1,118 @@
+/*
+ Copyright (c) 1990-2007 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2007-Mar-4 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __MACOS_OSDEP_H
+#define __MACOS_OSDEP_H 1
+
+#ifndef MACOS
+# define MACOS
+#endif
+
+
+#include <setjmp.h>
+#include <types.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unix.h>
+#include <unistd.h>
+#include <console.h>
+
+#include <Errors.h>
+#include <Files.h>
+
+#include "unixlike.h"
+#include "macglob.h"
+
+#define NO_MKTEMP 1
+#define PASSWD_FROM_STDIN 1
+#define NO_SYMLINKS 1
+
+#define USE_ZIPMAIN 1
+
+#define USE_CASE_MAP 1 /* case_map is used to ignore case in comparisons */
+
+
+
+
+/*
+#define DEBUG_TIME
+ */
+
+#if (!defined(NO_EF_UT_TIME) && !defined(USE_EF_UT_TIME))
+# define USE_EF_UT_TIME
+#endif
+
+#undef IZ_CHECK_TZ
+
+#ifndef ZP_NEED_MEMCOMPR
+# define ZP_NEED_MEMCOMPR
+#endif
+
+
+#define EXDEV 18
+
+#define PATHCUT ':'
+
+
+/* file operations use "b" for binary */
+#define FOPR "rb"
+#define FOPM "r+b"
+#define FOPW "wb"
+
+/*
+#define DEBUG
+*/
+
+/* These functions are defined as a macro instead of a function.
+so we have to undefine them for replacing (see printf.c) */
+#undef getc
+#undef getchar
+#undef putchar
+
+
+
+void setfiletype(char *file, unsigned long Creator, unsigned long Type);
+
+char *GetZipVersionsInfo(void);
+char *GetZipVersionLocal(void);
+char *GetZipCopyright(void);
+
+void InitAllVars(void);
+
+void PrintFileInfo(void);
+
+
+
+int fprintf(FILE *file, const char *format, ...);
+int printf(const char *format, ...);
+void perror(const char *parm1);
+int macgetch(void);
+
+
+int MacOpen(const char *path,int oflag,...);
+FILE *MacFopen(const char *path,const char *mode);
+#define fopen(path, mode) MacFopen(path, mode)
+#define open(path, oflag) MacOpen(path, oflag)
+
+
+char *GetComment(char *filename);
+int readlink(char *path, char *buf, int size);
+
+void PrintStatProgress(char *msg);
+void InformProgress(const long progressMax, const long progressSoFar );
+void ShowCounter(Boolean reset);
+void leftStatusString(char *status);
+
+
+
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#endif /* __MACOS_OSDEP_H */
diff --git a/macos/readme.1st b/macos/readme.1st
new file mode 100644
index 0000000..6182756
--- /dev/null
+++ b/macos/readme.1st
@@ -0,0 +1,16 @@
+This port is for Mac versions before Mac OS X. As Mac OS X is build on Unix,
+use the Unix port for Mac OS X. - 7 June 2008
+
+
+Before you start:
+
+Extract "*.hqx" and "source:*.hqx" first and read the Readme.txt.
+
+The resource file and the compiler project files are in BinHex form because
+they contain Macintosh resource forks and as such can not be simply
+stored a normal file on a non-Macintosh system. BinHex form is the
+traditional way for transferring such files via non-Macintosh systems.
+It's also the safest since it uses only printable characters. The ".hqx"
+files must be converted with StuffitExpander or BinHex 4.0 (or equivalent)
+on a Macintosh system before using them.
+
diff --git a/macos/source/VolWarn.h b/macos/source/VolWarn.h
new file mode 100644
index 0000000..2d921eb
--- /dev/null
+++ b/macos/source/VolWarn.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+
+This is an Important note about pathnames
+
+*/
+
+static char DuplicVolumeNote[] = {
+ "\rIMPORTANT NOTE:" \
+ "\r" \
+ "\r This port has one weak point: It is based on pathnames !! " \
+ "\r Because it's a port !! Unlike MacOS: As far as I know all other "\
+ "\r Operatingsystems (eg.: Unix, DOS, OS/2, ...) are based on pathnames" \
+ "\r " \
+ /* a short quote from "Inside Macintintosh, Files"; slightly modified by me */
+ "\r On a Mac: Files and directories located in the same directory " \
+ "\r must all have unique names. However, there is no requirement " \
+ "\r that volumes have unique names. It is perfectly acceptable for two mounted" \
+ "\r volumes to have the same name. This is one reason why a application should " \
+ "\r use volume reference numbers rather than volume names to specify volumes," \
+ "\r but for this Zip-Port I can't use reference numbers. " \
+ "\r " \
+ /* end quote */
+ "\r" \
+ "\r From the developers point of view:"\
+ "\r The use of pathnames, however, is highly discouraged. If the user changes"\
+ "\r names or moves things around, they are worthless." \
+ "\r Full pathnames are particularly unreliable as a means of identifying files," \
+ "\r directories or volumes within your application," \
+ "\r for two primary reasons:" \
+ "\r" \
+ "\r* The user can change the name of any element in the path at" \
+ "\r virtually any time." \
+ "\r* Volume names on the Macintosh are *not* unique. Multiple" \
+ "\r mounted volumes can have the same name. For this reason, the use of" \
+ "\r a full pathname to identify a specific volume may not produce the" \
+ "\r results you expect. If more than one volume has the same name and" \
+ "\r a full pathname is used, the File Manager currently uses the first" \
+ "\r mounted volume it finds with a matching name in the volume queue." \
+ "\r" \
+ "\r" \
+ "\r The main reason is that an attempt to implement support exact saving of" \
+ "\r the MacOS specific internal file-structures would require a throughout" \
+ "\r rewrite of major parts of shared code, probably sacrifying compatibility" \
+ "\r with other systems." \
+ "\r I have no solution at the moment. The port will just warn you if you try" \
+ "\r zip from / to a volume which has a duplicate name." \
+ "\r MacZip has problems to find the archives and files." \
+ "\r" \
+ "\r" \
+ "\r ... and the moral of this story:" \
+ "\r" \
+ "\r Don't mount multiple volumes with the same " \
+ "\r name while zip/unzip is running" \
+ "\r and "\
+ "\r My (Big) recommendation: Name all your volumes with a unique name "\
+ "\r (e.g: add a space character to the name) and" \
+ "\r MacZip will run without any problem." \
+ "\r" \
+ "\r" \
+ "\r Dirk Haase" \
+ };
diff --git a/macos/source/charmap.h b/macos/source/charmap.h
new file mode 100644
index 0000000..5656b63
--- /dev/null
+++ b/macos/source/charmap.h
@@ -0,0 +1,380 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef __macos_charmap_h
+#define __macos_charmap_h
+
+/*
+
+Conversion table from MacOS Roman to
+"Western Europe & America" Windows codepage 1252
+
+ Notes on Mac OS Roman:
+ ----------------------
+
+ Mac OS Roman character set is used for at least the following Mac OS
+ localizations: U.S., British, Canadian French, French, Swiss
+ French, German, Swiss German, Italian, Swiss Italian, Dutch,
+ Swedish, Norwegian, Danish, Finnish, Spanish, Catalan,
+ Portuguese, Brazilian, and the default International system.
+
+ Not every char of the charset MacRoman has their equivalent
+ in Windows CodePage1252.
+ To make the mapping in most cases possible, I choosed
+ most similar chars or at least the BULLET. Chars that
+ do not have a direct match are marked with '***'
+
+ The Windows codepage 1252 contains the ISO 8859-1 "Latin 1" codepage,
+ with some additional printable characters in the range (0x80 - 0x9F),
+ that is reserved to control codes in the ISO 8859-1 character table.
+
+In all Mac OS encodings, character codes 0x00-0x7F are identical to ASCII
+
+*/
+
+
+
+ZCONST unsigned char MacRoman_to_WinCP1252[128] = {
+/* Win CP1252 UniCode UniCode Names */
+ 0xC4 , /* 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS */
+ 0xC5 , /* 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE */
+ 0xC7 , /* 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA */
+ 0xC9 , /* 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE */
+ 0xD1 , /* 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE */
+ 0xD6 , /* 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS */
+ 0xDC , /* 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS */
+ 0xE1 , /* 0x00E1 #LATIN SMALL LETTER A WITH ACUTE */
+ 0xE0 , /* 0x00E0 #LATIN SMALL LETTER A WITH GRAVE */
+ 0xE2 , /* 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ 0xE4 , /* 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS */
+ 0xE3 , /* 0x00E3 #LATIN SMALL LETTER A WITH TILDE */
+ 0xE5 , /* 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE */
+ 0xE7 , /* 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA */
+ 0xE9 , /* 0x00E9 #LATIN SMALL LETTER E WITH ACUTE */
+ 0xE8 , /* 0x00E8 #LATIN SMALL LETTER E WITH GRAVE */
+ 0xEA , /* 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ 0xEB , /* 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS */
+ 0xED , /* 0x00ED #LATIN SMALL LETTER I WITH ACUTE */
+ 0xEC , /* 0x00EC #LATIN SMALL LETTER I WITH GRAVE */
+ 0xEE , /* 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ 0xEF , /* 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS */
+ 0xF1 , /* 0x00F1 #LATIN SMALL LETTER N WITH TILDE */
+ 0xF3 , /* 0x00F3 #LATIN SMALL LETTER O WITH ACUTE */
+ 0xF2 , /* 0x00F2 #LATIN SMALL LETTER O WITH GRAVE */
+ 0xF4 , /* 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ 0xF6 , /* 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS */
+ 0xF5 , /* 0x00F5 #LATIN SMALL LETTER O WITH TILDE */
+ 0xFA , /* 0x00FA #LATIN SMALL LETTER U WITH ACUTE */
+ 0xF9 , /* 0x00F9 #LATIN SMALL LETTER U WITH GRAVE */
+ 0xFB , /* 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ 0xFC , /* 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS */
+ 0x86 , /* 0x2020 #DAGGER */
+ 0xB0 , /* 0x00B0 #DEGREE SIGN */
+ 0xA2 , /* 0x00A2 #CENT SIGN */
+ 0xA3 , /* 0x00A3 #POUND SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 #BULLET */
+ 0xB6 , /* 0x00B6 #PILCROW SIGN */
+ 0xDF , /* 0x00DF #LATIN SMALL LETTER SHARP S */
+ 0xAE , /* 0x00AE #REGISTERED SIGN */
+ 0xA9 , /* 0x00A9 #COPYRIGHT SIGN */
+ 0x99 , /* 0x2122 #TRADE MARK SIGN */
+ 0xB4 , /* 0x00B4 #ACUTE ACCENT */
+ 0xA8 , /* 0x00A8 #DIAERESIS */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xC6 , /* 0x00C6 #LATIN CAPITAL LETTER AE */
+ 0xD8 , /* 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xB1 , /* 0x00B1 #PLUS-MINUS SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x00A5 #YEN SIGN */
+ 0xB5 , /* 0x00B5 #MICRO SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xAA , /* 0x00AA #FEMININE ORDINAL INDICATOR */
+ 0xBA , /* 0x00BA #MASCULINE ORDINAL INDICATOR */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xE6 , /* 0x00E6 #LATIN SMALL LETTER AE */
+ 0xF8 , /* 0x00F8 #LATIN SMALL LETTER O WITH STROKE */
+ 0xBF , /* 0x00BF #INVERTED QUESTION MARK */
+ 0xA1 , /* 0x00A1 #INVERTED EXCLAMATION MARK */
+ 0xAC , /* 0x00AC #NOT SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x83 , /* 0x0192 #LATIN SMALL LETTER F WITH HOOK */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xAB , /* 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0xBB , /* 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0x85 , /* 0x2026 #HORIZONTAL ELLIPSIS */
+ 0xA0 , /* 0x00A0 #NO-BREAK SPACE */
+ 0xC0 , /* 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE */
+ 0xC3 , /* 0x00C3 #LATIN CAPITAL LETTER A WITH TILDE */
+ 0xD5 , /* 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x96 , /* 0x2013 #EN DASH */
+ 0x97 , /* 0x2014 #EM DASH */
+ 0x93 , /* 0x201C #LEFT DOUBLE QUOTATION MARK */
+ 0x94 , /* 0x201D #RIGHT DOUBLE QUOTATION MARK */
+ 0x91 , /* 0x2018 #LEFT SINGLE QUOTATION MARK */
+ 0x92 , /* 0x2019 #RIGHT SINGLE QUOTATION MARK */
+ 0xF7 , /* 0x00F7 #DIVISION SIGN */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xFF , /* 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS */
+ 0x9F , /* 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xA4 , /* 0x00A4 #CURRENCY SIGN */
+ 0x8B , /* 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+ 0x9B , /* 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x87 , /* 0x2021 #DOUBLE DAGGER */
+ 0xB7 , /* 0x00B7 #MIDDLE DOT */
+ 0x82 , /* 0x201A #SINGLE LOW-9 QUOTATION MARK */
+ 0x84 , /* 0x201E #DOUBLE LOW-9 QUOTATION MARK */
+ 0x89 , /* 0x2030 #PER MILLE SIGN */
+ 0xC2 , /* 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ 0xCA , /* 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ 0xC1 , /* 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE */
+ 0xCB , /* 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS */
+ 0xC8 , /* 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE */
+ 0xCD , /* 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE */
+ 0xCE , /* 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ 0xCF , /* 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS */
+ 0xCC , /* 0x00CC #LATIN CAPITAL LETTER I WITH GRAVE */
+ 0xD3 , /* 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE */
+ 0xD4 , /* 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xD2 , /* 0x00D2 #LATIN CAPITAL LETTER O WITH GRAVE */
+ 0xDA , /* 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE */
+ 0xDB , /* 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ 0xD9 , /* 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x88 , /* 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT */
+ 0x98 , /* 0x02DC #SMALL TILDE */
+ 0xAF , /* 0x00AF #MACRON */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0xB8 , /* 0x00B8 #CEDILLA */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 , /* 0x2022 # *** BULLET */
+ 0x95 /* 0x2022 # *** BULLET */
+ };
+
+
+
+ZCONST unsigned char WinCP1252_to_MacRoman[128] = {
+/* Mac Roman UniCode UniCode Names */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xE2 , /* 0x201A # SINGLE LOW-9 QUOTATION MARK */
+ 0xC4 , /* 0x0192 # LATIN SMALL LETTER F WITH HOOK */
+ 0xE3 , /* 0x201E # DOUBLE LOW-9 QUOTATION MARK */
+ 0xC9 , /* 0x2026 # HORIZONTAL ELLIPSIS */
+ 0xA0 , /* 0x2020 # DAGGER */
+ 0xE0 , /* 0x2021 # DOUBLE DAGGER */
+ 0xF6 , /* 0x02C6 # MODIFIER LETTER CIRCUMFLEX ACCENT */
+ 0xE4 , /* 0x2030 # PER MILLE SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xDC , /* 0x2039 # SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xD4 , /* 0x2018 # LEFT SINGLE QUOTATION MARK */
+ 0xD5 , /* 0x2019 # RIGHT SINGLE QUOTATION MARK */
+ 0xD2 , /* 0x201C # LEFT DOUBLE QUOTATION MARK */
+ 0xD3 , /* 0x201D # RIGHT DOUBLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # BULLET */
+ 0xD0 , /* 0x2013 # EN DASH */
+ 0xD1 , /* 0x2014 # EM DASH */
+ 0xF7 , /* 0x02DC # SMALL TILDE */
+ 0xAA , /* 0x2122 # TRADE MARK SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xDD , /* 0x203A # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xD9 , /* 0x0178 # LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ 0xCA , /* 0x00A0 # NO-BREAK SPACE */
+ 0xC1 , /* 0x00A1 # INVERTED EXCLAMATION MARK */
+ 0xA2 , /* 0x00A2 # CENT SIGN */
+ 0xA3 , /* 0x00A3 # POUND SIGN */
+ 0xDB , /* 0x00A4 # CURRENCY SIGN */
+ 0xB4 , /* 0x00A5 # YEN SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xAC , /* 0x00A8 # DIAERESIS */
+ 0xA9 , /* 0x00A9 # COPYRIGHT SIGN */
+ 0xBB , /* 0x00AA # FEMININE ORDINAL INDICATOR */
+ 0xC7 , /* 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0xC2 , /* 0x00AC # NOT SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA8 , /* 0x00AE # REGISTERED SIGN */
+ 0xF8 , /* 0x00AF # MACRON */
+ 0xA1 , /* 0x00B0 # DEGREE SIGN */
+ 0xB1 , /* 0x00B1 # PLUS-MINUS SIGN */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xAB , /* 0x00B4 # ACUTE ACCENT */
+ 0xB5 , /* 0x00B5 # MICRO SIGN */
+ 0xA6 , /* 0x00B6 # PILCROW SIGN */
+ 0xE1 , /* 0x00B7 # MIDDLE DOT */
+ 0xFC , /* 0x00B8 # CEDILLA */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xBC , /* 0x00BA # MASCULINE ORDINAL INDICATOR */
+ 0xC8 , /* 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xC0 , /* 0x00BF # INVERTED QUESTION MARK */
+ 0xCB , /* 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE */
+ 0xE7 , /* 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE */
+ 0xE5 , /* 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ 0xCC , /* 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE */
+ 0x80 , /* 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS */
+ 0x81 , /* 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE */
+ 0xAE , /* 0x00C6 # LATIN CAPITAL LETTER AE */
+ 0x82 , /* 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA */
+ 0xE9 , /* 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE */
+ 0x83 , /* 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE */
+ 0xE6 , /* 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ 0xE8 , /* 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS */
+ 0xED , /* 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE */
+ 0xEA , /* 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE */
+ 0xEB , /* 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ 0xEC , /* 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0x84 , /* 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE */
+ 0xF1 , /* 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE */
+ 0xEE , /* 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE */
+ 0xEF , /* 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ 0xCD , /* 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE */
+ 0x85 , /* 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xAF , /* 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE */
+ 0xF4 , /* 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE */
+ 0xF2 , /* 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE */
+ 0xF3 , /* 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ 0x86 , /* 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA7 , /* 0x00DF # LATIN SMALL LETTER SHARP S */
+ 0x88 , /* 0x00E0 # LATIN SMALL LETTER A WITH GRAVE */
+ 0x87 , /* 0x00E1 # LATIN SMALL LETTER A WITH ACUTE */
+ 0x89 , /* 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ 0x8B , /* 0x00E3 # LATIN SMALL LETTER A WITH TILDE */
+ 0x8A , /* 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS */
+ 0x8C , /* 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE */
+ 0xBE , /* 0x00E6 # LATIN SMALL LETTER AE */
+ 0x8D , /* 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA */
+ 0x8F , /* 0x00E8 # LATIN SMALL LETTER E WITH GRAVE */
+ 0x8E , /* 0x00E9 # LATIN SMALL LETTER E WITH ACUTE */
+ 0x90 , /* 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ 0x91 , /* 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS */
+ 0x93 , /* 0x00EC # LATIN SMALL LETTER I WITH GRAVE */
+ 0x92 , /* 0x00ED # LATIN SMALL LETTER I WITH ACUTE */
+ 0x94 , /* 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ 0x95 , /* 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0x96 , /* 0x00F1 # LATIN SMALL LETTER N WITH TILDE */
+ 0x98 , /* 0x00F2 # LATIN SMALL LETTER O WITH GRAVE */
+ 0x97 , /* 0x00F3 # LATIN SMALL LETTER O WITH ACUTE */
+ 0x99 , /* 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ 0x9B , /* 0x00F5 # LATIN SMALL LETTER O WITH TILDE */
+ 0x9A , /* 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS */
+ 0xD6 , /* 0x00F7 # DIVISION SIGN */
+ 0xBF , /* 0x00F8 # LATIN SMALL LETTER O WITH STROKE */
+ 0x9D , /* 0x00F9 # LATIN SMALL LETTER U WITH GRAVE */
+ 0x9C , /* 0x00FA # LATIN SMALL LETTER U WITH ACUTE */
+ 0x9E , /* 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ 0x9F , /* 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xA5 , /* 0x2022 # *** BULLET */
+ 0xD8 /* 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS */
+ };
+
+
+/*
+
+The following characters has no equivalent
+to each other:
+
+MacCodes
+164 0xA4 0x00A7 # SECTION SIGN
+253 0xFD 0x02DD # DOUBLE ACUTE ACCENT
+189 0xBD 0x03A9 # GREEK CAPITAL LETTER OMEGA
+185 0xB9 0x03C0 # GREEK SMALL LETTER PI
+255 0xFF 0x02C7 # CARON
+249 0xF9 0x02D8 # BREVE
+250 0xFA 0x02D9 # DOT ABOVE
+251 0xFB 0x02DA # RING ABOVE
+254 0xFE 0x02DB # OGONEK
+218 0xDA 0x2044 # FRACTION SLASH
+182 0xB6 0x2202 # PARTIAL DIFFERENTIAL
+198 0xC6 0x2206 # INCREMENT
+184 0xB8 0x220F # N-ARY PRODUCT
+183 0xB7 0x2211 # N-ARY SUMMATION
+195 0xC3 0x221A # SQUARE ROOT
+176 0xB0 0x221E # INFINITY
+186 0xBA 0x222B # INTEGRAL
+197 0xC5 0x2248 # ALMOST EQUAL TO
+173 0xAD 0x2260 # NOT EQUAL TO
+178 0xB2 0x2264 # LESS-THAN OR EQUAL TO
+179 0xB3 0x2265 # GREATER-THAN OR EQUAL TO
+215 0xD7 0x25CA # LOZENGE
+240 0xF0 0xF8FF # Apple logo
+222 0xDE 0xFB01 # LATIN SMALL LIGATURE FI
+223 0xDF 0xFB02 # LATIN SMALL LIGATURE FL
+245 0xF5 0x0131 # LATIN SMALL LETTER DOTLESS I
+206 0xCE 0x0152 # LATIN CAPITAL LIGATURE OE
+207 0xCF 0x0153 # LATIN SMALL LIGATURE OE
+
+WinCodes
+129 0x81 #UNDEFINED
+141 0x8D #UNDEFINED
+143 0x8F #UNDEFINED
+144 0x90 #UNDEFINED
+157 0x9D #UNDEFINED
+167 0xA7 0x00A7 #SECTION SIGN
+173 0xAD 0x00AD #SOFT HYPHEN
+178 0xB2 0x00B2 #SUPERSCRIPT TWO
+179 0xB3 0x00B3 #SUPERSCRIPT THREE
+185 0xB9 0x00B9 #SUPERSCRIPT ONE
+188 0xBC 0x00BC #VULGAR FRACTION ONE QUARTER
+189 0xBD 0x00BD #VULGAR FRACTION ONE HALF
+190 0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS
+208 0xD0 0x00D0 #LATIN CAPITAL LETTER ETH
+215 0xD7 0x00D7 #MULTIPLICATION SIGN
+221 0xDD 0x00DD #LATIN CAPITAL LETTER Y WITH ACUTE
+222 0xDE 0x00DE #LATIN CAPITAL LETTER THORN
+240 0xF0 0x00F0 #LATIN SMALL LETTER ETH
+253 0xFD 0x00FD #LATIN SMALL LETTER Y WITH ACUTE
+254 0xFE 0x00FE #LATIN SMALL LETTER THORN
+140 0x8C 0x0152 #LATIN CAPITAL LIGATURE OE
+156 0x9C 0x0153 #LATIN SMALL LIGATURE OE
+138 0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON
+154 0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON
+142 0x8E 0x017D #LATIN CAPITAL LETTER Z WITH CARON
+158 0x9E 0x017E #LATIN SMALL LETTER Z WITH CARON
+128 0x80 0x20AC #EURO SIGN
+166 0xA6 0x00A6 #BROKEN BAR
+
+
+*/
+
+
+
+
+#endif /* !__macos_charmap_h */
diff --git a/macos/source/extrafld.c b/macos/source/extrafld.c
new file mode 100644
index 0000000..a2efcdb
--- /dev/null
+++ b/macos/source/extrafld.c
@@ -0,0 +1,920 @@
+/*
+ Copyright (c) 1990-2002 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ extrafld.c
+
+ contains functions to build extra-fields.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <sound.h>
+#include "zip.h"
+#include "unixlike.h"
+#include "helpers.h"
+#include "pathname.h"
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'MAC3' extra field to the zlist data pointed to by z. */
+/* This is the (new) Info-zip extra block for Macintosh */
+#define EB_MAC3_HLEN 14 /* fixed length part of MAC3's header */
+#define EB_L_MAC3_FINFO_LEN 52 /* fixed part of MAC3 compressible data */
+
+#define EB_MAX_OF_VARDATA 1300 /* max possible datasize */
+
+#define EB_L_MAC3_SIZE (EB_HEADSIZE + EB_MAC3_HLEN)
+#define EB_C_MAC3_SIZE (EB_HEADSIZE + EB_MAC3_HLEN)
+
+/* maximum memcompress overhead is the sum of the compression header length */
+/* (6 = ush compression type, ulg CRC) and the worstcase deflate overhead */
+/* when uncompressible data are kept in 2 "stored" blocks (5 per block = */
+/* byte blocktype + 2 * ush blocklength) */
+#define MEMCOMPRESS_OVERHEAD (EB_MEMCMPR_HSIZ + EB_DEFLAT_EXTRA)
+
+#define EB_M3_FL_COMPRESS 0x00
+#define EB_M3_FL_DATFRK 0x01 /* data is data-fork */
+#define EB_M3_FL_NOCHANGE 0x02 /* filename will be not changed */
+#define EB_M3_FL_UNCMPR 0x04 /* data is 'natural' (not compressed) */
+#define EB_M3_FL_TIME64 0x08 /* time is coded in 64 bit */
+#define EB_M3_FL_NOUTC 0x10 /* only 'local' time-stamps are stored */
+
+
+#define EB_L_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(2))
+#define EB_C_UT_SIZE (EB_HEADSIZE + EB_UT_LEN(1))
+
+/* disable compressing of extra field
+#define MAC_EXTRAFLD_UNCMPR */
+
+/* ---------------------------------------------------------------------- */
+/* Add a 'JLEE' extra field to the zlist data pointed to by z. */
+/* This is the (old) Info-zip resource-fork extra block for Macintosh
+(last Revision 1996-09-22) Layout made by Johnny Lee, Code made by me :-) */
+#define EB_L_JLEE_LEN 40 /* fixed length of JLEE's header */
+#define EB_C_JLEE_LEN 40 /* fixed length of JLEE's header */
+
+#define EB_L_JLEE_SIZE (EB_HEADSIZE + EB_L_JLEE_LEN)
+#define EB_C_JLEE_SIZE (EB_HEADSIZE + EB_C_JLEE_LEN)
+
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+extern MacZipGlobals MacZip;
+extern unsigned long count_of_Zippedfiles;
+
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+static int add_UT_ef(struct zlist far *z, iztimes *z_utim);
+static int add_JLEE_ef(struct zlist far *z); /* old mac extra field */
+static int add_MAC3_ef(struct zlist far *z); /* new mac extra field */
+
+static void make_extrafield_JLEE(char *l_ef);
+static unsigned make_extrafield_MAC3(char *ef);
+static char *make_EF_Head_MAC3(char *ef, unsigned compsize, ulg attrsize,
+ unsigned flag);
+
+static void print_extra_info(void);
+void UserStop(void);
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/*
+* Set the extra-field's for each compressed file
+*/
+int set_extra_field(struct zlist far *z, iztimes *z_utim)
+ /* store full data in local header but just modification time stamp info
+ in central header */
+{
+ int retval;
+
+ Assert_it(z, "set_extra_field","")
+ Assert_it(z_utim, "set_extra_field","")
+
+ z_utim = z_utim;
+
+ /* Check to make sure z is valid. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* Resource forks are always binary */
+ if (MacZip.CurrentFork == ResourceFork) z->att = BINARY;
+
+ if (noisy)
+ {
+ count_of_Zippedfiles++;
+ InformProgress(MacZip.RawCountOfItems, count_of_Zippedfiles );
+ }
+
+ /*
+ PrintFileInfo();
+ */
+ switch (MacZip.MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ retval = add_JLEE_ef( z );
+ if (retval != ZE_OK) return retval;
+ break;
+ }
+ case NewZipMode_EF:
+ { /* */
+#ifdef USE_EF_UT_TIME
+ retval = add_UT_ef(z, z_utim);
+ if (retval != ZE_OK) return retval;
+#endif
+
+ retval = add_MAC3_ef( z );
+ if (retval != ZE_OK) return retval;
+ break;
+ }
+ default:
+ {
+ printerr("Unknown Extrafieldmode", -1, -1, __LINE__, __FILE__, "");
+ return ZE_LOGIC; /* function should never reach this point */
+ }
+ }
+
+ /* MacStat information is now outdated and
+ must be refreshed for the next file */
+ MacZip.isMacStatValid = false;
+
+ return ZE_OK;
+}
+
+
+
+
+#ifdef USE_EF_UT_TIME
+/*
+* Build and add the Unix time extra-field. This extra field
+* will be included be default. Johnny Lee's implementation does
+* not use this kind of extra-field.
+* All datas are in Intel (=little-endian) format
+
+ Extra field info:
+ - 'UT' - UNIX time extra field
+
+ This is done the same way ../unix/unix.c stores the 'UT'/'Ux' fields
+ (full data in local header, only modification time in central header),
+ with the 'M3' field added to the end and the size of the 'M3' field
+ in the central header.
+ */
+
+static int add_UT_ef(struct zlist far *z, iztimes *z_utim)
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+
+ Assert_it(z, "add_UT_ef","")
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ return ZE_OK; /* skip silently if no valid TZ info */
+#endif
+
+ /* We can't work if there's no entry to work on. */
+ if( z == NULL ) {
+ return ZE_LOGIC;
+ }
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + EB_L_UT_SIZE > EF_SIZE_MAX ||
+ z->cext + EB_C_UT_SIZE > EF_SIZE_MAX ) {
+ return ZE_MEM;
+ }
+
+ /* Allocate memory for the local and central extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_UT_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_UT_SIZE );
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_UT_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_UT_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /* Now add the local version of the field. */
+ *l_ef++ = 'U';
+ *l_ef++ = 'T';
+ *l_ef++ = (char)(EB_UT_LEN(2)); /* length of data in local EF */
+ *l_ef++ = (char)0;
+ *l_ef++ = (char)(EB_UT_FL_MTIME | EB_UT_FL_CTIME);
+ *l_ef++ = (char)(z_utim->mtime);
+ *l_ef++ = (char)(z_utim->mtime >> 8);
+ *l_ef++ = (char)(z_utim->mtime >> 16);
+ *l_ef++ = (char)(z_utim->mtime >> 24);
+ *l_ef++ = (char)(z_utim->ctime);
+ *l_ef++ = (char)(z_utim->ctime >> 8);
+ *l_ef++ = (char)(z_utim->ctime >> 16);
+ *l_ef++ = (char)(z_utim->ctime >> 24);
+
+ z->ext += EB_L_UT_SIZE;
+
+ /* Now add the central version. */
+ memcpy(c_ef, l_ef-EB_L_UT_SIZE, EB_C_UT_SIZE);
+ c_ef[EB_LEN] = (char)(EB_UT_LEN(1)); /* length of data in central EF */
+
+ z->cext += EB_C_UT_SIZE;
+
+ return ZE_OK;
+}
+#endif /* USE_EF_UT_TIME */
+
+
+/*
+* Build and add the old 'Johnny Lee' Mac extra field
+* All native datas are in Motorola (=big-endian) format
+*/
+
+static int add_JLEE_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+
+ Assert_it(z, "add_JLEE_ef","")
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if ( z->ext + EB_L_JLEE_SIZE > EF_SIZE_MAX ||
+ z->cext + EB_C_JLEE_SIZE > EF_SIZE_MAX ) {
+ return ZE_MEM;
+ }
+
+
+ /* Allocate memory for the local extra fields. */
+ if ( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext + EB_L_JLEE_SIZE );
+ } else {
+ l_ef = (char *)malloc( EB_L_JLEE_SIZE );
+ z->ext = 0;
+ }
+ if ( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ /* Allocate memory for the central extra fields. */
+ if ( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_JLEE_SIZE );
+ } else {
+ c_ef = (char *)malloc( EB_C_JLEE_SIZE );
+ z->cext = 0;
+ }
+ if ( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+
+ if ( verbose ) {
+ print_extra_info();
+ }
+
+
+ /**
+ **
+ ** Now add the local version of the field.
+ **/
+ make_extrafield_JLEE(l_ef);
+ z->ext += EB_L_JLEE_SIZE;
+
+
+ /**
+ **
+ ** Now add the central version of the field.
+ ** It's identical to the local header. I wonder why ??
+ * the first two fields are in Intel little-endian format */
+ make_extrafield_JLEE(c_ef);
+ z->cext += EB_C_JLEE_SIZE;
+
+ return ZE_OK;
+}
+
+
+
+/*
+* This is an implementation of Johnny Lee's extra field.
+* I never saw Johnny Lee's code. My code is based on the extra-field
+* definition mac (see latest appnote 1997-03-11)
+* and on some experiments with Johnny Lee's Zip-app version 1.0, 1992
+*
+* Unfortunately I cannot agree with his extra-field layout.
+* - it wasted space
+* - and holds not all mac-specific information
+*
+* I coded this extra-field only for testing purposes.
+* I don't want support this extra-field. Please use my implementation.
+*
+* This is old implementation of Johnny Lee's extra field.
+* All native datas are in Motorola (=big-endian) format
+*/
+
+static void make_extrafield_JLEE(char *ef)
+{
+
+ Assert_it(ef, "make_extrafield_JLEE","")
+
+ if (MacZip.isMacStatValid == false)
+ {
+ fprintf(stderr,"Internal Logic Error: [%d/%s] MacStat is out of sync !",
+ __LINE__,__FILE__);
+ exit(-1);
+ }
+
+
+ /* the first two fields are in Intel little-endian format */
+ *ef++ = 0xC8; /* tag for this extra block */
+ *ef++ = 0x07;
+
+ *ef++ = (char)(EB_L_JLEE_LEN); /* total data size this block */
+ *ef++ = (char)((EB_L_JLEE_LEN) >> 8);
+
+ /* the following fields are in motorola big-endian format */
+ *ef++ = 'J'; /* extra field signature: 4 Bytes */
+ *ef++ = 'L'; /* the old style extra field */
+ *ef++ = 'E';
+ *ef++ = 'E';
+
+ /* Start Macintosh Finder FInfo structure 16 Bytes overall */
+ /* Type: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+ /* Creator: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+ /* file Finder Flags: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+
+ /* Finders Icon position of a file*/
+ /* V/Y-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+ /* H/X-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+
+ /* fdFldr Folder containing file 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr);
+ /* End Macintosh Finder FInfo structure */
+
+
+ /* Creation-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat);
+
+ /* Modification-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat);
+
+ /* info Bits 4 Bytes */
+ *ef++ = 0x00;
+ *ef++ = 0x00;
+ *ef++ = 0x00;
+ if (MacZip.DataForkOnly)
+ { /* don't convert filename for unzipping */
+ /* 0x01 = data-fork; 0x00 = resource-fork */
+ *ef++ = (char) (MacZip.CurrentFork == DataFork) | 2;
+ }
+ else
+ {
+ *ef++ = (char) (MacZip.CurrentFork == DataFork);
+ }
+
+ /* file's location folder ID 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlParID);
+ /* ============ */
+ /* 40 Bytes */
+}
+
+
+
+/*
+* Build and add the new mac extra field
+* All native data are stored in Intel (=little-endian) format
+*/
+
+static int add_MAC3_ef( struct zlist far *z )
+{
+ char *l_ef = NULL;
+ char *c_ef = NULL;
+ char *attrbuff = NULL;
+ off_t attrsize = (EB_L_MAC3_FINFO_LEN + EB_MAX_OF_VARDATA);
+ char *compbuff = NULL;
+ unsigned compsize = 0;
+ unsigned m3_compr;
+ Boolean compress_data = true;
+
+ Assert_it(z, "add_MAC3_ef","")
+
+ UserStop(); /* do event handling and let the user stop */
+
+ if( verbose ) {
+ print_extra_info();
+ }
+
+ /* allocate temporary buffer to collect the Mac extra field info */
+ attrbuff = (char *)malloc( (size_t)attrsize );
+ if( attrbuff == NULL ) {
+ return ZE_MEM;
+ }
+
+ /* fill the attribute buffer, to get its (uncompressed) size */
+ attrsize = make_extrafield_MAC3(attrbuff);
+
+ if (compress_data &&
+ ((compbuff = (char *)malloc((size_t)attrsize + MEMCOMPRESS_OVERHEAD))
+ != NULL))
+ {
+ /* Try compressing the data */
+ compsize = memcompress( compbuff,
+ (size_t)attrsize + MEMCOMPRESS_OVERHEAD,
+ attrbuff,
+ (size_t)attrsize );
+#ifdef MAC_EXTRAFLD_UNCMPR
+ compsize = attrsize;
+#endif
+ }
+ else
+ {
+ compsize = attrsize;
+ }
+
+ if ((compsize) < attrsize) {
+ /* compression gained some space ... */
+ free(attrbuff); /* no longer needed ... */
+ m3_compr = EB_M3_FL_COMPRESS;
+ } else {
+ /* compression does not help, store data in uncompressed mode */
+ if (compbuff != NULL) free(compbuff);
+ compbuff = attrbuff;
+ compsize = attrsize;
+ m3_compr = EB_M3_FL_UNCMPR;
+ }
+
+ /* Check to make sure we've got enough room in the extra fields. */
+ if( z->ext + (EB_L_MAC3_SIZE + compsize) > EF_SIZE_MAX ||
+ z->cext + EB_C_MAC3_SIZE > EF_SIZE_MAX ) {
+ if (compbuff != NULL) free(compbuff);
+ return ZE_MEM;
+ }
+
+ /* Allocate memory for the local extra fields. */
+ if( z->extra && z->ext != 0 ) {
+ l_ef = (char *)realloc( z->extra, z->ext +
+ EB_L_MAC3_SIZE + compsize);
+ } else {
+ l_ef = (char *)malloc( EB_L_MAC3_SIZE + compsize);
+ z->ext = 0;
+ }
+ if( l_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->extra = l_ef;
+ l_ef += z->ext;
+
+ /* Allocate memory for the central extra fields. */
+ if( z->cextra && z->cext != 0 ) {
+ c_ef = (char *)realloc( z->cextra, z->cext + EB_C_MAC3_SIZE);
+ } else {
+ c_ef = (char *)malloc( EB_C_MAC3_SIZE );
+ z->cext = 0;
+ }
+ if( c_ef == NULL ) {
+ return ZE_MEM;
+ }
+ z->cextra = c_ef;
+ c_ef += z->cext;
+
+ /**
+ ** Now add the local version of the field.
+ **/
+ l_ef = make_EF_Head_MAC3(l_ef, compsize, (ulg)attrsize, m3_compr);
+ memcpy(l_ef, compbuff, (size_t)compsize);
+ l_ef += compsize;
+ z->ext += EB_L_MAC3_SIZE + compsize;
+ free(compbuff);
+ /* And the central version. */
+ c_ef = make_EF_Head_MAC3(c_ef, 0, (ulg)attrsize, m3_compr);
+ z->cext += EB_C_MAC3_SIZE;
+
+ return ZE_OK;
+}
+
+
+
+
+/*
+* Build the new mac local extra field header.
+* It's identical with the central extra field.
+* All native data are in Intel (=little-endian) format
+*/
+static char *make_EF_Head_MAC3(char *ef, unsigned compsize, ulg attrsize,
+ unsigned flag)
+{
+ unsigned info_flag = flag;
+
+ Assert_it(ef, "make_EF_Head_MAC3","")
+
+ /* the first four fields are in Intel little-endian format */
+ *ef++ = 'M'; /* tag for this extra block 2 Bytes */
+ *ef++ = '3';
+
+ /* total data size this block 2 Bytes */
+ *ef++ = (char) (EB_MAC3_HLEN + compsize);
+ *ef++ = (char)((EB_MAC3_HLEN + compsize) >> 8);
+
+ *ef++ = (char)(attrsize);
+ *ef++ = (char)(attrsize >> 8);
+ *ef++ = (char)(attrsize >> 16);
+ *ef++ = (char)(attrsize >> 24);
+
+ /* info Bits (flags) 2 Bytes */
+
+ if (MacZip.DataForkOnly) info_flag |= (EB_M3_FL_DATFRK |
+ EB_M3_FL_NOCHANGE);
+ if (MacZip.CurrentFork == DataFork) info_flag |= EB_M3_FL_DATFRK;
+ if (!MacZip.HaveGMToffset) info_flag |= EB_M3_FL_NOUTC;
+
+ *ef++ = (char)info_flag;
+ *ef++ = (char)0x00; /* reserved at the moment */
+
+ /* Note: Apple defined File-Type/-Creator as OSType ( =unsigned long,
+ see Universal Headers 3.1). However, File-Type/-Creator are a
+ unique four-character sequence. Therefore the byteorder of the
+ File-Type/-Creator are NOT changed. The native format is used. */
+
+ /* Type: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+ /* Creator: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+ return ef;
+}
+
+
+
+
+
+/*
+* Build the new mac local extra field header.
+* All native data are in Intel (=little-endian) format
+*/
+unsigned make_extrafield_MAC3(char *ef)
+{
+ char *ef_m3_begin = ef;
+ char *temp_Pathname;
+ char tmp_buffer[NAME_MAX];
+ unsigned char comment[257];
+ unsigned short FLength = 0;
+ unsigned short CLength = 0;
+ short tempFork;
+ OSErr err;
+
+ Assert_it(ef, "make_extrafield_MAC3","")
+
+ if (MacZip.isMacStatValid == false)
+ {
+ fprintf(stderr,
+ "Internal Logic Error: [%d/%s] MacStat is out of sync !",
+ __LINE__, __FILE__);
+ exit(-1);
+ }
+
+ /* Start Macintosh Finder FInfo structure except Type/Creator
+ (see make_EF_Head_MAC3()) 8 Bytes overall */
+
+ /* file Finder Flags: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags >> 8);
+
+ /* Finders Icon position of a file*/
+ /* V/Y-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v >> 8);
+
+ /* H/X-Position: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h >> 8);
+
+ /* fdFldr Folder containing file 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFldr >> 8);
+
+ /* End Macintosh Finder FInfo structure */
+
+ /* 8 Bytes so far ... */
+
+ /* Start Macintosh Finder FXInfo structure 16 Bytes overall */
+ /* Icon ID: 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdIconID);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdIconID >> 8);
+
+ /* unused: 6 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[0]);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[0] >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[1]);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[1] >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[2]);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdUnused[2] >> 8);
+ /* Script flag: 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdScript);
+ /* More flag bits: 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdXFlags);
+ /* Comment ID 2 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdComment);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdComment >> 8);
+
+ /* Home Dir ID: 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlXFndrInfo.fdPutAway >> 24);
+ /* End Macintosh Finder FXInfo structure */
+
+ /* 24 Bytes so far ... */
+
+ /* file version number 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFVersNum);
+
+ /* directory access rights 1 Byte */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioACUser);
+
+ /* Creation-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlCrDat >> 24);
+ /* Modification-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlMdDat >> 24);
+ /* Backup-time 4 Bytes */
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 8);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 16);
+ *ef++ = (char)(MacZip.fpb.hFileInfo.ioFlBkDat >> 24);
+
+ /* 38 Bytes so far ... */
+#ifdef USE_EF_UT_TIME
+ if (MacZip.HaveGMToffset) {
+ /* GMT-Offset times 12 Bytes */
+ *ef++ = (char)(MacZip.Cr_UTCoffs);
+ *ef++ = (char)(MacZip.Cr_UTCoffs >> 8);
+ *ef++ = (char)(MacZip.Cr_UTCoffs >> 16);
+ *ef++ = (char)(MacZip.Cr_UTCoffs >> 24);
+ *ef++ = (char)(MacZip.Md_UTCoffs);
+ *ef++ = (char)(MacZip.Md_UTCoffs >> 8);
+ *ef++ = (char)(MacZip.Md_UTCoffs >> 16);
+ *ef++ = (char)(MacZip.Md_UTCoffs >> 24);
+ *ef++ = (char)(MacZip.Bk_UTCoffs);
+ *ef++ = (char)(MacZip.Bk_UTCoffs >> 8);
+ *ef++ = (char)(MacZip.Bk_UTCoffs >> 16);
+ *ef++ = (char)(MacZip.Bk_UTCoffs >> 24);
+ }
+ /* 50 Bytes so far ... */
+#endif
+
+ /* Text Encoding Base (charset) 2 Bytes */
+ *ef++ = (char)(MacZip.CurrTextEncodingBase);
+ *ef++ = (char)(MacZip.CurrTextEncodingBase >> 8);
+ /* 52 Bytes so far ... */
+
+ /* MacZip.CurrentFork will be changed, so we have to save it */
+ tempFork = MacZip.CurrentFork;
+ if (!MacZip.StoreFullPath) {
+ temp_Pathname = StripPartialDir(tmp_buffer, MacZip.SearchDir,
+ MacZip.FullPath);
+ } else {
+ temp_Pathname = MacZip.FullPath;
+ }
+ MacZip.CurrentFork = tempFork;
+
+ FLength = strlen(temp_Pathname) + 1;
+ memcpy( ef, temp_Pathname, (size_t)FLength );
+ ef += FLength; /* make room for the string - variable length */
+
+ err = FSpLocationFromFullPath(strlen(MacZip.FullPath), MacZip.FullPath,
+ &MacZip.fileSpec);
+ printerr("FSpLocationFromFullPath:", err, err,
+ __LINE__, __FILE__, tmp_buffer);
+
+ err = FSpDTGetComment(&MacZip.fileSpec, comment);
+ printerr("FSpDTGetComment:", (err != -5012) && (err != 0), err,
+ __LINE__, __FILE__, "");
+ PToCCpy(comment,tmp_buffer);
+
+ CLength = strlen(tmp_buffer) + 1;
+ memcpy( ef, tmp_buffer, (size_t)CLength );
+ ef += CLength; /* make room for the string - variable length */
+
+ if (verbose) printf("\n comment: [%s]", tmp_buffer);
+
+ return (unsigned)(ef - ef_m3_begin);
+}
+
+
+
+
+
+
+/*
+* Print all native data of the new mac local extra field.
+* It's for debugging purposes and disabled by default.
+*/
+
+static void PrintFileInfo(void)
+{
+DateTimeRec MacTime;
+
+printf("\n\n---------------------------------------------"\
+ "----------------------------------");
+printf("\n FullPath Name = [%s]", MacZip.FullPath);
+printf("\n File Attributes = %s 0x%x %d",
+ sBit2Str(MacZip.fpb.hFileInfo.ioFlAttrib),
+ MacZip.fpb.hFileInfo.ioFlAttrib,
+ MacZip.fpb.hFileInfo.ioFlAttrib);
+printf("\n Enclosing Folder ID# = 0x%x %d",
+ MacZip.fpb.hFileInfo.ioFlParID,
+ MacZip.fpb.hFileInfo.ioFlParID);
+
+if (!MacZip.isDirectory)
+{
+printf("\n File Type = [%c%c%c%c] 0x%lx",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType);
+
+printf("\n File Creator = [%c%c%c%c] 0x%lx",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+
+printf("\n Data Fork :" );
+printf("\n Actual (Logical) Length = %d 0x%x ",
+ MacZip.fpb.hFileInfo.ioFlLgLen,
+ MacZip.fpb.hFileInfo.ioFlLgLen);
+printf("\n Allocated (Physical) Length = %d 0x%x",
+ MacZip.fpb.hFileInfo.ioFlPyLen,
+ MacZip.fpb.hFileInfo.ioFlPyLen);
+printf("\n Resource Fork :" );
+printf("\n Actual (Logical) Length = %d 0x%x",
+ MacZip.fpb.hFileInfo.ioFlRLgLen,
+ MacZip.fpb.hFileInfo.ioFlRLgLen );
+printf("\n Allocated (Physical) Length = %d 0x%x",
+ MacZip.fpb.hFileInfo.ioFlRPyLen,
+ MacZip.fpb.hFileInfo.ioFlRPyLen );
+}
+
+printf("\n Dates : ");
+
+SecondsToDate (MacZip.CreatDate, &MacTime);
+printf("\n Created = %4d/%2d/%2d %2d:%2d:%2d ",
+ MacTime.year,
+ MacTime.month,
+ MacTime.day,
+ MacTime.hour,
+ MacTime.minute,
+ MacTime.second);
+
+SecondsToDate (MacZip.BackDate, &MacTime);
+printf("\n Backup = %4d/%2d/%2d %2d:%2d:%2d ",
+ MacTime.year,
+ MacTime.month,
+ MacTime.day,
+ MacTime.hour,
+ MacTime.minute,
+ MacTime.second);
+
+SecondsToDate (MacZip.ModDate, &MacTime);
+printf("\n Modified = %4d/%2d/%2d %2d:%2d:%2d ",
+ MacTime.year,
+ MacTime.month,
+ MacTime.day,
+ MacTime.hour,
+ MacTime.minute,
+ MacTime.second);
+
+if (!MacZip.isDirectory)
+{
+printf("\n Finder Flags : %s 0x%x %d",
+ sBit2Str(MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags),
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags);
+printf("\n Finder Icon Position = X: %d 0x%x ",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.h);
+printf("\n Y: %d 0x%x ",
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdLocation.v);
+}
+else
+{
+printf("\n Finder Flags : %s 0x%x %d",
+ sBit2Str(MacZip.fpb.dirInfo.ioDrUsrWds.frFlags),
+ MacZip.fpb.dirInfo.ioDrUsrWds.frFlags,
+ MacZip.fpb.dirInfo.ioDrUsrWds.frFlags);
+printf("\n Finder Icon Position = X: %d 0x%x ",
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.h,
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.h);
+printf("\n Y: %d 0x%x ",
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.v,
+ MacZip.fpb.dirInfo.ioDrUsrWds.frLocation.v);
+}
+
+printf("\n----------------------------------------------------"\
+ "---------------------------\n");
+}
+
+
+
+/*
+* If the switch '-v' is used, print some more info.
+*/
+
+static void print_extra_info(void)
+{
+char Fork[20];
+
+if (MacZip.CurrentFork == DataFork) sstrcpy(Fork,"<DataFork>");
+else sstrcpy(Fork,"<ResourceFork>");
+
+printf("\n%16s [%c%c%c%c] [%c%c%c%c]",Fork,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType,
+
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 24,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 16,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator >> 8,
+ MacZip.fpb.hFileInfo.ioFlFndrInfo.fdCreator);
+}
diff --git a/macos/source/getenv.c b/macos/source/getenv.c
new file mode 100644
index 0000000..3b22327
--- /dev/null
+++ b/macos/source/getenv.c
@@ -0,0 +1,398 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*
+
+This file implements the getenv() function.
+
+# Background:
+# Under Unix: Each Process (= running Program) has a set of
+# associated variables. The variables are called enviroment
+# variables and, together, constitute the process environment.
+# These variables include the search path, the terminal type,
+# and the user's login name.
+
+# Unfortunatelly the MacOS has no equivalent. So we need
+# a file to define the environment variables.
+# Name of this file is "MacZip.Env". It can be placed
+# in the current folder of MacZip or in the
+# preference folder of the system disk.
+# If MacZip founds the "MacZip.Env" file in the current
+# the folder of MacZip the "MacZip.Env" file in the
+# preference folder will be ignored.
+
+# An environment variable has a name and a value:
+# Name=Value
+# Note: Spaces are significant:
+# ZIPOPT=-r and
+# ZIPOPT = -r are different !!!
+
+
+ */
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unix.h>
+#include <Files.h>
+#include <Folders.h>
+
+#include "pathname.h"
+#include "helpers.h"
+
+/*****************************************************************************/
+/* Module level Vars */
+/*****************************************************************************/
+
+static char ListAllKeyValues = 0;
+static unsigned LineNumber = 0;
+static char CompletePath[NAME_MAX];
+Boolean IgnoreEnvironment = false; /* used by dialog.c and initfunc.c
+ of the Mainapp */
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+typedef struct _EnviromentPair {
+ char *key;
+ char *value;
+} EnviromentPair;
+
+
+#define MAX_COMMAND 1024
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+
+int get_char(FILE *file);
+void unget_char(int ch,FILE *file);
+int get_string(char *string,int size, FILE *file, char *terms);
+void skip_comments(FILE *file);
+char *load_entry(FILE *file);
+char *getenv(const char *name);
+EnviromentPair *ParseLine(char *line);
+OSErr FSpFindFolder_Name(short vRefNum, OSType folderType,
+ Boolean createFolder,FSSpec *spec, unsigned char *name);
+FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode);
+void ShowAllKeyValues(void);
+void Set_LineNum(unsigned ln);
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/* get_string(str, max, file, termstr) : like fgets() but
+ * (1) has terminator string which should include \n
+ * (2) will always leave room for the null
+ * (3) uses get_char() so LineNumber will be accurate
+ * (4) returns EOF or terminating character, whichever
+ */
+int get_string(char *string, int size, FILE *file, char *terms)
+{
+ int ch;
+
+ while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) {
+ if (size > 1) {
+ *string++ = (char) ch;
+ size--;
+ }
+ }
+
+ if (size > 0)
+ {
+ *string = '\0';
+ }
+
+ return ch;
+}
+
+
+
+
+void Set_LineNum(unsigned ln)
+{
+ LineNumber = ln;
+}
+
+
+
+/* get_char(file) : like getc() but increment LineNumber on newlines
+ */
+int get_char(FILE *file)
+{
+ int ch;
+
+ ch = getc(file);
+ if (ch == '\n')
+ {
+ Set_LineNum(LineNumber + 1);
+ }
+
+ return ch;
+}
+
+
+
+
+/* skip_comments(file) : read past comment (if any)
+ */
+void skip_comments(FILE *file)
+{
+ int ch;
+
+ while (EOF != (ch = get_char(file)))
+ {
+ /* ch is now the first character of a line.
+ */
+
+ while (ch == ' ' || ch == '\t')
+ {
+ ch = get_char(file);
+ }
+
+ if (ch == EOF)
+ {
+ break;
+ }
+
+ /* ch is now the first non-blank character of a line.
+ */
+
+ if (ch != '\n' && ch != '#')
+ {
+ break;
+ }
+
+ /* ch must be a newline or comment as first non-blank
+ * character on a line.
+ */
+
+ while (ch != '\n' && ch != EOF)
+ {
+ ch = get_char(file);
+ }
+
+ /* ch is now the newline of a line which we're going to
+ * ignore.
+ */
+ }
+
+ if (ch != EOF)
+ {
+ unget_char(ch, file);
+ }
+}
+
+
+
+
+/* unget_char(ch, file) : like ungetc but do LineNumber processing
+ */
+void unget_char(int ch, FILE *file)
+{
+ ungetc(ch, file);
+ if (ch == '\n')
+ {
+ Set_LineNum(LineNumber - 1);
+ }
+}
+
+
+/* this function reads one file entry -- the next -- from a file.
+* it skips any leading blank lines, ignores comments, and returns
+* NULL if for any reason the entry can't be read and parsed.
+*/
+
+char *load_entry(FILE *file)
+{
+ int ch;
+ static char cmd[MAX_COMMAND];
+
+ skip_comments(file);
+
+ ch = get_string(cmd, MAX_COMMAND, file, "\n");
+
+ if (ch == EOF)
+ {
+ return NULL;
+ }
+
+ return cmd;
+}
+
+
+
+
+
+EnviromentPair *ParseLine(char *line)
+{
+char *tmpPtr;
+static EnviromentPair *Env;
+unsigned short length = strlen(line);
+
+Env->key = "";
+Env->value = "";
+
+for (tmpPtr = line; *tmpPtr; tmpPtr++)
+ {
+ if (*tmpPtr == '=')
+ {
+ *tmpPtr = 0;
+ Env->key = line;
+ if (strlen(Env->key) < length)
+ {
+ Env->value = ++tmpPtr;
+ }
+ return Env;
+ }
+ }
+return Env;
+}
+
+
+
+
+
+char *getenv(const char *name)
+{
+FILE *fp;
+char *LineStr = NULL;
+EnviromentPair *Env1;
+FSSpec spec;
+OSErr err;
+
+if (IgnoreEnvironment)
+ return NULL; /* user wants to ignore the environment vars */
+
+if (name == NULL)
+ return NULL;
+
+GetCompletePath(CompletePath,"MacZip.Env",&spec,&err);
+
+/* try open the file in the current folder */
+fp = FSp_fopen(&spec,"r");
+if (fp == NULL)
+ { /* Okey, lets try open the file in the preference folder */
+ FSpFindFolder_Name(
+ kOnSystemDisk,
+ kPreferencesFolderType,
+ kDontCreateFolder,
+ &spec,
+ "\pMacZip.Env");
+ fp = FSp_fopen(&spec,"r");
+ if (fp == NULL)
+ {
+ return NULL; /* there is no enviroment-file */
+ }
+ }
+
+LineStr = load_entry(fp);
+while (LineStr != NULL)
+ { /* parse the file line by line */
+ Env1 = ParseLine(LineStr);
+ if (strlen(Env1->value) > 0)
+ { /* we found a key/value pair */
+ if (ListAllKeyValues)
+ printf("\n Line:%3d [%s] = [%s]",LineNumber,Env1->key,Env1->value);
+ if (stricmp(name,Env1->key) == 0)
+ { /* we found the value of a given key */
+ return Env1->value;
+ }
+ }
+ LineStr = load_entry(fp); /* read next line */
+ }
+fclose(fp);
+
+return NULL;
+}
+
+
+
+
+
+OSErr FSpFindFolder_Name(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec, /* Pointer to resulting directory. */
+ unsigned char *name) /* Name of the file in the folder */
+{
+ short foundVRefNum;
+ long foundDirID;
+ OSErr err;
+
+ err = FindFolder(vRefNum, folderType, createFolder,
+ &foundVRefNum, &foundDirID);
+ if (err != noErr)
+ {
+ return err;
+ }
+
+ err = FSMakeFSSpec(foundVRefNum, foundDirID, name, spec);
+ return err;
+}
+
+
+
+
+void ShowAllKeyValues(void)
+{
+OSErr err;
+FSSpec spec;
+Boolean tmpIgnoreEnvironment = IgnoreEnvironment;
+
+ListAllKeyValues = 1;
+IgnoreEnvironment = false;
+
+GetCompletePath(CompletePath,"MacZip.Env",&spec,&err);
+if (err != 0)
+ { /* Okey, lets try open the file in the preference folder */
+ FSpFindFolder_Name(
+ kOnSystemDisk,
+ kPreferencesFolderType,
+ kDontCreateFolder,
+ &spec,
+ "\pMacZip.Env");
+ GetFullPathFromSpec(CompletePath,&spec, &err);
+ if (err != 0)
+ {
+ return; /* there is no enviroment-file */
+ }
+ }
+
+printf("\nLocation of the current \"MacZip.Env\" file:\n [%s]",CompletePath);
+
+printf("\n\nList of all environment variables\n");
+getenv(" ");
+printf("\n\nEnd\n\n");
+
+/* restore used variables */
+ListAllKeyValues = 0;
+LineNumber = 0;
+IgnoreEnvironment = tmpIgnoreEnvironment;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/macos/source/helpers.c b/macos/source/helpers.c
new file mode 100644
index 0000000..36b5bef
--- /dev/null
+++ b/macos/source/helpers.c
@@ -0,0 +1,479 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ helpers.c
+
+ Some useful functions Used by unzip and zip.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include "zip.h"
+#include <ctype.h>
+#include <time.h>
+#include <sound.h>
+
+#include "macstuff.h"
+#include "helpers.h"
+#include "pathname.h"
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+
+extern int noisy;
+extern char MacPathEnd;
+extern char *zipfile; /* filename of the Zipfile */
+extern char *tempzip; /* Temporary zip file name */
+extern ZCONST unsigned char MacRoman_to_WinCP1252[128];
+
+
+static char argStr[1024];
+static char *argv[MAX_ARGS + 1];
+
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/*
+** Copy a C string to a Pascal string
+**
+*/
+
+unsigned char *CToPCpy(unsigned char *pstr, char *cstr)
+{
+ register char *dptr;
+ register unsigned len;
+
+ len=0;
+ dptr=(char *)pstr+1;
+ while (len<255 && (*dptr++ = *cstr++)!='\0') ++len;
+ *pstr= (unsigned char)len;
+ return pstr;
+}
+
+
+/*
+** Copy a Pascal string to a C string
+**
+*/
+
+char *PToCCpy(unsigned char *pstr, char *cstr)
+{
+strncpy(cstr, (char *) &pstr[1], *pstr);
+ cstr[pstr[0]] = '\0'; /* set endmarker for c-string */
+return cstr;
+}
+
+
+/*
+** strcpy() and strcat() work-alikes which allow overlapping buffers.
+*/
+
+char *sstrcpy(char *to,const char *from)
+{
+ memmove(to, from, 1+strlen(from));
+ return to;
+}
+
+char *sstrcat(char *to,const char *from)
+{
+ sstrcpy(to + strlen(to), from);
+ return to;
+}
+
+
+
+/*
+** Alloc memory and init it
+**
+*/
+
+char *StrCalloc(unsigned short size)
+{
+char *strPtr = NULL;
+
+if ((strPtr = calloc(size, sizeof(char))) == NULL)
+ printerr("StrCalloc failed:", -1, size, __LINE__, __FILE__, "");
+
+Assert_it(strPtr,"strPtr == NULL","")
+return strPtr;
+}
+
+
+
+/*
+** Release only non NULL pointers
+**
+*/
+
+char *StrFree(char *strPtr)
+{
+
+if (strPtr != NULL)
+ {
+ free(strPtr);
+ }
+
+return NULL;
+}
+
+
+
+
+/*
+** Return a value in a binary string
+**
+*/
+
+char *sBit2Str(unsigned short value)
+{
+ static char str[sizeof(value)*8];
+ int biz = 16;
+ int strwid = 16;
+ int i, j;
+ char *tempPtr = str;
+
+ j = strwid - (biz + (biz >> 2)- (biz % 4 ? 0 : 1));
+
+ for (i = 0; i < j; i++) {
+ *tempPtr++ = ' ';
+ }
+ while (--biz >= 0)
+ {
+ *tempPtr++ = ((value >> biz) & 1) + '0';
+ if (!(biz % 4) && biz) {
+ *tempPtr++ = ' ';
+ }
+ }
+ *tempPtr = '\0';
+
+ return str;
+}
+
+
+
+
+/*
+** Parse commandline style arguments
+**
+*/
+
+int ParseArguments(char *s, char ***arg)
+{
+ int n = 1, Quote = 0;
+ char *p = s, *p1, c;
+
+ argv[0] = GetAppName();
+
+ *arg = argv;
+
+ p1 = (char *) argStr;
+ while ((c = *p++) != 0) {
+ if (c==' ') continue;
+ argv[n++] = p1;
+ if (n > MAX_ARGS)
+ return (n-1);
+ do {
+ if (c=='\\' && *p++)
+ c = *p++;
+ else
+ if ((c=='"') || (c == '\'')) {
+ if (!Quote) {
+ Quote = c;
+ continue;
+ }
+ if (c == Quote) {
+ Quote = 0;
+ continue;
+ }
+ }
+ *p1++ = c;
+ } while (*p && ((c = *p++) != ' ' || Quote));
+ *p1++ = '\0';
+ }
+ return n;
+}
+
+
+
+/*
+** Print commandline style arguments
+**
+*/
+
+void PrintArguments(int argc, char **argv)
+{
+
+printf("\n Arguments:");
+printf("\n --------------------------");
+
+while(--argc >= 0)
+ printf("\n argc: %d argv: [%s]", argc, &*argv[argc]);
+
+printf("\n --------------------------\n\n");
+return;
+}
+
+
+
+/*
+** return some error-msg on file-system
+**
+*/
+
+int PrintUserHFSerr(int cond, int err, char *msg2)
+{
+char *msg;
+
+if (cond != 0)
+ {
+ switch (err)
+ {
+ case -35:
+ msg = "No such Volume";
+ break;
+
+ case -56:
+ msg = "No such Drive";
+ break;
+
+ case -37:
+ msg = "Bad Volume Name";
+ break;
+
+ case -49:
+ msg = "File is already open for writing";
+ break;
+
+ case -43:
+ msg = "Directory/File not found";
+ break;
+
+ case -120:
+ msg = "Directory/File not found or incomplete pathname";
+ break;
+
+ default: return err;
+ }
+ fprintf(stderr, "\n\n Error: %s ->%s", msg, msg2);
+ exit(err);
+ }
+
+return 0;
+}
+
+
+
+/*
+** Check mounted volumes and return number of volumes
+** with the same name.
+*/
+
+short CheckMountedVolumes(char *FullPath)
+{
+FSSpec volumes[50]; /* 50 Volumes should be enough */
+char VolumeName[257], volume[257];
+short actVolCount, volIndex = 1, VolCount = 0;
+OSErr err;
+int i;
+
+GetVolumeFromPath(FullPath, VolumeName);
+
+err = OnLine(volumes, 50, &actVolCount, &volIndex);
+printerr("OnLine:", (err != -35) && (err != 0), err, __LINE__, __FILE__, "");
+
+for (i=0; i < actVolCount; i++)
+ {
+ PToCCpy(volumes[i].name,volume);
+ if (stricmp(volume, VolumeName) == 0) VolCount++;
+ }
+printerr("OnLine: ", (VolCount == 0), VolCount, __LINE__, __FILE__, FullPath);
+
+return VolCount;
+}
+
+
+
+
+
+
+
+
+/*
+** compares strings, ignoring differences in case
+**
+*/
+
+int stricmp(const char *p1, const char *p2)
+{
+int diff;
+
+while (*p1 && *p2)
+ {
+ if (*p1 != *p2)
+ {
+ if (isalpha(*p1) && isalpha(*p2))
+ {
+ diff = toupper(*p1) - toupper(*p2);
+ if (diff) return diff;
+ }
+ else break;
+ }
+ p1++;
+ p2++;
+ }
+return *p1 - *p2;
+}
+
+
+
+/*
+** Convert the MacOS-Strings (Filenames/Findercomments) to a most compatible.
+** These strings will be stored in the public area of the zip-archive.
+** Every foreign platform (outside macos) will access these strings
+** for extraction.
+*/
+
+void MakeCompatibleString(char *MacOS_Str,
+ const char SpcChar1, const char SpcChar2,
+ const char SpcChar3, const char SpcChar4,
+ short CurrTextEncodingBase)
+{
+ char *tmpPtr;
+ register uch curch;
+
+ Assert_it(MacOS_Str,"MakeCompatibleString MacOS_Str == NULL","")
+ for (tmpPtr = MacOS_Str; (curch = *tmpPtr) != '\0'; tmpPtr++)
+ {
+ if (curch == SpcChar1)
+ *tmpPtr = SpcChar2;
+ else
+ if (curch == SpcChar3)
+ *tmpPtr = SpcChar4;
+ else /* default */
+ /* now convert from MacRoman to ISO-8859-1 */
+ /* but convert only if MacRoman is activ */
+ if ((CurrTextEncodingBase == kTextEncodingMacRoman) &&
+ (curch > 127))
+ {
+ *tmpPtr = (char)MacRoman_to_WinCP1252[curch - 128];
+ }
+ } /* end for */
+}
+
+
+
+
+Boolean CheckForSwitch(char *Switch, int argc, char **argv)
+{
+ char *p; /* steps through option arguments */
+ int i; /* arg counter, root directory flag */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (argv[i][1])
+ {
+ for (p = argv[i]+1; *p; p++)
+ {
+ if (*p == Switch[0])
+ {
+ return true;
+ }
+ if ((Switch[1] != NULL) &&
+ ((*p == Switch[0]) && (*p == Switch[1])))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+return false;
+}
+
+
+
+
+
+
+
+#if (defined(USE_SIOUX) || defined(MACUNZIP_STANDALONE))
+
+/*
+** checks the condition and returns an error-msg
+** this function is for internal use only
+*/
+
+OSErr printerr(const char *msg, int cond, int err, int line, char *file,
+ const char *msg2)
+{
+
+if (cond != 0)
+ {
+ fprintf(stderr, "\nint err: %d: %s %d [%d/%s] {%s}\n", clock(), msg, err,
+ line, file, msg2);
+ }
+
+return cond;
+}
+
+
+/*
+fake-functions:
+Not Implemented for metrowerks SIOUX
+*/
+
+void leftStatusString(char *status)
+{
+status = status;
+}
+
+
+void rightStatusString(char *status)
+{
+status = status;
+}
+
+
+
+void DoWarnUserDupVol( char *FullPath )
+{
+ char VolName[257];
+ GetVolumeFromPath(FullPath, VolName);
+
+ printf("\n There are more than one volume that has the same name !!\n");
+
+ printf("\n Volume: %s\n",VolName);
+
+ printf("\n This port has one weak point:");
+ printf("\n It is based on pathnames. As you may be already know:");
+ printf("\n Pathnames are not unique on a Mac !");
+ printf("\n MacZip has problems to find the correct location of");
+ printf("\n the archive or the files.\n");
+
+ printf("\n My (Big) recommendation: Name all your volumes with an");
+ printf("\n unique name and MacZip will run without any problem.");
+}
+
+
+
+#endif
diff --git a/macos/source/helpers.h b/macos/source/helpers.h
new file mode 100644
index 0000000..a9df5d8
--- /dev/null
+++ b/macos/source/helpers.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef HELPERS_H
+#define HELPERS_H 1
+
+ /* Convert a C string to a Pascal string */
+unsigned char *CToPCpy(unsigned char *pstr, char *cstr);
+
+ /* Convert a Pascal string to a C string */
+char *PToCCpy(unsigned char *pstr, char *cstr);
+
+char *sstrcpy(char *to,const char *from);
+char *sstrcat(char *to,const char *from);
+
+char *StrCalloc(unsigned short size);
+char *StrFree(char *strPtr);
+
+char *sBit2Str(unsigned short value);
+
+void print_extra_info(void);
+
+int ParseArguments(char *s, char ***arg);
+void PrintArguments(int argc, char **argv);
+
+Boolean IsZipFile(char *name);
+OSErr printerr(const char *msg, int cond, int err, int line, char *file,
+ const char *msg2);
+int PrintUserHFSerr(int cond, int err, char *msg2);
+
+short CheckMountedVolumes(char *FullPath);
+void DoWarnUserDupVol(char *path);
+
+void PrintFileInfo(void);
+
+int stricmp(const char *p1, const char *p2);
+void leftStatusString(char *status);
+void rightStatusString(char *status);
+
+Boolean isZipFile(FSSpec *fileToOpen);
+
+unsigned long MacFileDate_to_UTime(unsigned long mactime);
+Boolean CheckForSwitch(char *Switch, int argc, char **argv);
+
+void MakeCompatibleString(char *MacOS_Str,
+ const char SpcChar1, const char SpcChar2,
+ const char SpcChar3, const char SpcChar4,
+ short CurrTextEncodingBase);
+
+#define MAX_ARGS 25
+
+#endif /* HELPERS_H */
diff --git a/macos/source/macglob.h b/macos/source/macglob.h
new file mode 100644
index 0000000..17415e1
--- /dev/null
+++ b/macos/source/macglob.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef _MACGLOBAL_
+#define _MACGLOBAL_
+
+#include <time.h>
+
+/*
+all my Global vars are defined here.
+*/
+
+#define ResourceFork -1
+#define DataFork 1
+#define NoFork 0
+
+/*
+all my Global vars are defined here.
+*/
+typedef struct {
+ short CurrentFork;
+ short MacZipMode;
+
+ Boolean isMacStatValid;
+ Boolean HaveGMToffset;
+
+ short CurrTextEncodingBase;
+
+ /* info about the current file */
+ Boolean isDirectory;
+ char FullPath[NAME_MAX];
+ char FileName[NAME_MAX];
+ FSSpec fileSpec;
+
+ long dirID;
+ CInfoPBRec fpb;
+
+ /* time infos about the current file */
+ time_t CreatDate;
+ time_t ModDate;
+ time_t BackDate;
+ long Cr_UTCoffs; /* offset "local time - UTC" for CreatDate */
+ long Md_UTCoffs; /* offset "local time - UTC" for ModDate */
+ long Bk_UTCoffs; /* offset "local time - UTC" for BackDate */
+
+ /* some statistics over all*/
+ unsigned long FoundFiles;
+ unsigned long FoundDirectories;
+ unsigned long RawCountOfItems;
+ unsigned long BytesOfData;
+
+ unsigned long attrsize;
+
+ /* some switches and user parameters */
+ Boolean DataForkOnly;
+ Boolean StoreFullPath;
+ Boolean StoreFoldersAlso; /* internal switch is true if '-r' is set */
+ unsigned short SearchLevels;
+ char Pattern[NAME_MAX];
+ Boolean IncludeInvisible;
+ Boolean StatingProgress;
+
+ char SearchDir[NAME_MAX];
+ char CurrentPath[NAME_MAX];
+
+ /* current zip / tempzip file info */
+ char ZipFullPath[NAME_MAX];
+
+ FSSpec ZipFileSpec;
+ unsigned long ZipFileType;
+ char TempZipFullPath[NAME_MAX];
+ FSSpec TempZipFileSpec;
+
+} MacZipGlobals;
+
+
+
+void UserStop(void);
+
+
+#endif
diff --git a/macos/source/macopen.c b/macos/source/macopen.c
new file mode 100644
index 0000000..9e18730
--- /dev/null
+++ b/macos/source/macopen.c
@@ -0,0 +1,363 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*** macopen.c; stuff only required for the Mac port ***/
+
+#include "zip.h"
+
+#include <string.h>
+#include <fcntl.h>
+#include <unix.h>
+#include <sound.h>
+
+#include "helpers.h"
+#include "pathname.h"
+#include "macopen.h"
+#include "macstuff.h"
+
+#ifdef MACZIP
+#include "macglob.h"
+
+extern char *zipfile; /* filename of the Zipfile */
+extern char *tempzip; /* Temporary zip file name */
+
+extern MacZipGlobals MacZip;
+
+
+/* don't include "osdep.h" otherwise we will trap into endless loop */
+#undef open
+#undef fopen
+
+
+
+FILE *MacFopen(const char *path, const char *mode)
+{
+static char TruncPath[NAME_MAX];
+OSErr err = 0;
+
+AssertStr(path,path)
+
+ /* open zipfile or tempzip */
+if (strcmp(zipfile,path) == 0)
+ {
+ GetCompletePath(MacZip.ZipFullPath,path,&MacZip.ZipFileSpec,&err);
+ err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+ printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);
+ if (CheckMountedVolumes(MacZip.ZipFullPath) > 1)
+ DoWarnUserDupVol(MacZip.ZipFullPath);
+
+ /* tempfile should appear in the same directory of the zipfile
+ -> save path of zipfile */
+ TruncFilename(TruncPath, MacZip.ZipFullPath);
+ return fopen(MacZip.ZipFullPath, mode);
+ }
+
+if (strcmp(tempzip,path) == 0)
+ { /* add path of zipfile */
+ sstrcat(TruncPath,tempzip);
+ GetCompletePath(MacZip.TempZipFullPath,TruncPath,&MacZip.TempZipFileSpec,&err);
+ err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+ printerr("GetCompletePath:",err,err,__LINE__,__FILE__,path);
+
+ return fopen(MacZip.TempZipFullPath, mode);
+ }
+
+printerr("MacFopen:",err,err,__LINE__,__FILE__,path);
+return NULL;
+}
+
+
+
+
+int MacOpen(const char *path,int oflag, ...)
+{
+char RealFname[NAME_MAX];
+
+AssertStr(path,path)
+
+RfDfFilen2Real(RealFname,path, MacZip.MacZipMode, MacZip.DataForkOnly, &MacZip.CurrentFork);
+/* convert to real fname and init global var MacZip.CurrentFork !! */
+
+switch (MacZip.CurrentFork)
+ {
+ case DataFork:
+ {
+ return my_open(RealFname, oflag);
+ break;
+ }
+ case ResourceFork:
+ {
+ return my_open( RealFname, oflag | O_RSRC);
+ break;
+ }
+ default: /* for now (Zip ver 2.3b) MacOpen should never reach this point */
+ { /* however, this may change in the future ... */
+ printerr("open: no resource / datafork ",-1,-1,__LINE__,__FILE__,path);
+ return -1;
+ }
+ }
+}
+
+
+#ifdef muell
+ /* file to delete */
+int destroy(char *path)
+{
+static char lastpath[NAME_MAX];
+char currpath[NAME_MAX];
+static Boolean FirstCall = true;
+long rc;
+
+AssertStr(path,path)
+
+RfDfFilen2Real(currpath, path, MacZip.MacZipMode, MacZip.DataForkOnly, &MacZip.CurrentFork);
+
+if (FirstCall == true)
+ {
+ FirstCall = false;
+ rc = remove(currpath);
+ }
+else if (strcmp(currpath,lastpath) == 0) return 0; /* ignore, file is already deleted */
+ else rc = remove(currpath); /* we are removeing all the files only by their
+ pathname this is dangerous on a mac but there is no other way without
+ a complete rewrite of the port */
+
+strcpy(lastpath,currpath);
+
+return rc;
+}
+#endif
+
+
+
+
+/* this function replaces the function "replace()" defined in fileio.c */
+int replace(char *new_f, char *temp_f) /* destination and source file names */
+{
+OSErr err = 0;
+char newfname[NAME_MAX];
+
+AssertStr(new_f,new_f)
+AssertStr(temp_f,temp_f)
+
+UserStop();
+
+GetFilename(newfname, new_f);
+
+/* check zipfile name and tempfile name */
+/* we are using this function only for replacing the tempfile with the zipfile */
+if ((strcmp(zipfile,new_f) == 0) || (strcmp(tempzip,temp_f) == 0))
+ {
+ remove(MacZip.ZipFullPath);
+
+ /* rename the temp file to the zip file */
+ err = rename(MacZip.TempZipFullPath,MacZip.ZipFullPath);
+ printerr("rename:",err,err,__LINE__,__FILE__,MacZip.TempZipFullPath);
+if (err != 0) return ZE_CREAT;
+ else return ZE_OK;
+ }
+else return ZE_CREAT;
+}
+
+
+
+ /* file to delete */
+ /* we are removeing all the files only by their
+ pathname this is dangerous on a mac but there is no
+ other way without a complete rewrite of the port */
+
+int destroy(char *path)
+{
+static char lastpath[NAME_MAX];
+static FSSpec trashfolder;
+static Boolean FirstCall = true;
+static char Num = 0;
+static Boolean Immediate_File_Deletion = false;
+char currpath[NAME_MAX], *envptr;
+FSSpec fileToDelete;
+OSErr err;
+
+/* init this function */
+if ((path == NULL) ||
+ (strlen(path) == 0))
+ {
+ FirstCall = true;
+ Num = 0;
+ return -1;
+ }
+
+UserStop();
+
+RfDfFilen2Real(currpath, path, MacZip.MacZipMode,
+ MacZip.DataForkOnly, &MacZip.CurrentFork);
+GetCompletePath(currpath,currpath,&fileToDelete, &err);
+
+if (FirstCall == true)
+ {
+ FirstCall = false;
+ sstrcpy(lastpath,currpath);
+ err = FSpFindFolder(fileToDelete.vRefNum, kTrashFolderType,
+ kDontCreateFolder,&trashfolder);
+ printerr("FSpFindFolder:",err,err,__LINE__,__FILE__,path);
+
+ envptr = getenv("Immediate_File_Deletion");
+ if (!(envptr == (char *)NULL || *envptr == '\0'))
+ {
+ if (stricmp(envptr,"yes") == 0)
+ Immediate_File_Deletion = true;
+ else
+ Immediate_File_Deletion = false;
+ }
+
+ if (Immediate_File_Deletion)
+ {
+ err = FSpDelete(&fileToDelete);
+ return err;
+ }
+
+ err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+ fileToDelete.name, trashfolder.parID, trashfolder.name);
+ return err;
+ }
+
+if (strcmp(currpath,lastpath) == 0)
+ {
+ return 0; /* ignore, file is already deleted */
+ }
+else
+ {
+
+ if (Immediate_File_Deletion)
+ {
+ err = FSpDelete(&fileToDelete);
+ sstrcpy(lastpath,path);
+ return err;
+ }
+
+ err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+ fileToDelete.name, trashfolder.parID, trashfolder.name);
+
+ /* -48 = file is already existing so we have to rename it before
+ moving the file */
+ if (err == -48)
+ {
+ Num++;
+ if (fileToDelete.name[0] >= 28) /* cut filename if to long */
+ fileToDelete.name[0] = 28;
+ P2CStr(fileToDelete.name);
+ sprintf(currpath,"%s~%d",(char *)fileToDelete.name,Num);
+ C2PStr(currpath);
+ C2PStr((char *)fileToDelete.name);
+ err = HRename (fileToDelete.vRefNum, fileToDelete.parID,
+ fileToDelete.name, (unsigned char *) currpath);
+ err = CatMove (fileToDelete.vRefNum, fileToDelete.parID,
+ (unsigned char *) currpath, trashfolder.parID,
+ trashfolder.name);
+ }
+ }
+
+sstrcpy(lastpath,currpath);
+return err;
+}
+
+
+
+#endif /* #ifdef MACZIP */
+
+
+
+
+/*
+ * int open(const char *path, int oflag)
+ *
+ * Opens a file stream.
+ */
+int my_open(char *path, int oflag)
+{
+ FSSpec spec;
+ char permission;
+ HParamBlockRec hpb;
+ OSErr err, errno;
+ Boolean targetIsFolder, wasAliased;
+
+ AssertStr(path,path)
+
+ /* Setup permission */
+ if ((oflag & 0x03) == O_RDWR)
+ permission = fsRdWrPerm;
+ else
+ permission = (oflag & O_RDONLY) ? fsRdPerm : 0 + (oflag & O_WRONLY) ? fsWrPerm : 0;
+
+ FSpLocationFromFullPath(strlen(path),path, &spec);
+ if ((oflag & (O_ALIAS | O_NRESOLVE)) == 0)
+ ResolveAliasFile(&spec, true, &targetIsFolder, &wasAliased);
+ hpb.fileParam.ioNamePtr = spec.name;
+ hpb.fileParam.ioVRefNum = spec.vRefNum;
+ hpb.fileParam.ioDirID = spec.parID;
+ hpb.ioParam.ioPermssn = permission;
+
+ if (oflag & O_RSRC) /* open the resource fork of the file */
+ err = PBHOpenRFSync(&hpb);
+ else /* open the data fork of the file */
+ err = PBHOpenDFSync(&hpb);
+
+ if ((err == fnfErr) && (oflag & O_CREAT)) {
+ hpb.fileParam.ioFlVersNum = 0;
+ err = PBHCreateSync(&hpb);
+ if (err == noErr) {
+ /* Set the finder info */
+ unsigned long secs;
+ unsigned long isbinary = oflag & O_BINARY;
+
+ hpb.fileParam.ioFlFndrInfo.fdType = '\?\?\?\?';
+ hpb.fileParam.ioFlFndrInfo.fdCreator = '\?\?\?\?';
+ hpb.fileParam.ioFlFndrInfo.fdFlags = 0;
+ if (oflag & O_ALIAS) /* set the alias bit */
+ hpb.fileParam.ioFlFndrInfo.fdFlags = kIsAlias;
+ else /* clear all flags */
+ hpb.fileParam.ioFlFndrInfo.fdFlags = 0;
+
+ GetDateTime(&secs);
+ hpb.fileParam.ioFlCrDat = hpb.fileParam.ioFlMdDat = secs;
+ PBHSetFInfoSync(&hpb);
+ }
+
+ if (err && (err != dupFNErr)) {
+ errno = err; return -1;
+ }
+
+ if (oflag & O_RSRC) /* open the resource fork of the file */
+ err = PBHOpenRFSync(&hpb);
+ else /* open the data fork of the file */
+ err = PBHOpenDFSync(&hpb);
+ }
+
+ if (err && (err != dupFNErr) && (err != opWrErr)) {
+ errno = err; return -1;
+ }
+
+ if (oflag & O_TRUNC) {
+ IOParam pb;
+
+ pb.ioRefNum = hpb.ioParam.ioRefNum;
+ pb.ioMisc = 0L;
+ err = PBSetEOFSync((ParmBlkPtr)&pb);
+ if (err != noErr) {
+ errno = err; return -1;
+ }
+ }
+
+ if (oflag & O_APPEND) lseek(hpb.ioParam.ioRefNum,0,SEEK_END);
+
+ return (hpb.ioParam.ioRefNum);
+}
+
+
+
+
+
diff --git a/macos/source/macopen.h b/macos/source/macopen.h
new file mode 100644
index 0000000..152bceb
--- /dev/null
+++ b/macos/source/macopen.h
@@ -0,0 +1,21 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef __MACOPEN_H__
+#define __MACOPEN_H__
+
+#include <stdio.h>
+#include <Files.h>
+
+
+FILE *MacFopen(const char *path, const char *mode);
+int MacOpen(const char *path, int oflag, ...);
+
+int my_open(char *path, int oflag);
+
+#endif /* __MACOPEN_H__ */
diff --git a/macos/source/macos.c b/macos/source/macos.c
new file mode 100644
index 0000000..935c9a1
--- /dev/null
+++ b/macos/source/macos.c
@@ -0,0 +1,1079 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ macos.c
+
+ Macintosh-specific routines for use with Info-ZIP's Zip 2.3 and later.
+
+ ---------------------------------------------------------------------------*/
+
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include "zip.h"
+
+#include "revision.h"
+#include "crypt.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sound.h>
+
+#include <unistd.h>
+
+#include <Strings.h>
+#include <setjmp.h>
+
+/* #include "charmap.h" */
+#include "helpers.h"
+#include "macstuff.h"
+#include "pathname.h"
+#include "recurse.h"
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+#define PATH_END MacPathEnd
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+int error_level; /* used only in ziperr() */
+
+
+/* Note: sizeof() returns the size of this allusion
+ 13 is current length of "XtraStuf.mac:" */
+extern const char ResourceMark[13]; /* var is initialized in file pathname.c */
+
+
+extern jmp_buf EnvForExit;
+MacZipGlobals MacZip;
+
+unsigned long count_of_Zippedfiles = 0;
+
+
+/*****************************************************************************/
+/* Module level Vars */
+/*****************************************************************************/
+
+static const char MacPathEnd = ':'; /* the Macintosh dir separator */
+
+/* Inform Progress vars */
+long estTicksToFinish;
+long createTime;
+long updateTicks;
+
+static char *Time_Est_strings[] = {
+ "Zipping Files; Items done:",
+ "More than 24 hours",
+ "More than %s hours",
+ "About %s hours, %s minutes",
+ "About an hour",
+ "Less than an hour",
+ "About %s minutes, %s seconds",
+ "About a minute",
+ "Less than a minute",
+ "About %s seconds",
+ "About a second",
+ "About 1 minute, %s seconds"};
+
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+int DoCurrentDir(void);
+
+void DoAboutBox(void);
+void DoQuit(void);
+void DoEventLoop(void);
+
+void ZipInitAllVars(void);
+void UserStop(void);
+Boolean IsZipFile(char *name);
+
+static long EstimateCompletionTime(const long progressMax,
+ const long progressSoFar, unsigned char percent);
+static void UpdateTimeToComplete(void);
+
+
+
+
+#ifdef USE_SIOUX
+#include <sioux.h>
+void DoWarnUserDupVol( char *FullPath );
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+/*
+** Standalone Unzip with Metrowerks SIOUX starts here
+**
+*/
+int main(int argc, char **argv)
+{
+ int return_code;
+
+ SIOUXSettings.asktosaveonclose = FALSE;
+ SIOUXSettings.showstatusline = TRUE;
+
+ SIOUXSettings.columns = 100;
+ SIOUXSettings.rows = 40;
+
+ /* 30 = MacZip Johnny Lee's; 40 = new (my) MacZip */
+ MacZip.MacZipMode = NewZipMode_EF;
+
+ argc = ccommand(&argv);
+ if (verbose) PrintArguments(argc, argv);
+
+ ZipInitAllVars();
+
+ return_code = zipmain(argc, argv);
+
+ if (verbose) printf("\n\n Finish");
+ return return_code;
+}
+
+
+
+/*
+** SIOUX needs no extra event handling
+**
+*/
+
+void UserStop(void)
+{
+};
+
+
+
+
+/*
+** Password enter function '*' printed for each char
+**
+*/
+
+int macgetch(void)
+{
+ WindowPtr whichWindow;
+ EventRecord theEvent;
+ char c; /* one-byte buffer for read() to use */
+
+ do {
+ SystemTask();
+ if (!GetNextEvent(everyEvent, &theEvent))
+ theEvent.what = nullEvent;
+ else {
+ switch (theEvent.what) {
+ case keyDown:
+ c = theEvent.message & charCodeMask;
+ break;
+ case mouseDown:
+ if (FindWindow(theEvent.where, &whichWindow) ==
+ inSysWindow)
+ SystemClick(&theEvent, whichWindow);
+ break;
+ case updateEvt:
+ break;
+ }
+ }
+ } while (theEvent.what != keyDown);
+
+ printf("*");
+ fflush(stdout);
+
+ return (int)c;
+}
+
+#endif
+
+
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+/*
+** Print Compilers version and compile time/date
+**
+*/
+
+void version_local()
+{
+/* prints e.g:
+Compiled with Metrowerks CodeWarrior version 2000 for PowerPC Processor
+ compile time: Feb 4 1998 17:49:49.
+*/
+
+static ZCONST char CompiledWith[] =
+ "\n\nCompiled with %s %x for %s \n %s %s %s.\n\n";
+
+ printf(CompiledWith,
+
+
+#ifdef __MWERKS__
+ " Metrowerks CodeWarrior version", __MWERKS__,
+#endif
+
+
+#ifdef __MC68K__
+ " MC68K Processor",
+#else
+ " PowerPC Processor",
+#endif
+
+#ifdef __DATE__
+ "compile time: ", __DATE__, __TIME__
+#else
+ "", "", ""
+#endif
+ );
+} /* end function version_local() */
+
+
+
+
+
+/*
+** Deletes a dir if the switch '-m' is used
+**
+*/
+
+int deletedir(char *path)
+{
+static char Num = 0;
+static FSSpec trashfolder;
+static Boolean FirstCall = true;
+static Boolean Immediate_File_Deletion = false;
+OSErr err;
+FSSpec dirToDelete;
+char currpath[NAME_MAX], *envptr;
+CInfoPBRec fpb;
+
+/* init this function */
+if ((path == NULL) ||
+ (strlen(path) == 0))
+ {
+ Num = 0;
+ FirstCall = true;
+ return -1;
+ }
+
+UserStop();
+
+GetCompletePath(currpath,path,&dirToDelete, &err);
+
+if (FirstCall == true)
+ {
+ FirstCall = false;
+ envptr = getenv("Immediate_File_Deletion");
+ if (!(envptr == (char *)NULL || *envptr == '\0'))
+ {
+ if (stricmp(envptr,"yes") == 0)
+ Immediate_File_Deletion = true;
+ else
+ Immediate_File_Deletion = false;
+ }
+ err = FSpFindFolder(dirToDelete.vRefNum, kTrashFolderType,
+ kDontCreateFolder,&trashfolder);
+ printerr("FSpFindFolder:",err,err,__LINE__,__FILE__,path);
+ }
+
+ fpb.dirInfo.ioNamePtr = dirToDelete.name;
+ fpb.dirInfo.ioVRefNum = dirToDelete.vRefNum;
+ fpb.dirInfo.ioDrDirID = dirToDelete.parID;
+ fpb.dirInfo.ioFDirIndex = 0;
+
+ err = PBGetCatInfoSync(&fpb);
+ printerr("PBGetCatInfo deletedir ", err, err,
+ __LINE__, __FILE__, "");
+
+if (fpb.dirInfo.ioDrNmFls > 0)
+ {
+ return 0; /* do not move / delete folders which are not empty */
+ }
+
+if (Immediate_File_Deletion)
+ {
+ err = FSpDelete(&dirToDelete);
+ return err;
+ }
+
+err = CatMove (dirToDelete.vRefNum, dirToDelete.parID,
+ dirToDelete.name, trashfolder.parID, trashfolder.name);
+
+/* -48 = file is already existing so we have to rename it before
+ moving the file */
+if (err == -48)
+ {
+ Num++;
+ if (dirToDelete.name[0] >= 28) /* cut foldername if to long */
+ dirToDelete.name[0] = 28;
+ P2CStr(dirToDelete.name);
+ sprintf(currpath,"%s~%d",(char *)dirToDelete.name,Num);
+ C2PStr(currpath);
+ C2PStr((char *)dirToDelete.name);
+ err = HRename (dirToDelete.vRefNum, dirToDelete.parID,
+ dirToDelete.name, (unsigned char *) currpath);
+
+ err = CatMove (dirToDelete.vRefNum, dirToDelete.parID,
+ (unsigned char *) currpath, trashfolder.parID,
+ trashfolder.name);
+ }
+
+return err;
+}
+
+
+
+
+/*
+** Set the file-type so the archive will get the correct icon, type
+** and creator code.
+*/
+
+void setfiletype(char *new_f, unsigned long Creator, unsigned long Type)
+{
+OSErr err;
+
+if (strcmp(zipfile, new_f) == 0)
+ err = FSpChangeCreatorType(&MacZip.ZipFileSpec, Creator, Type);
+printerr("FSpChangeCreatorType:", err, err, __LINE__, __FILE__, new_f);
+
+return;
+}
+
+
+
+
+
+/*
+** Convert the external (native) filename into Zip's internal Unix compatible
+** name space.
+*/
+
+char *ex2in(char *externalFilen, int isdir, int *pdosflag)
+/* char *externalFilen external file name */
+/* int isdir input: externalFilen is a directory */
+/* int *pdosflag output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *internalFilen; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+ char *Pathname;
+ char buffer[NAME_MAX];
+ int dosflag;
+
+ AssertStr(externalFilen, externalFilen)
+ AssertBool(isdir,"")
+
+ dosflag = dosify; /* default for non-DOS and non-OS/2 */
+
+ /* Find starting point in name before doing malloc */
+ for (t = externalFilen; *t == PATH_END; t++)
+ ;
+
+ if (!MacZip.StoreFullPath)
+ {
+ Pathname = StripPartialDir(buffer, MacZip.SearchDir,t);
+ }
+ else
+ {
+ Pathname = t;
+ }
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ if (!pathput)
+ {
+ t = last(Pathname, PATH_END);
+ }
+ else t = Pathname;
+
+ /* Malloc space for internal name and copy it */
+ if ((internalFilen = malloc(strlen(t) + 10 + strlen(ResourceMark) )) == NULL)
+ return NULL;
+
+ sstrcpy(internalFilen, t);
+
+ /* we have to eliminate illegal chars:
+ * The name space for Mac filenames and Zip filenames (unix style names)
+ * do both include all printable extended-ASCII characters. The only
+ * difference we have to take care of is the single special character
+ * used as path delimiter:
+ * ':' on MacOS and '/' on Unix and '\' on Dos.
+ * So, to convert between Mac filenames and Unix filenames without any
+ * loss of information, we simply interchange ':' and '/'. Additionally,
+ * we try to convert the coding of the extended-ASCII characters into
+ * InfoZip's standard ISO 8859-1 codepage table.
+ */
+ MakeCompatibleString(internalFilen, ':', '/', '/', ':',
+ MacZip.CurrTextEncodingBase);
+
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosflag;
+
+ if (isdir)
+ {
+ return internalFilen; /* avoid warning on unused variable */
+ }
+
+ if (dosify)
+ {
+ msname(internalFilen);
+ printf("\n ex2in: %s",internalFilen);
+ }
+
+ return internalFilen;
+}
+
+
+
+/*
+** Collect all filenames. Go through all directories
+**
+*/
+
+int wild(char *Pathpat)
+ /* path/pattern to match */
+/* If not in exclude mode, expand the pattern based on the contents of the
+ file system. Return an error code in the ZE_ class. */
+{
+FSSpec Spec;
+char fullpath[NAME_MAX];
+OSErr err;
+
+AssertStr(Pathpat, Pathpat);
+
+if (noisy) printf("%s \n\n",GetZipVersionsInfo());
+
+if (extra_fields == 0)
+ {
+ MacZip.DataForkOnly = true;
+ }
+
+/* for switch '-R' -> '.' means current dir */
+if (strcmp(Pathpat,".") == 0) sstrcpy(Pathpat,"*");
+
+sstrcpy(MacZip.Pattern,Pathpat);
+
+if (recurse)
+ {
+ MacZip.StoreFoldersAlso = true;
+ MacZip.SearchLevels = 0; /* if 0 we aren't checking levels */
+ }
+else
+ {
+ MacZip.StoreFoldersAlso = false;
+ MacZip.SearchLevels = 1;
+ }
+
+/* make complete path */
+GetCompletePath(fullpath, MacZip.Pattern, &Spec,&err);
+err = PrintUserHFSerr((err != -43) && (err != 0), err, MacZip.Pattern);
+printerr("GetCompletePath:", err, err, __LINE__, __FILE__, fullpath);
+
+/* extract the filepattern */
+GetFilename(MacZip.Pattern, fullpath);
+
+/* extract Path and get FSSpec of search-path */
+/* get FSSpec of search-path ; we need a dir to start
+ searching for filenames */
+TruncFilename(MacZip.SearchDir, fullpath);
+GetCompletePath(MacZip.SearchDir, MacZip.SearchDir, &Spec,&err);
+
+if (noisy) {
+ if (MacZip.SearchLevels == 0)
+ {
+ printf("\nSearch Pattern: [%s] Levels: all", MacZip.Pattern);
+ }
+ else
+ {
+ printf("\nSearch Pattern: [%s] Levels: %d", MacZip.Pattern,
+ MacZip.SearchLevels);
+ }
+ printf("\nSearch Path: [%s]", MacZip.SearchDir);
+ printf("\nZip-File: [%s] \n",MacZip.ZipFullPath);
+
+}
+
+/* we are working only with pathnames;
+ * this can cause big problems on a mac ...
+ */
+if (CheckMountedVolumes(MacZip.SearchDir) > 1)
+ DoWarnUserDupVol(MacZip.SearchDir);
+
+/* start getting all filenames */
+err = FSpRecurseDirectory(&Spec, MacZip.SearchLevels);
+printerr("FSpRecurseDirectory:", err, err, __LINE__, __FILE__, "");
+
+return ZE_OK;
+}
+
+
+
+/*
+** Convert the internal filename into a external (native).
+** The user will see this modified filename.
+** For more performance:
+** I do not completly switch back to the native macos filename.
+** The user will still see directory separator '/' and the converted
+** charset.
+*/
+
+char *in2ex(char *n) /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+
+ AssertStr(n,n)
+
+ if ((x = malloc(strlen(n) + 1)) == NULL)
+ return NULL;
+
+ RfDfFilen2Real(x, n, MacZip.MacZipMode, MacZip.DataForkOnly,
+ &MacZip.CurrentFork);
+
+ return x;
+}
+
+
+
+
+/*
+** Process on filenames. This function will be called to collect
+** the filenames.
+*/
+
+int procname(char *filename, /* name to process */
+ int caseflag) /* true to force case-sensitive match
+ (always false on a Mac) */
+/* Process a name . Return
+ an error code in the ZE_ class. */
+{
+ int rc; /* matched flag */
+
+AssertBool(caseflag,"caseflag")
+AssertStr(filename,filename)
+
+ /* add or remove name of file */
+rc = newname(filename, MacZip.isDirectory, caseflag);
+
+return rc;
+}
+
+
+
+
+ulg filetime(
+char *f, /* name of file to get info on */
+ulg *a, /* return value: file attributes */
+long *n, /* return value: file size */
+iztimes *t) /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+
+ AssertStr(f,f)
+
+ if (strlen(f) == 0) return 0;
+
+ if (SSTAT(f, &s) != 0)
+ /* Accept about any file kind including directories
+ * (stored with trailing : with -r option)
+ */
+ return 0;
+
+ if (a != NULL) {
+ *a = ((ulg)s.st_mode << 16) | !(s.st_mode & S_IWRITE);
+ if (MacZip.isDirectory) {
+ *a |= MSDOS_DIR_ATTR;
+ }
+ }
+ if (n != NULL)
+ *n = (s.st_mode & UNX_IFMT) == UNX_IFREG ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime; /* on Mac, st_ctime contains creation time! */
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+
+
+void stamp(char *f, ulg d)
+/* char *f; name of file to change */
+/* ulg d; dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ time_t u[2]; /* argument for utime() */
+
+f = f;
+
+ /* Convert DOS time to time_t format in u */
+
+ u[0] = u[1] = dos2unixtime(d);
+/* utime(f, u); */
+}
+
+
+
+
+/*
+** return only the longest part of the path:
+** second parameter: Volume:test folder:second folder:
+** third parameter: Volume:test folder:second folder:third folder:file
+** result will be: third folder:file
+** first parameter: contains string buffer that will be used to prepend
+** the "resource mark" part in front of the result when
+** a resource fork is processed in "M3" mode.
+**
+*/
+
+char *StripPartialDir(char *CompletePath,
+ const char *PartialPath, const char *FullPath)
+{
+const char *tmpPtr1 = PartialPath;
+const char *tmpPtr2 = FullPath;
+int result;
+
+Assert_it(CompletePath,"StripPartialDir","")
+AssertStrNoOverlap(FullPath,PartialPath,PartialPath)
+
+if (MacZip.DataForkOnly)
+ {
+ tmpPtr2 += strlen(tmpPtr1);
+ return (char *)tmpPtr2;
+ }
+
+switch (MacZip.MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ tmpPtr2 += strlen(tmpPtr1);
+ return (char *)tmpPtr2;
+ break;
+ }
+
+ case NewZipMode_EF:
+ { /* determine Fork type */
+ result = strncmp(FullPath, ResourceMark, sizeof(ResourceMark)-2);
+ if (result != 0)
+ { /* data fork */
+ MacZip.CurrentFork = DataFork;
+ tmpPtr2 += strlen(tmpPtr1);
+ return (char *)tmpPtr2;
+ }
+ else
+ { /* resource fork */
+ MacZip.CurrentFork = ResourceFork;
+ sstrcpy(CompletePath, ResourceMark);
+ tmpPtr2 += strlen(tmpPtr1);
+ tmpPtr2 += sizeof(ResourceMark);
+ sstrcat(CompletePath, tmpPtr2);
+ return (char *)CompletePath;
+ }
+ break;
+ }
+ }
+
+ return NULL; /* function should never reach this point */
+}
+
+
+
+
+/*
+** Init all global variables
+** Must be called for each zip-run
+*/
+
+void ZipInitAllVars(void)
+{
+getcwd(MacZip.CurrentPath, sizeof(MacZip.CurrentPath));
+/* MacZip.MacZipMode = JohnnyLee_EF; */
+MacZip.MacZipMode = NewZipMode_EF;
+
+MacZip.DataForkOnly = false;
+MacZip.CurrentFork = NoFork;
+
+MacZip.StoreFoldersAlso = false;
+
+MacZip.FoundFiles = 0;
+MacZip.FoundDirectories = 0;
+MacZip.RawCountOfItems = 0;
+MacZip.BytesOfData = 0;
+
+MacZip.StoreFullPath = false;
+MacZip.StatingProgress = false;
+MacZip.IncludeInvisible = false;
+
+MacZip.isMacStatValid = false;
+
+MacZip.CurrTextEncodingBase = FontScript();
+
+MacZip.HaveGMToffset = false;
+
+createTime = TickCount();
+estTicksToFinish = -1;
+updateTicks = 0;
+
+/* init some functions */
+IsZipFile(NULL);
+
+destroy(NULL);
+deletedir(NULL);
+ShowCounter(true);
+
+extra_fields = 1;
+error_level = 0;
+count_of_Zippedfiles = 0;
+}
+
+
+
+
+/*
+** Get the findercomment and store it as file-comment in the Zip-file
+**
+*/
+char *GetComment(char *filename)
+{
+OSErr err;
+static char buffer[NAME_MAX];
+char buffer2[NAME_MAX];
+char *tmpPtr;
+
+if (filename == NULL) return NULL;
+
+ /* now we can convert Unix-Path in HFS-Path */
+for (tmpPtr = filename; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == '/')
+ *tmpPtr = ':';
+
+if (MacZip.StoreFullPath)
+ { /* filename is already a fullpath */
+ sstrcpy(buffer,filename);
+ }
+else
+ { /* make a fullpath */
+ sstrcpy(buffer,MacZip.SearchDir);
+ sstrcat(buffer,filename);
+ }
+
+/* make fullpath and get FSSpec */
+/* Unfortunately: I get only the converted filename here */
+/* so filenames with extended characters can not be found */
+GetCompletePath(buffer2,buffer, &MacZip.fileSpec, &err);
+printerr("GetCompletePath:",(err != -43) && (err != -120) && (err != 0) ,
+ err,__LINE__,__FILE__,buffer);
+
+err = FSpDTGetComment(&MacZip.fileSpec, (unsigned char *) buffer);
+printerr("FSpDTGetComment:", (err != -5012) && (err != 0), err,
+ __LINE__, __FILE__, filename);
+P2CStr((unsigned char *) buffer);
+if (err == -5012) return NULL; /* no finder-comments found */
+
+if (noisy) printf("\n%32s -> %s",filename, buffer);
+/*
+Beside the script change we need only to change 0x0d in 0x0a
+so the last two arguments are not needed and does nothing.
+*/
+MakeCompatibleString(buffer, 0x0d, 0x0a, ' ', ' ',
+ MacZip.CurrTextEncodingBase);
+
+return buffer;
+}
+
+
+
+
+/*
+** Print a progress indicator for stating the files
+**
+*/
+
+void PrintStatProgress(char *msg)
+{
+
+if (!noisy) return; /* do no output if noisy is false */
+
+MacZip.StatingProgress = true;
+
+if (strcmp(msg,"done") == 0)
+ {
+ MacZip.StatingProgress = false;
+ printf("\n ... done \n\n");
+ }
+else printf("\n %s",msg);
+
+}
+
+
+
+
+void InformProgress(const long progressMax, const long progressSoFar )
+{
+int curr_percent;
+char no_time[5] = "...";
+
+curr_percent = percent(progressMax, progressSoFar);
+
+if (curr_percent < 95)
+ {
+ estTicksToFinish = EstimateCompletionTime(progressMax,
+ progressSoFar, curr_percent);
+ }
+else
+ {
+ rightStatusString(no_time);
+ leftStatusString(no_time);
+ }
+
+updateTicks = TickCount() + 60;
+return;
+}
+
+
+void ShowCounter(Boolean reset)
+{
+static char statusline[100];
+static unsigned long filecount = 0;
+
+if (reset)
+ {
+ filecount = 0;
+ return;
+ }
+
+if (noisy)
+ {
+ sprintf(statusline, "%6d", filecount++);
+ rightStatusString(statusline);
+ }
+}
+
+
+static long EstimateCompletionTime(const long progressMax,
+ const long progressSoFar,
+ unsigned char curr_percent)
+{
+ long max = progressMax, value = progressSoFar;
+ static char buf[100];
+ unsigned long ticksTakenSoFar = TickCount() - createTime;
+ float currentRate = (float) ticksTakenSoFar / (float) value;
+ long newEst = (long)( currentRate * (float)( max - value ));
+
+ sprintf(buf, "%d [%d%%]",progressSoFar, curr_percent);
+ rightStatusString(buf);
+
+ estTicksToFinish = newEst;
+
+ UpdateTimeToComplete();
+
+return estTicksToFinish;
+}
+
+
+
+
+
+static void UpdateTimeToComplete(void)
+{
+ short days, hours, minutes, seconds;
+ char estStr[255];
+ Str15 xx, yy;
+ short idx = 0;
+
+ if ( estTicksToFinish == -1 )
+ return;
+
+ days = estTicksToFinish / 5184000L;
+ hours = ( estTicksToFinish - ( days * 5184000L )) / 216000L;
+ minutes = ( estTicksToFinish - ( days * 5184000L ) -
+ ( hours * 216000L )) / 3600L;
+ seconds = ( estTicksToFinish - ( days * 5184000L ) -
+ ( hours * 216000L ) - ( minutes * 3600L )) / 60L;
+
+ xx[0] = 0;
+ yy[0] = 0;
+
+ if ( days )
+ {
+ /* "more than 24 hours" */
+
+ idx = 1;
+ goto setEstTimeStr;
+ }
+
+ if ( hours >= 8 )
+ {
+ /* "more than x hours" */
+
+ NumToString( hours, xx );
+ idx = 2;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 252000L ) /* > 1hr, 10 minutes */
+ {
+ /* "about x hours, y minutes" */
+
+ NumToString( hours, xx );
+ NumToString( minutes, yy );
+ idx = 3;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 198000L ) /* > 55 minutes */
+ {
+ /* "about an hour" */
+ idx = 4;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 144000L ) /* > 40 minutes */
+ {
+ /* "less than an hour" */
+
+ idx = 5;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 4200L ) /* > 1 minute, 10 sec */
+ {
+ /* "about x minutes, y seconds */
+
+ NumToString( minutes, xx );
+ NumToString( seconds, yy );
+
+ if ( minutes == 1 )
+ idx = 11;
+ else
+ idx = 6;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 3000L ) /* > 50 seconds */
+ {
+ /* "about a minute" */
+
+ idx = 7;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 1500L ) /* > 25 seconds */
+ {
+ /* "less than a minute" */
+
+ idx = 8;
+ goto setEstTimeStr;
+ }
+
+ if ( estTicksToFinish > 120L ) /* > 2 seconds */
+ {
+ NumToString( seconds, xx );
+ idx = 9;
+ goto setEstTimeStr;
+ }
+
+ idx = 10;
+
+ setEstTimeStr:
+ sprintf(estStr,Time_Est_strings[idx],P2CStr(xx),P2CStr(yy));
+ leftStatusString((char *)estStr);
+}
+
+
+
+
+
+/*
+** Just return the zip version
+**
+*/
+
+char *GetZipVersionsInfo(void)
+{
+static char ZipVersion[100];
+
+sprintf(ZipVersion, "Zip Module\n%d.%d%d%s of %s", Z_MAJORVER, Z_MINORVER,
+ Z_PATCHLEVEL, Z_BETALEVEL, REVDATE);
+
+return ZipVersion;
+}
+
+
+
+
+#ifndef USE_SIOUX
+
+/*
+** Just return the copyright message
+**
+*/
+
+char *GetZipCopyright(void)
+{
+static char CopyR[300];
+
+sstrcpy(CopyR, copyright[0]);
+sstrcat(CopyR, copyright[1]);
+sstrcat(CopyR, "\r\rPlease send bug reports to the authors at\r"\
+ "Zip-Bugs@lists.wku.edu");
+
+return CopyR;
+}
+
+
+
+
+/*
+** Just return the compilers date/time
+**
+*/
+
+char *GetZipVersionLocal(void)
+{
+static char ZipVersionLocal[50];
+
+sprintf(ZipVersionLocal, "[%s %s]", __DATE__, __TIME__);
+
+return ZipVersionLocal;
+}
+
+#endif /* #ifndef USE_SIOUX */
+
+
+
+
diff --git a/macos/source/macstuff.c b/macos/source/macstuff.c
new file mode 100644
index 0000000..0323607
--- /dev/null
+++ b/macos/source/macstuff.c
@@ -0,0 +1,1724 @@
+/*
+These Functions were originally part of More Files version 1.4.8
+
+More Files fixes many of the broken or underfunctional
+parts of the file system.
+
+More Files
+
+A collection of File Manager and related routines
+
+by Jim Luther (Apple Macintosh Developer Technical Support Emeritus)
+with significant code contributions by Nitin Ganatra
+(Apple Macintosh Developer Technical Support Emeritus)
+Copyright 1992-1998 Apple Computer, Inc.
+Portions copyright 1995 Jim Luther
+All rights reserved.
+
+The Package "More Files" is distributed under the following
+license terms:
+
+ "You may incorporate this sample code into your
+ applications without restriction, though the
+ sample code has been provided "AS IS" and the
+ responsibility for its operation is 100% yours.
+ However, what you are not permitted to do is to
+ redistribute the source as "DSC Sample Code" after
+ having made changes. If you're going to
+ redistribute the source, we require that you make
+ it clear in the source that the code was descended
+ from Apple Sample Code, but that you've made
+ changes."
+
+
+The following changes are made by Info-ZIP:
+
+- The only changes are made by pasting the functions
+ (mostly found in MoreFilesExtras.c / MoreFiles.c)
+ directly into macstuff.c / macstuff.h and slightly
+ reformatting the text (replacement of TABs by spaces,
+ removal/replacement of non-ASCII characters).
+ The code itself is NOT changed.
+
+This file has been modified by Info-ZIP for use in MacZip.
+This file is NOT part of the original package More Files.
+
+More Files can be found on the MetroWerks CD and Developer CD from
+Apple. You can also download the latest version from:
+
+ http://members.aol.com/JumpLong/#MoreFiles
+
+Jim Luther's Home-page:
+ http://members.aol.com/JumpLong/
+
+
+*/
+
+#include <string.h>
+
+
+#include "macstuff.h"
+
+
+
+extern int errno;
+
+static OSErr GetCommentFromDesktopFile(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ Str255 comment);
+
+static OSErr GetCommentID(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ short *commentID);
+
+static OSErr GetDesktopFileName(short vRefNum,
+ Str255 desktopName);
+
+
+enum
+{
+ kBNDLResType = 'BNDL',
+ kFREFResType = 'FREF',
+ kIconFamResType = 'ICN#',
+ kFCMTResType = 'FCMT',
+ kAPPLResType = 'APPL'
+};
+
+
+/*****************************************************************************/
+
+/*
+** File Manager FSp calls
+*/
+
+/*****************************************************************************/
+
+pascal OSErr FSMakeFSSpecCompat(short vRefNum,
+ long dirID,
+ ConstStr255Param fileName,
+ FSSpec *spec)
+{
+ OSErr result;
+
+#if !__MACOSSEVENORLATER
+ if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+ {
+ Boolean isDirectory;
+
+ result = GetObjectLocation(vRefNum, dirID, fileName,
+ &(spec->vRefNum), &(spec->parID), spec->name,
+ &isDirectory);
+ }
+ else
+#endif /* !__MACOSSEVENORLATER */
+ {
+ /* Let the file system create the FSSpec if it can since it does the job */
+ /* much more efficiently than I can. */
+ result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
+
+ /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
+ /* returned in the parID field when making an FSSpec to the volume's */
+ /* root directory by passing a full pathname in MakeFSSpec's */
+ /* fileName parameter. Fixed in Mac OS 8.1 */
+ if ( (result == noErr) && (spec->parID == 0) )
+ spec->parID = fsRtParID;
+ }
+ return ( result );
+}
+
+
+/*****************************************************************************/
+/* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
+
+#if !__MACOSSEVENORLATER
+static Boolean FSHasFSSpecCalls(void)
+{
+ long response;
+#if !GENERATENODATA
+ static Boolean tested = false;
+ static Boolean result = false;
+#else
+ Boolean result = false;
+#endif
+
+#if !GENERATENODATA
+ if ( !tested )
+ {
+ tested = true;
+#endif
+ if ( Gestalt(gestaltFSAttr, &response) == noErr )
+ {
+ result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
+ }
+#if !GENERATENODATA
+ }
+#endif
+ return ( result );
+}
+#endif /* !__MACOSSEVENORLATER */
+
+
+
+/*****************************************************************************/
+/* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
+/* except for FSpExchangeFiles. */
+
+#if !__MACOSSEVENORLATER
+static Boolean QTHasFSSpecCalls(void)
+{
+ long response;
+#if !GENERATENODATA
+ static Boolean tested = false;
+ static Boolean result = false;
+#else
+ Boolean result = false;
+#endif
+
+#if !GENERATENODATA
+ if ( !tested )
+ {
+ tested = true;
+#endif
+ result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
+#if !GENERATENODATA
+ }
+#endif
+ return ( result );
+}
+#endif /* !__MACOSSEVENORLATER */
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpGetDefaultDir --
+ *
+ * This function gets the current default directory.
+ *
+ * Results:
+ * The provided FSSpec is changed to point to the "default"
+ * directory. The function returns what ever errors
+ * FSMakeFSSpecCompat may encounter.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int FSpGetDefaultDir(FSSpecPtr dirSpec) /* On return the default directory. */
+{
+ OSErr err;
+ short vRefNum = 0;
+ long int dirID = 0;
+
+ err = HGetVol(NULL, &vRefNum, &dirID);
+
+ if (err == noErr) {
+ err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
+ dirSpec);
+ }
+
+ return err;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpSetDefaultDir --
+ *
+ * This function sets the default directory to the directory
+ * pointed to by the provided FSSpec.
+ *
+ * Results:
+ * The function returns what ever errors HSetVol may encounter.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int FSpSetDefaultDir(FSSpecPtr dirSpec) /* The new default directory. */
+{
+ OSErr err;
+
+ /*
+ * The following special case is needed to work around a bug
+ * in the Macintosh OS. (Acutally PC Exchange.)
+ */
+
+ if (dirSpec->parID == fsRtParID) {
+ err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
+ } else {
+ err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
+ }
+
+ return err;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpFindFolder --
+ *
+ * This function is a version of the FindFolder function that
+ * returns the result as a FSSpec rather than a vRefNum and dirID.
+ *
+ * Results:
+ * Results will be simaler to that of the FindFolder function.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpFindFolder(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec) /* Pointer to resulting directory. */
+{
+ short foundVRefNum;
+ long foundDirID;
+ OSErr err;
+
+ err = FindFolder(vRefNum, folderType, createFolder,
+ &foundVRefNum, &foundDirID);
+ if (err != noErr) {
+ return err;
+ }
+
+ err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
+ return err;
+}
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpPathFromLocation --
+ *
+ * This function obtains a full path name for a given macintosh
+ * FSSpec. Unlike the More Files function FSpGetFullPath, this
+ * function will return a C string in the Handle. It also will
+ * create paths for FSSpec that do not yet exist.
+ *
+ * Results:
+ * OSErr code.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpPathFromLocation(
+ FSSpec *spec, /* The location we want a path for. */
+ int *length, /* Length of the resulting path. */
+ Handle *fullPath) /* Handle to path. */
+{
+ OSErr err;
+ FSSpec tempSpec;
+ CInfoPBRec pb;
+
+ *fullPath = NULL;
+
+ /*
+ * Make a copy of the input FSSpec that can be modified.
+ */
+ BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+
+ if (tempSpec.parID == fsRtParID) {
+ /*
+ * The object is a volume. Add a colon to make it a full
+ * pathname. Allocate a handle for it and we are done.
+ */
+ tempSpec.name[0] += 2;
+ tempSpec.name[tempSpec.name[0] - 1] = ':';
+ tempSpec.name[tempSpec.name[0]] = '\0';
+
+ err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ } else {
+ /*
+ * The object isn't a volume. Is the object a file or a directory?
+ */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrDirID = tempSpec.parID;
+ pb.dirInfo.ioFDirIndex = 0;
+ err = PBGetCatInfoSync(&pb);
+
+ if ((err == noErr) || (err == fnfErr)) {
+ /*
+ * If the file doesn't currently exist we start over. If the
+ * directory exists everything will work just fine. Otherwise we
+ * will just fail later. If the object is a directory, append a
+ * colon so full pathname ends with colon.
+ */
+ if (err == fnfErr) {
+ BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+ } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) {
+ tempSpec.name[0] += 1;
+ tempSpec.name[tempSpec.name[0]] = ':';
+ }
+
+ /*
+ * Create a new Handle for the object - make it a C string.
+ */
+ tempSpec.name[0] += 1;
+ tempSpec.name[tempSpec.name[0]] = '\0';
+ err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ if (err == noErr) {
+ /*
+ * Get the ancestor directory names - loop until we have an
+ * error or find the root directory.
+ */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrParID = tempSpec.parID;
+ do {
+ pb.dirInfo.ioFDirIndex = -1;
+ pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+ err = PBGetCatInfoSync(&pb);
+ if (err == noErr) {
+ /*
+ * Append colon to directory name and add
+ * directory name to beginning of fullPath.
+ */
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+
+ (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
+ tempSpec.name[0]);
+ err = MemError();
+ }
+ } while ( (err == noErr) &&
+ (pb.dirInfo.ioDrDirID != fsRtDirID) );
+ }
+ }
+ }
+
+ /*
+ * On error Dispose the handle, set it to NULL & return the err.
+ * Otherwise, set the length & return.
+ */
+ if (err == noErr) {
+ *length = GetHandleSize(*fullPath) - 1;
+ } else {
+ if ( *fullPath != NULL ) {
+ DisposeHandle(*fullPath);
+ }
+ *fullPath = NULL;
+ *length = 0;
+ }
+
+ return err;
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetDirectoryID(const FSSpec *spec,
+ long *theDirID,
+ Boolean *isDirectory)
+{
+ return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
+ theDirID, isDirectory) );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetDirectoryID(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ long *theDirID,
+ Boolean *isDirectory)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+ if ( error == noErr )
+ {
+ *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+ if ( *isDirectory )
+ {
+ *theDirID = pb.dirInfo.ioDrDirID;
+ }
+ else
+ {
+ *theDirID = pb.hFileInfo.ioFlParID;
+ }
+ }
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetCatInfoNoName(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ CInfoPBPtr pb)
+{
+ Str31 tempName;
+ OSErr error;
+
+ /* Protection against File Sharing problem */
+ if ( (name == NULL) || (name[0] == 0) )
+ {
+ tempName[0] = 0;
+ pb->dirInfo.ioNamePtr = tempName;
+ pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ else
+ {
+ pb->dirInfo.ioNamePtr = (StringPtr)name;
+ pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ pb->dirInfo.ioVRefNum = vRefNum;
+ pb->dirInfo.ioDrDirID = dirID;
+ error = PBGetCatInfoSync(pb);
+ pb->dirInfo.ioNamePtr = NULL;
+ return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr GetObjectLocation(short vRefNum,
+ long dirID,
+ ConstStr255Param pathname,
+ short *realVRefNum,
+ long *realParID,
+ Str255 realName,
+ Boolean *isDirectory)
+{
+ OSErr error;
+ CInfoPBRec pb;
+ Str255 tempPathname;
+
+ /* clear results */
+ *realVRefNum = 0;
+ *realParID = 0;
+ realName[0] = 0;
+
+ /*
+ ** Get the real vRefNum
+ */
+ error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
+ if ( error == noErr )
+ {
+ /*
+ ** Determine if the object already exists and if so,
+ ** get the real parent directory ID if it's a file
+ */
+
+ /* Protection against File Sharing problem */
+ if ( (pathname == NULL) || (pathname[0] == 0) )
+ {
+ tempPathname[0] = 0;
+ pb.hFileInfo.ioNamePtr = tempPathname;
+ pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ else
+ {
+ pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBGetCatInfoSync(&pb);
+ if ( error == noErr )
+ {
+ /*
+ ** The file system object is present and we have the file's
+ ** real parID
+ */
+
+ /* Is it a directory or a file? */
+ *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+ if ( *isDirectory )
+ {
+ /*
+ ** It's a directory, get its name and parent dirID, and then
+ ** we're done
+ */
+
+ pb.dirInfo.ioNamePtr = realName;
+ pb.dirInfo.ioVRefNum = *realVRefNum;
+ /* pb.dirInfo.ioDrDirID already contains the dirID of the
+ directory object */
+ pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
+ error = PBGetCatInfoSync(&pb);
+
+ /* get the parent ID here, because the file system can return the */
+ /* wrong parent ID from the last call. */
+ *realParID = pb.dirInfo.ioDrParID;
+ }
+ else
+ {
+ /*
+ ** It's a file - use the parent directory ID from the last call
+ ** to GetCatInfoparse, get the file name, and then we're done
+ */
+ *realParID = pb.hFileInfo.ioFlParID;
+ error = GetFilenameFromPathname(pathname, realName);
+ }
+ }
+ else if ( error == fnfErr )
+ {
+ /*
+ ** The file system object is not present - see if its parent is present
+ */
+
+ /*
+ ** Parse to get the object name from end of pathname
+ */
+ error = GetFilenameFromPathname(pathname, realName);
+
+ /* if we can't get the object name from the end, we can't continue */
+ if ( error == noErr )
+ {
+ /*
+ ** What we want now is the pathname minus the object name
+ ** for example:
+ ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
+ ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
+ ** if pathname is ':dir:file' tempPathname becomes ':dir:'
+ ** if pathname is ':dir:file:' tempPathname becomes ':dir:'
+ ** if pathname is ':file' tempPathname becomes ':'
+ ** if pathname is 'file or file:' tempPathname becomes ''
+ */
+
+ /* get a copy of the pathname */
+ BlockMoveData(pathname, tempPathname, pathname[0] + 1);
+
+ /* remove the object name */
+ tempPathname[0] -= realName[0];
+ /* and the trailing colon (if any) */
+ if ( pathname[pathname[0]] == ':' )
+ {
+ --tempPathname[0];
+ }
+
+ /* OK, now get the parent's directory ID */
+
+ /* Protection against File Sharing problem */
+ pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
+ if ( tempPathname[0] != 0 )
+ {
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ else
+ {
+ pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBGetCatInfoSync(&pb);
+ *realParID = pb.dirInfo.ioDrDirID;
+
+ *isDirectory = false; /* we don't know what the object is
+ really going to be */
+ }
+
+ if ( error != noErr )
+ {
+ error = dirNFErr; /* couldn't find parent directory */
+ }
+ else
+ {
+ error = fnfErr; /* we found the parent, but not the file */
+ }
+ }
+ }
+
+ return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr DetermineVRefNum(ConstStr255Param pathname,
+ short vRefNum,
+ short *realVRefNum)
+{
+ HParamBlockRec pb;
+ OSErr error;
+
+ error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+ if ( error == noErr )
+ {
+ *realVRefNum = pb.volumeParam.ioVRefNum;
+ }
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetFilenameFromPathname(ConstStr255Param pathname,
+ Str255 filename)
+{
+ short index;
+ short nameEnd;
+ OSErr error;
+
+ /* default to no filename */
+ filename[0] = 0;
+
+ /* check for no pathname */
+ if ( pathname != NULL )
+ {
+ /* get string length */
+ index = pathname[0];
+
+ /* check for empty string */
+ if ( index != 0 )
+ {
+ /* skip over last trailing colon (if any) */
+ if ( pathname[index] == ':' )
+ {
+ --index;
+ }
+
+ /* save the end of the string */
+ nameEnd = index;
+
+ /* if pathname ends with multiple colons, then this pathname refers */
+ /* to a directory, not a file */
+ if ( pathname[index] != ':' )
+ {
+ /* parse backwards until we find a colon or hit the beginning
+ of the pathname */
+ while ( (index != 0) && (pathname[index] != ':') )
+ {
+ --index;
+ }
+
+ /* if we parsed to the beginning of the pathname and the
+ pathname ended */
+ /* with a colon, then pathname is a full pathname to a volume,
+ not a file */
+ if ( (index != 0) || (pathname[pathname[0]] != ':') )
+ {
+ /* get the filename and return noErr */
+ filename[0] = (char)(nameEnd - index);
+ BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
+ error = noErr;
+ }
+ else
+ {
+ /* pathname to a volume, not a file */
+ error = notAFileErr;
+ }
+ }
+ else
+ {
+ /* directory, not a file */
+ error = notAFileErr;
+ }
+ }
+ else
+ {
+ /* empty string isn't a file */
+ error = notAFileErr;
+ }
+ }
+ else
+ {
+ /* NULL pathname isn't a file */
+ error = notAFileErr;
+ }
+
+ return ( error );
+}
+
+
+
+/*****************************************************************************/
+
+/*
+** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
+** in cases where the returned volume name is not needed by the caller.
+** The pathname and vRefNum parameters are not touched, and the pb
+** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
+** the parameter block is always returned as NULL (since it might point
+** to the local tempPathname).
+**
+** I noticed using this code in several places, so here it is once.
+** This reduces the code size of MoreFiles.
+*/
+pascal OSErr GetVolumeInfoNoName(ConstStr255Param pathname,
+ short vRefNum,
+ HParmBlkPtr pb)
+{
+ Str255 tempPathname;
+ OSErr error;
+
+ /* Make sure pb parameter is not NULL */
+ if ( pb != NULL )
+ {
+ pb->volumeParam.ioVRefNum = vRefNum;
+ if ( pathname == NULL )
+ {
+ pb->volumeParam.ioNamePtr = NULL;
+ pb->volumeParam.ioVolIndex = 0; /* use ioVRefNum only */
+ }
+ else
+ { /* make a copy of the string and */
+ BlockMoveData(pathname, tempPathname, pathname[0] + 1);
+ /* use the copy so original isn't trashed */
+ pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;
+ /* use ioNamePtr/ioVRefNum combination */
+ pb->volumeParam.ioVolIndex = -1;
+ }
+ error = PBHGetVInfoSync(pb);
+ pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local
+ tempPathname, so don't return it */
+ }
+ else
+ {
+ error = paramErr;
+ }
+ return ( error );
+}
+
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetFullPath(const FSSpec *spec,
+ short *fullPathLength,
+ Handle *fullPath)
+{
+ OSErr result;
+ OSErr realResult;
+ FSSpec tempSpec;
+ CInfoPBRec pb;
+
+ *fullPathLength = 0;
+ *fullPath = NULL;
+
+ /* Default to noErr */
+ realResult = noErr;
+
+ /* Make a copy of the input FSSpec that can be modified */
+ BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+
+ if ( tempSpec.parID == fsRtParID )
+ {
+ /* The object is a volume */
+
+ /* Add a colon to make it a full pathname */
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+
+ /* We're done */
+ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ }
+ else
+ {
+ /* The object isn't a volume */
+
+ /* Is the object a file or a directory? */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrDirID = tempSpec.parID;
+ pb.dirInfo.ioFDirIndex = 0;
+ result = PBGetCatInfoSync(&pb);
+ /* Allow file/directory name at end of path to not exist. */
+ realResult = result;
+ if ( (result == noErr) || (result == fnfErr) )
+ {
+ /* if the object is a directory, append a colon so full pathname
+ ends with colon */
+ if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+ {
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+ }
+
+ /* Put the object name in first */
+ result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+ if ( result == noErr )
+ {
+ /* Get the ancestor directory names */
+ pb.dirInfo.ioNamePtr = tempSpec.name;
+ pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+ pb.dirInfo.ioDrParID = tempSpec.parID;
+ do /* loop until we have an error or find the root directory */
+ {
+ pb.dirInfo.ioFDirIndex = -1;
+ pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+ result = PBGetCatInfoSync(&pb);
+ if ( result == noErr )
+ {
+ /* Append colon to directory name */
+ ++tempSpec.name[0];
+ tempSpec.name[tempSpec.name[0]] = ':';
+
+ /* Add directory name to beginning of fullPath */
+ (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
+ tempSpec.name[0]);
+ result = MemError();
+ }
+ } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
+ }
+ }
+ }
+ if ( result == noErr )
+ {
+ /* Return the length */
+ *fullPathLength = InlineGetHandleSize(*fullPath);
+ result = realResult; /* return realResult in case it was fnfErr */
+ }
+ else
+ {
+ /* Dispose of the handle and return NULL and zero length */
+ if ( *fullPath != NULL )
+ {
+ DisposeHandle(*fullPath);
+ }
+ *fullPath = NULL;
+ *fullPathLength = 0;
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpLocationFromFullPath(short fullPathLength,
+ const void *fullPath,
+ FSSpec *spec)
+{
+ AliasHandle alias;
+ OSErr result;
+ Boolean wasChanged;
+ Str32 nullString;
+
+ /* Create a minimal alias from the full pathname */
+ nullString[0] = 0; /* null string to indicate no zone or server name */
+ result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString,
+ nullString, &alias);
+
+ if ( result == noErr )
+ {
+ /* Let the Alias Manager resolve the alias. */
+ result = ResolveAlias(NULL, alias, spec, &wasChanged);
+
+ DisposeHandle((Handle)alias); /* Free up memory used */
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr GetFullPath(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ short *fullPathLength,
+ Handle *fullPath)
+{
+ OSErr result;
+ FSSpec spec;
+
+ *fullPathLength = 0;
+ *fullPath = NULL;
+
+ result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
+ if ( (result == noErr) || (result == fnfErr) )
+ {
+ result = FSpGetFullPath(&spec, fullPathLength, fullPath);
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr ChangeCreatorType(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ OSType creator,
+ OSType fileType)
+{
+ CInfoPBRec pb;
+ OSErr error;
+ short realVRefNum;
+ long parID;
+
+ pb.hFileInfo.ioNamePtr = (StringPtr)name;
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ error = PBGetCatInfoSync(&pb);
+ if ( error == noErr )
+ {
+ if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) /* if file */
+ { /* save parent dirID for BumpDate call */
+ parID = pb.hFileInfo.ioFlParID;
+
+ /* If creator not 0x00000000, change creator */
+ if ( creator != (OSType)0x00000000 )
+ {
+ pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
+ }
+
+ /* If fileType not 0x00000000, change fileType */
+ if ( fileType != (OSType)0x00000000 )
+ {
+ pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
+ }
+
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBSetCatInfoSync(&pb); /* now, save the new information
+ back to disk */
+
+ if ( (error == noErr) && (parID != fsRtParID) ) /* can't
+ bump fsRtParID */
+ {
+ /* get the real vRefNum in case a full pathname was passed */
+ error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+ if ( error == noErr )
+ {
+ error = BumpDate(realVRefNum, parID, NULL);
+ /* and bump the parent directory's mod date to wake
+ up the Finder */
+ /* to the change we just made */
+ }
+ }
+ }
+ else
+ {
+ /* it was a directory, not a file */
+ error = notAFileErr;
+ }
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpChangeCreatorType(const FSSpec *spec,
+ OSType creator,
+ OSType fileType)
+{
+ return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name,
+ creator, fileType) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr BumpDate(short vRefNum,
+ long dirID,
+ ConstStr255Param name)
+/* Given a file or directory, change its modification date to the
+ current date/time. */
+{
+ CInfoPBRec pb;
+ Str31 tempName;
+ OSErr error;
+ unsigned long secs;
+
+ /* Protection against File Sharing problem */
+ if ( (name == NULL) || (name[0] == 0) )
+ {
+ tempName[0] = 0;
+ pb.hFileInfo.ioNamePtr = tempName;
+ pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
+ }
+ else
+ {
+ pb.hFileInfo.ioNamePtr = (StringPtr)name;
+ pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
+ }
+ pb.hFileInfo.ioVRefNum = vRefNum;
+ pb.hFileInfo.ioDirID = dirID;
+ error = PBGetCatInfoSync(&pb);
+ if ( error == noErr )
+ {
+ GetDateTime(&secs);
+ /* set mod date to current date, or one second into the future
+ if mod date = current date */
+ pb.hFileInfo.ioFlMdDat =
+ (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
+ if ( pb.dirInfo.ioNamePtr == tempName )
+ {
+ pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
+ }
+ else
+ {
+ pb.hFileInfo.ioDirID = dirID;
+ }
+ error = PBSetCatInfoSync(&pb);
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpBumpDate(const FSSpec *spec)
+{
+ return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr OnLine(FSSpecPtr volumes,
+ short reqVolCount,
+ short *actVolCount,
+ short *volIndex)
+{
+ HParamBlockRec pb;
+ OSErr error = noErr;
+ FSSpec *endVolArray;
+
+ if ( *volIndex > 0 )
+ {
+ *actVolCount = 0;
+ for ( endVolArray = volumes + reqVolCount;
+ (volumes < endVolArray) && (error == noErr); ++volumes )
+ {
+ pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
+ pb.volumeParam.ioVolIndex = *volIndex;
+ error = PBHGetVInfoSync(&pb);
+ if ( error == noErr )
+ {
+ volumes->parID = fsRtParID; /* the root directory's
+ parent is 1 */
+ volumes->vRefNum = pb.volumeParam.ioVRefNum;
+ ++*volIndex;
+ ++*actVolCount;
+ }
+ }
+ }
+ else
+ {
+ error = paramErr;
+ }
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr DTGetComment(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ Str255 comment)
+{
+ DTPBRec pb;
+ OSErr error;
+ short dtRefNum;
+ Boolean newDTDatabase;
+
+ if (comment != NULL)
+ {
+ comment[0] = 0; /* return nothing by default */
+
+ /* attempt to open the desktop database */
+ error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+ if ( error == noErr )
+ {
+ /* There was a desktop database and it's now open */
+
+ if ( !newDTDatabase )
+ {
+ pb.ioDTRefNum = dtRefNum;
+ pb.ioNamePtr = (StringPtr)name;
+ pb.ioDirID = dirID;
+ pb.ioDTBuffer = (Ptr)&comment[1];
+ /*
+ ** IMPORTANT NOTE #1: Inside Macintosh says that comments
+ ** are up to 200 characters. While that may be correct for
+ ** the HFS file system's Desktop Manager, other file
+ ** systems (such as Apple Photo Access) return up to
+ ** 255 characters. Make sure the comment buffer is a Str255
+ ** or you'll regret it.
+ **
+ ** IMPORTANT NOTE #2: Although Inside Macintosh doesn't
+ ** mention it, ioDTReqCount is a input field to
+ ** PBDTGetCommentSync. Some file systems (like HFS) ignore
+ ** ioDTReqCount and always return the full comment --
+ ** others (like AppleShare) respect ioDTReqCount and only
+ ** return up to ioDTReqCount characters of the comment.
+ */
+ pb.ioDTReqCount = sizeof(Str255) - 1;
+ error = PBDTGetCommentSync(&pb);
+ if (error == noErr)
+ {
+ comment[0] = (unsigned char)pb.ioDTActCount;
+ }
+ }
+ }
+ else
+ {
+ /* There is no desktop database - try the Desktop file */
+ error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
+ if ( error != noErr )
+ {
+ error = afpItemNotFound; /* return an expected error */
+ }
+ }
+ }
+ else
+ {
+ error = paramErr;
+ }
+
+ return (error);
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpDTGetComment(const FSSpec *spec,
+ Str255 comment)
+{
+ return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr DTSetComment(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ ConstStr255Param comment)
+{
+ DTPBRec pb;
+ OSErr error;
+ short dtRefNum;
+ Boolean newDTDatabase;
+
+ error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+ if ( error == noErr )
+ {
+ pb.ioDTRefNum = dtRefNum;
+ pb.ioNamePtr = (StringPtr)name;
+ pb.ioDirID = dirID;
+ pb.ioDTBuffer = (Ptr)&comment[1];
+ /* Truncate the comment to 200 characters just in case */
+ /* some file system doesn't range check */
+ if ( comment[0] <= 200 )
+ {
+ pb.ioDTReqCount = comment[0];
+ }
+ else
+ {
+ pb.ioDTReqCount = 200;
+ }
+ error = PBDTSetCommentSync(&pb);
+ }
+ return (error);
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpDTSetComment(const FSSpec *spec,
+ ConstStr255Param comment)
+{
+ return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr DTOpen(ConstStr255Param volName,
+ short vRefNum,
+ short *dtRefNum,
+ Boolean *newDTDatabase)
+{
+ OSErr error;
+ GetVolParmsInfoBuffer volParmsInfo;
+ long infoSize;
+ DTPBRec pb;
+
+ /* Check for volume Desktop Manager support before calling */
+ infoSize = sizeof(GetVolParmsInfoBuffer);
+ error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
+ if ( error == noErr )
+ {
+ if ( hasDesktopMgr(volParmsInfo) )
+ {
+ pb.ioNamePtr = (StringPtr)volName;
+ pb.ioVRefNum = vRefNum;
+ error = PBDTOpenInform(&pb);
+ /* PBDTOpenInform informs us if the desktop was just created */
+ /* by leaving the low bit of ioTagInfo clear (0) */
+ *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
+ if ( error == paramErr )
+ {
+ error = PBDTGetPath(&pb);
+ /* PBDTGetPath doesn't tell us if the database is new */
+ /* so assume it is not new */
+ *newDTDatabase = false;
+ }
+ *dtRefNum = pb.ioDTRefNum;
+ }
+ else
+ {
+ error = paramErr;
+ }
+ }
+ return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+** GetCommentFromDesktopFile
+**
+** Get a file or directory's Finder comment field (if any) from the
+** Desktop file's 'FCMT' resources.
+*/
+static OSErr GetCommentFromDesktopFile(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ Str255 comment)
+{
+ OSErr error;
+ short commentID;
+ short realVRefNum;
+ Str255 desktopName;
+ short savedResFile;
+ short dfRefNum;
+ StringHandle commentHandle;
+
+ /* Get the comment ID number */
+ error = GetCommentID(vRefNum, dirID, name, &commentID);
+ if ( error == noErr )
+ {
+ if ( commentID != 0 ) /* commentID == 0 means there's no comment */
+ {
+ error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+ if ( error == noErr )
+ {
+ error = GetDesktopFileName(realVRefNum, desktopName);
+ if ( error == noErr )
+ {
+ savedResFile = CurResFile();
+ /*
+ ** Open the 'Desktop' file in the root directory. (because
+ ** opening the resource file could preload unwanted resources,
+ ** bracket the call with SetResLoad(s))
+ */
+ SetResLoad(false);
+ dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName,
+ fsRdPerm);
+ SetResLoad(true);
+
+ if ( dfRefNum != -1)
+ {
+ /* Get the comment resource */
+ commentHandle = (StringHandle)Get1Resource(kFCMTResType,
+ commentID);
+ if ( commentHandle != NULL )
+ {
+ if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
+ {
+ BlockMoveData(*commentHandle, comment,
+ *commentHandle[0] + 1);
+ }
+ else
+ { /* no comment available */
+ error = afpItemNotFound;
+ }
+ }
+ else
+ { /* no comment available */
+ error = afpItemNotFound;
+ }
+
+ /* restore the resource chain and close
+ the Desktop file */
+ UseResFile(savedResFile);
+ CloseResFile(dfRefNum);
+ }
+ else
+ {
+ error = afpItemNotFound;
+ }
+ }
+ else
+ {
+ error = afpItemNotFound;
+ }
+ }
+ }
+ else
+ {
+ error = afpItemNotFound; /* no comment available */
+ }
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr HGetVolParms(ConstStr255Param volName,
+ short vRefNum,
+ GetVolParmsInfoBuffer *volParmsInfo,
+ long *infoSize)
+{
+ HParamBlockRec pb;
+ OSErr error;
+
+ pb.ioParam.ioNamePtr = (StringPtr)volName;
+ pb.ioParam.ioVRefNum = vRefNum;
+ pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+ pb.ioParam.ioReqCount = *infoSize;
+ error = PBHGetVolParmsSync(&pb);
+ if ( error == noErr )
+ {
+ *infoSize = pb.ioParam.ioActCount;
+ }
+ return ( error );
+}
+
+/*****************************************************************************/
+/*
+** GetCommentID
+**
+** Get the comment ID number for the Desktop file's 'FCMT' resource ID from
+** the file or folders fdComment (frComment) field.
+*/
+static OSErr GetCommentID(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ short *commentID)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+ *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
+ return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+** GetDesktopFileName
+**
+** Get the name of the Desktop file.
+*/
+static OSErr GetDesktopFileName(short vRefNum,
+ Str255 desktopName)
+{
+ OSErr error;
+ HParamBlockRec pb;
+ short index;
+ Boolean found;
+
+ pb.fileParam.ioNamePtr = desktopName;
+ pb.fileParam.ioVRefNum = vRefNum;
+ pb.fileParam.ioFVersNum = 0;
+ index = 1;
+ found = false;
+ do
+ {
+ pb.fileParam.ioDirID = fsRtDirID;
+ pb.fileParam.ioFDirIndex = index;
+ error = PBHGetFInfoSync(&pb);
+ if ( error == noErr )
+ {
+ if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
+ (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
+ {
+ found = true;
+ }
+ }
+ ++index;
+ } while ( (error == noErr) && !found );
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr XGetVInfo(short volReference,
+ StringPtr volName,
+ short *vRefNum,
+ UnsignedWide *freeBytes,
+ UnsignedWide *totalBytes)
+{
+ OSErr result;
+ long response;
+ XVolumeParam pb;
+
+ /* See if large volume support is available */
+ if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
+ {
+ /* Large volume support is available */
+ pb.ioVRefNum = volReference;
+ pb.ioNamePtr = volName;
+ pb.ioXVersion = 0; /* this XVolumeParam version (0) */
+ pb.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
+ result = PBXGetVolInfoSync(&pb);
+ if ( result == noErr )
+ {
+ /* The volume name was returned in volName (if not NULL) and */
+ /* we have the volume's vRefNum and allocation block size */
+ *vRefNum = pb.ioVRefNum;
+
+ /* return the freeBytes and totalBytes */
+ *totalBytes = pb.ioVTotalBytes;
+ *freeBytes = pb.ioVFreeBytes;
+ }
+ }
+ else
+ {
+ /* No large volume support */
+
+ /* Use HGetVInfo to get the results */
+ result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
+ if ( result == noErr )
+ {
+ /* zero the high longs of totalBytes and freeBytes */
+ totalBytes->hi = 0;
+ freeBytes->hi = 0;
+ }
+ }
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr HGetVInfo(short volReference,
+ StringPtr volName,
+ short *vRefNum,
+ unsigned long *freeBytes,
+ unsigned long *totalBytes)
+{
+ HParamBlockRec pb;
+ unsigned long allocationBlockSize;
+ unsigned short numAllocationBlocks;
+ unsigned short numFreeBlocks;
+ VCB *theVCB;
+ Boolean vcbFound;
+ OSErr result;
+
+ /* Use the File Manager to get the real vRefNum */
+ pb.volumeParam.ioVRefNum = volReference;
+ pb.volumeParam.ioNamePtr = volName;
+ pb.volumeParam.ioVolIndex = 0; /* use ioVRefNum only, return volume name */
+ result = PBHGetVInfoSync(&pb);
+
+ if ( result == noErr )
+ {
+ /* The volume name was returned in volName (if not NULL) and */
+ /* we have the volume's vRefNum and allocation block size */
+ *vRefNum = pb.volumeParam.ioVRefNum;
+ allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz;
+
+ /* System 7.5 (and beyond) pins the number of allocation blocks and */
+ /* the number of free allocation blocks returned by PBHGetVInfo to */
+ /* a value so that when multiplied by the allocation block size, */
+ /* the volume will look like it has $7fffffff bytes or less. This */
+ /* was done so older applications that use signed math or that use */
+ /* the GetVInfo function (which uses signed math) will continue to work. */
+ /* However, the unpinned numbers (which we want) are always available */
+ /* in the volume's VCB so we'll get those values from the VCB if possible. */
+
+ /* Find the volume's VCB */
+ vcbFound = false;
+ theVCB = (VCB *)(GetVCBQHdr()->qHead);
+ while ( (theVCB != NULL) && !vcbFound )
+ {
+ /* Check VCB signature before using VCB. Don't have to check for */
+ /* MFS (0xd2d7) because they can't get big enough to be pinned */
+ if ( theVCB->vcbSigWord == 0x4244 )
+ {
+ if ( theVCB->vcbVRefNum == *vRefNum )
+ {
+ vcbFound = true;
+ }
+ }
+
+ if ( !vcbFound )
+ {
+ theVCB = (VCB *)(theVCB->qLink);
+ }
+ }
+
+ if ( theVCB != NULL )
+ {
+ /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
+ /* and the number of free blocks from the VCB. */
+ numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks;
+ numFreeBlocks = (unsigned short)theVCB->vcbFreeBks;
+ }
+ else
+ {
+ /* Didn't find a VCB we can use. Return the number of allocation blocks */
+ /* and the number of free blocks returned by PBHGetVInfoSync. */
+ numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks;
+ numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
+ }
+
+ /* Now, calculate freeBytes and totalBytes using unsigned values */
+ *freeBytes = numFreeBlocks * allocationBlockSize;
+ *totalBytes = numAllocationBlocks * allocationBlockSize;
+ }
+
+ return ( result );
+}
+
+
+/*
+** PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
+** File Manager requests from CFM-based programs. At some point, Apple
+** will get around to adding this to the standard libraries you link with
+** and you'll get a duplicate symbol link error. At that time, just delete
+** this code (or comment it out).
+**
+** Non-CFM 68K programs don't needs this glue (and won't get it) because
+** they instead use the inline assembly glue found in the Files.h interface
+** file.
+*/
+
+#if __WANTPASCALELIMINATION
+#undef pascal
+#endif
+
+#if GENERATINGCFM
+pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
+{
+ enum
+ {
+ kXGetVolInfoSelector = 0x0012, /* Selector for XGetVolInfo */
+
+ uppFSDispatchProcInfo = kRegisterBased
+ | REGISTER_RESULT_LOCATION(kRegisterD0)
+ | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
+ | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */
+ | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */
+ | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
+ };
+
+ return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
+ uppFSDispatchProcInfo,
+ _FSDispatch,
+ kXGetVolInfoSelector,
+ paramBlock) );
+}
+#endif
+
+#if __WANTPASCALELIMINATION
+#define pascal
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr GetDirName(short vRefNum,
+ long dirID,
+ Str31 name)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ if ( name != NULL )
+ {
+ pb.dirInfo.ioNamePtr = name;
+ pb.dirInfo.ioVRefNum = vRefNum;
+ pb.dirInfo.ioDrDirID = dirID;
+ pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */
+ error = PBGetCatInfoSync(&pb);
+ }
+ else
+ {
+ error = paramErr;
+ }
+
+ return ( error );
+}
+
+
+/*****************************************************************************/
+
+pascal OSErr GetVolFileSystemID(ConstStr255Param pathname,
+ short vRefNum,
+ short *fileSystemID)
+{
+ HParamBlockRec pb;
+ OSErr error;
+
+ error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+ if ( error == noErr )
+ {
+ *fileSystemID = pb.volumeParam.ioVFSID;
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr GetDInfo(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ DInfo *fndrInfo)
+{
+ CInfoPBRec pb;
+ OSErr error;
+
+ error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+ if ( error == noErr )
+ {
+ if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+ {
+ /* it's a directory, return the DInfo */
+ *fndrInfo = pb.dirInfo.ioDrUsrWds;
+ }
+ else
+ {
+ /* oops, a file was passed */
+ error = dirNFErr;
+ }
+ }
+
+ return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetDInfo(const FSSpec *spec,
+ DInfo *fndrInfo)
+{
+ return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
+}
+
+
diff --git a/macos/source/macstuff.h b/macos/source/macstuff.h
new file mode 100644
index 0000000..9e92dce
--- /dev/null
+++ b/macos/source/macstuff.h
@@ -0,0 +1,18 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _MACSTUFF_H
+#define _MACSTUFF_H 1
+
+#include "MoreFilesExtras.h"
+#include "MoreDesktopMgr.h"
+#include "MoreFiles.h"
+#include "FSpCompat.h"
+#include "FullPath.h"
+
+#endif /* _MACSTUFF_H */
diff --git a/macos/source/mactime.c b/macos/source/mactime.c
new file mode 100644
index 0000000..af9ad5e
--- /dev/null
+++ b/macos/source/mactime.c
@@ -0,0 +1,451 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/* -----------------------------------------------------------------------------
+
+The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
+mktime and time do not work correctly. The supplied link library mactime.c
+contains replacement functions for them.
+
+ * Caveat: On a Mac, we only know the GMT and DST offsets for
+ * the current time, not for the time in question.
+ * Mac has no support for DST handling.
+ * DST changeover is all manually set by the user.
+
+
+------------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <OSUtils.h>
+
+#include "mactime.h"
+
+
+/*
+The MacOS function GetDateTime returns the
+number of seconds elapsed since midnight, January 1, 1904.
+*/
+const unsigned long MacOS_2_Unix = 2082844800L;
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+
+#ifndef TEST_TIME_LIB
+#define my_gmtime gmtime
+#define my_localtime localtime
+#define my_mktime mktime
+#define my_time time
+#endif
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+/* internal prototypes */
+static void clear_tm(struct tm * tm);
+static long GMTDelta(void);
+static Boolean DaylightSaving(void);
+static time_t GetTimeMac(void);
+static time_t Mactime(time_t *timer);
+static void normalize(int *i,int *j,int norm);
+static struct tm *time2tm(const time_t *timer);
+static time_t tm2time(struct tm *tp);
+
+/* Because serial port and SLIP conflict with ReadXPram calls,
+ we cache the call here so we don't hang on calling ReadLocation() */
+static void myReadLocation(MachineLocation * loc);
+
+
+/* prototypes for STD lib replacement functions */
+struct tm *my_gmtime(const time_t *t);
+struct tm *my_localtime(const time_t *t);
+time_t my_mktime(struct tm *tp);
+time_t my_time(time_t *t);
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+ /*
+ * Mac file times are based on 1904 Jan 1 00:00 local time,
+ * not 1970 Jan 1 00:00 UTC.
+ * So we have to convert the time stamps into UNIX UTC
+ * compatible values.
+ */
+time_t MacFtime2UnixFtime(unsigned long macftime)
+{
+ long UTCoffset;
+
+ GetGMToffsetMac(macftime, &UTCoffset);
+ MACOS_TO_UNIX(macftime);
+ macftime -= UTCoffset;
+
+ return macftime;
+}
+
+
+ /*
+ * Mac file times are based on 1904 Jan 1 00:00 local time,
+ * not 1970 Jan 1 00:00 UTC.
+ * So we have to convert the time stamps into MacOS local
+ * compatible values.
+ */
+unsigned long UnixFtime2MacFtime(time_t unxftime)
+{
+ long UTCoffset;
+ unsigned long macftime = unxftime;
+
+ UNIX_TO_MACOS(macftime);
+ GetGMToffsetMac(macftime, &UTCoffset);
+ macftime += UTCoffset;
+
+ return macftime;
+}
+
+
+
+
+
+/*
+* This function convert a file-localtime to an another
+* file-localtime.
+*/
+time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs)
+{
+ time_t MacGMTTime;
+ long UTCoffset;
+
+ /* convert macloctim into corresponding UTC value */
+ MacGMTTime = macloctim - s_gmtoffs;
+ GetGMToffsetMac(macloctim, &UTCoffset);
+
+ return (MacGMTTime + UTCoffset);
+} /* AdjustForTZmove() */
+
+
+
+
+/*
+ * This function calculates the difference between the supplied Mac
+ * ftime value (local time) and the corresponding UTC time in seconds.
+ */
+Boolean GetGMToffsetMac(unsigned long mactime, long *UTCoffset)
+{
+
+mactime = mactime;
+/*
+ * Caveat: On a Mac, we only know the GMT and DST offsets for
+ * the current time, not for the time in question.
+ * Mac has no support for DST handling.
+ * DST changeover is all manually set by the user.
+
+ May be later I can include a support of GMT offset calculation for the
+ time in question here.
+*/
+ *UTCoffset = GMTDelta();
+
+ return true;
+}
+
+
+
+
+
+
+
+/*****************************************************************************
+ * Standard Library Replacement Functions
+ * gmtime(), mktime(), localtime(), time()
+ *
+ * The unix epoch is used here.
+ * These functions gmtime(), mktime(), localtime() and time()
+ * expects and returns unix times.
+ *
+ * At midnight Jan. 1, 1970 GMT, the local time was
+ * midnight Jan. 1, 1970 + GMTDelta().
+ *
+ *
+ *****************************************************************************/
+
+
+struct tm *my_gmtime(const time_t *timer)
+{
+ return time2tm(timer);
+}
+
+
+
+
+struct tm *my_localtime(const time_t *timer)
+{
+ time_t maclocal;
+
+ maclocal = *timer;
+ maclocal += GMTDelta();
+
+ return time2tm(&maclocal);
+}
+
+
+
+
+time_t my_mktime(struct tm *tp)
+{
+ time_t maclocal;
+
+ maclocal = tm2time(tp);
+ maclocal -= GMTDelta();
+
+ return maclocal;
+}
+
+
+
+
+
+
+time_t my_time(time_t *time)
+{
+time_t tmp_time;
+
+GetDateTime(&tmp_time);
+
+MACOS_TO_UNIX(tmp_time);
+
+if (time)
+ {
+ *time = tmp_time;
+ }
+
+return tmp_time;
+}
+
+
+
+/*****************************************************************************/
+/* static module level functions
+/*****************************************************************************/
+
+
+/*
+ * The geographic location and time zone information of a Mac
+ * are stored in extended parameter RAM. The ReadLocation
+ * produdure uses the geographic location record, MachineLocation,
+ * to read the geographic location and time zone information in
+ * extended parameter RAM.
+ *
+ * Because serial port and SLIP conflict with ReadXPram calls,
+ * we cache the call here.
+ *
+ * Caveat: this caching will give the wrong result if a session
+ * extend across the DST changeover time, but
+ * this function resets itself every 2 hours.
+ */
+static void myReadLocation(MachineLocation * loc)
+{
+ static MachineLocation storedLoc; /* InsideMac, OSUtilities, page 4-20 */
+ static time_t first_call = 0, last_call = 86400;
+
+ if ((last_call - first_call) > 7200)
+ {
+ GetDateTime(&first_call);
+ ReadLocation(&storedLoc);
+ }
+
+ GetDateTime(&last_call);
+ *loc = storedLoc;
+}
+
+
+
+
+static Boolean DaylightSaving(void)
+{
+ MachineLocation loc;
+ unsigned char dlsDelta;
+
+ myReadLocation(&loc);
+ dlsDelta = loc.u.dlsDelta;
+
+ return (dlsDelta != 0);
+}
+
+
+
+
+/* current local time = GMTDelta() + GMT
+ GMT = local time - GMTDelta() */
+static long GMTDelta(void)
+{
+ MachineLocation loc;
+ long gmtDelta;
+
+ myReadLocation(&loc);
+
+ /*
+ * On a Mac, the GMT value is in seconds east of GMT. For example,
+ * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour)
+ * east of GMT. The gmtDelta field is a 3-byte value contained in a
+ * long word, so you must take care to get it properly.
+ */
+ gmtDelta = loc.u.gmtDelta & 0x00FFFFFF;
+ if ((gmtDelta & 0x00800000) != 0)
+ {
+ gmtDelta |= 0xFF000000;
+ }
+
+ return gmtDelta;
+}
+
+
+
+/* This routine simulates stdclib time(), time in seconds since 1.1.1970
+ The time is in GMT */
+static time_t GetTimeMac(void)
+{
+ unsigned long maclocal;
+
+
+ /*
+ * Get the current time expressed as the number of seconds
+ * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time).
+ * On a Mac, current time accuracy is up to a second.
+ */
+
+ GetDateTime(&maclocal); /* Get Mac local time */
+ maclocal -= GMTDelta(); /* Get Mac GMT */
+ MACOS_TO_UNIX(maclocal);
+
+ return maclocal; /* return unix GMT */
+}
+
+
+
+
+/*
+ * clear_tm - sets a broken-down time to the equivalent of 1970/1/1 00:00:00
+ */
+
+static void clear_tm(struct tm * tm)
+{
+ tm->tm_sec = 0;
+ tm->tm_min = 0;
+ tm->tm_hour = 0;
+ tm->tm_mday = 1;
+ tm->tm_mon = 0;
+ tm->tm_year = 0;
+ tm->tm_wday = 1;
+ tm->tm_yday = 0;
+ tm->tm_isdst = -1;
+}
+
+
+static void normalize(int *i,int *j,int norm)
+{
+ while(*i < 0)
+ {
+ *i += norm;
+ (*j)--;
+ }
+
+ while(*i >= norm)
+ {
+ *i -= norm;
+ (*j)++;
+ }
+}
+
+
+
+/* Returns the GMT times */
+static time_t Mactime(time_t *timer)
+{
+ time_t t = GetTimeMac();
+
+ if (timer != NULL)
+ *timer = t;
+
+ return t;
+}
+
+
+
+
+static struct tm *time2tm(const time_t *timer)
+{
+ DateTimeRec dtr;
+ MachineLocation loc;
+ time_t macLocal = *timer;
+
+ static struct tm statictime;
+ static const short monthday[12] =
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+ UNIX_TO_MACOS(macLocal);
+ SecondsToDate(macLocal, &dtr);
+
+ statictime.tm_sec = dtr.second; /* second, from 0 to 59 */
+ statictime.tm_min = dtr.minute; /* minute, from 0 to 59 */
+ statictime.tm_hour = dtr.hour; /* hour, from 0 to 23 */
+ statictime.tm_mday = dtr.day; /* day of the month, from 1 to 31 */
+ statictime.tm_mon = dtr.month - 1; /* month, 1= January and 12 = December */
+ statictime.tm_year = dtr.year - 1900; /* year, ranging from 1904 to 2040 */
+ statictime.tm_wday = dtr.dayOfWeek - 1; /* day of the week, 1 = Sun, 7 = Sat */
+
+ statictime.tm_yday = monthday[statictime.tm_mon]
+ + statictime.tm_mday - 1;
+
+ if (2 < statictime.tm_mon && !(statictime.tm_year & 3))
+ {
+ ++statictime.tm_yday;
+ }
+
+ myReadLocation(&loc);
+ statictime.tm_isdst = DaylightSaving();
+
+ return(&statictime);
+}
+
+
+
+
+
+static time_t tm2time(struct tm *tp)
+{
+time_t intMacTime;
+DateTimeRec dtr;
+
+ normalize(&tp->tm_sec, &tp->tm_min, 60);
+ normalize(&tp->tm_min, &tp->tm_hour,60);
+ normalize(&tp->tm_hour,&tp->tm_mday,24);
+ normalize(&tp->tm_mon, &tp->tm_year,12);
+
+ dtr.year = tp->tm_year + 1900; /* years since 1900 */
+ dtr.month = tp->tm_mon + 1; /* month, 0 = January and 11 = December */
+ dtr.day = tp->tm_mday; /* day of the month, from 1 to 31 */
+ dtr.hour = tp->tm_hour; /* hour, from 0 to 23 */
+ dtr.minute = tp->tm_min; /* minute, from 0 to 59 */
+ dtr.second = tp->tm_sec; /* second, from 0 to 59 */
+
+ DateToSeconds(&dtr, &intMacTime);
+
+ MACOS_TO_UNIX(intMacTime);
+
+ return intMacTime;
+}
diff --git a/macos/source/mactime.h b/macos/source/mactime.h
new file mode 100644
index 0000000..cb76aa4
--- /dev/null
+++ b/macos/source/mactime.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef _MACTIME_H_
+#define _MACTIME_H_
+/* -----------------------------------------------------------------------------
+
+The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
+mktime and time do not work correctly. The supplied link library mactime.c
+contains replacement functions for them.
+
+ * Caveat: On a Mac, we only know the GMT and DST offsets for
+ * the current time, not for the time in question.
+ * Mac has no support for DST handling.
+ * DST changeover is all manually set by the user.
+
+
+------------------------------------------------------------------------------*/
+
+#include <time.h>
+#include <mactypes.h>
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+
+ /*
+ * ARGH. Mac times are based on 1904 Jan 1 00:00, not 1970 Jan 1 00:00.
+ * So we have to diddle time_t's appropriately: add or subtract 66 years'
+ * worth of seconds == number of days times 86400 == (66*365 regular days +
+ * 17 leap days ) * 86400 == (24090 + 17) * 86400 == 2082844800L seconds.
+ * We hope time_t is an unsigned long (ulg) on the Macintosh...
+ */
+/*
+This Offset is only used by MacFileDate_to_UTime()
+*/
+
+#define MACOS_TO_UNIX(x) (x) -= (unsigned long)MacOS_2_Unix
+#define UNIX_TO_MACOS(x) (x) += (unsigned long)MacOS_2_Unix
+
+/*
+The MacOS function GetDateTime returns the
+number of seconds elapsed since midnight, January 1, 1904.
+*/
+extern const unsigned long MacOS_2_Unix;
+
+
+/* prototypes for public utility functions */
+time_t MacFtime2UnixFtime(unsigned long macftime);
+unsigned long UnixFtime2MacFtime(time_t unxftime);
+time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs);
+Boolean GetGMToffsetMac(unsigned long macftime, long *UTCoffset);
+
+
+#endif
diff --git a/macos/source/pathname.c b/macos/source/pathname.c
new file mode 100644
index 0000000..6bf1003
--- /dev/null
+++ b/macos/source/pathname.c
@@ -0,0 +1,726 @@
+/*
+ Copyright (c) 1990-2003 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ pathname.c
+
+ Function dealing with the pathname. Mostly C-string work.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sound.h>
+
+#include "pathname.h"
+#include "helpers.h"
+#include "macstuff.h"
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+const char ResourceMark[] = "XtraStuf.mac:"; /* see also macos.c */
+
+
+#include "zip.h"
+
+
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FSpFindFolder --
+ *
+ * This function is a version of the FindFolder function that
+ * returns the result as a FSSpec rather than a vRefNum and dirID.
+ *
+ * Results:
+ * Results will be simaler to that of the FindFolder function.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+OSErr
+FSpFindFolder(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec) /* Pointer to resulting directory. */
+{
+ short foundVRefNum;
+ long foundDirID;
+ OSErr err;
+
+ err = FindFolder(vRefNum, folderType, createFolder,
+ &foundVRefNum, &foundDirID);
+ if (err != noErr) {
+ return err;
+ }
+
+ err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "\p", spec);
+ return err;
+}
+
+
+/*
+** return volumename from pathname
+**
+*/
+
+unsigned short GetVolumeFromPath(const char *FullPath, char *VolumeName)
+{
+const char *VolEnd, *tmpPtr1;
+char *tmpPtr2 = VolumeName;
+
+AssertStr(FullPath,"GetVolumeFromPath")
+
+for (VolEnd = FullPath; *VolEnd != '\0' && *VolEnd != ':'; VolEnd++)
+ ;
+if (*VolEnd == '\0') return 0;
+
+for (tmpPtr1 = FullPath; tmpPtr1 != VolEnd;)
+ {
+ *tmpPtr2++ = *tmpPtr1++;
+ }
+
+*tmpPtr2 = '\0';
+
+return (unsigned short) strlen(VolumeName);
+}
+
+
+
+/***********************************/
+/* Function FindNewExtractFolder() */
+/***********************************/
+
+char *FindNewExtractFolder(char *ExtractPath, Boolean uniqueFolder)
+{
+char buffer[NAME_MAX], *tmpPtr, *namePtr;
+char *last_dotpos = ExtractPath;
+short count = 0, folderCount = 0;
+OSErr err;
+FSSpec Spec;
+long theDirID;
+Boolean isDirectory;
+unsigned short namelen, pathlen = strlen(ExtractPath);
+unsigned long ext_length = 0;
+unsigned long num_to_cut = 0;
+long firstpart_length = pathlen;
+
+AssertStr(ExtractPath,"FindNewExtractFolder ExtractPath == NULL")
+
+for (tmpPtr = ExtractPath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':')
+ {
+ folderCount++;
+ namePtr = tmpPtr;
+ }
+
+if (folderCount > 1) {
+ namelen = strlen(namePtr);
+} else {
+ namelen = strlen(ExtractPath);
+}
+
+if (uniqueFolder) {
+ for (count = 0; count < 99; count++)
+ {
+ memset(buffer,0,sizeof(buffer));
+
+ if (namelen >= 28)
+ ExtractPath[pathlen-2] = 0x0;
+ else
+ ExtractPath[pathlen-1] = 0x0;
+
+ sprintf(buffer,"%s%d",ExtractPath,count);
+ GetCompletePath(ExtractPath, buffer, &Spec,&err);
+ err = FSpGetDirectoryID(&Spec, &theDirID, &isDirectory);
+ if (err == -43) break;
+ }
+} else {
+ /* Look for the last extension pos */
+ for (tmpPtr = ExtractPath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == '.') last_dotpos = tmpPtr;
+
+ ext_length = strlen(last_dotpos);
+
+ if (ext_length < 6) { /* up to 5 chars are treated as a */
+ /* normal extension like ".html" or ".class" */
+ int nameLength = last_dotpos - ExtractPath;
+ if (nameLength > 1) {
+ ExtractPath[nameLength] = 0x0;
+ } else {
+ ExtractPath[pathlen-1] = 0x0;
+ }
+ } else {
+ ExtractPath[pathlen-1] = 0x0;
+ }
+
+ GetCompletePath(ExtractPath, ExtractPath, &Spec,&err);
+}
+
+/* Foldernames must always end with a colon */
+sstrcat(ExtractPath,":");
+return ExtractPath;
+}
+
+
+
+/*
+** creates an archive file name
+**
+*/
+
+void createArchiveName(char *thePath)
+{
+char *tmpPtr, *namePtr;
+short folderCount = 0;
+unsigned short namelen, pathlen = strlen(thePath);
+
+if (thePath[pathlen-1] == ':') thePath[pathlen-1] = 0x0;
+
+for (tmpPtr = thePath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':')
+ {
+ folderCount++;
+ namePtr = tmpPtr;
+ }
+
+namelen = strlen(namePtr);
+
+ /* we have to eliminate illegal chars:
+ * The name space for Mac filenames and Zip filenames (unix style names)
+ * do both include all printable extended-ASCII characters. The only
+ * difference we have to take care of is the single special character
+ * used as path delimiter:
+ * ':' on MacOS and '/' on Unix and '\\' on Dos.
+ * So, to convert between Mac filenames and Unix filenames without any
+ * loss of information, we simply interchange ':' and '/'. Additionally,
+ * we try to convert the coding of the extended-ASCII characters into
+ * InfoZip's standard ISO 8859-1 codepage table.
+ */
+ MakeCompatibleString(namePtr, '/', '_', '.', '-', -1);
+
+ /* Avoid filenames like: "Archive..zip" */
+if (thePath[pathlen-1] == '.')
+ {
+ thePath[pathlen-1] = 0;
+ }
+
+if (folderCount >= 1)
+ { /* path contains at least one folder */
+
+ if (namelen >= 28)
+ {
+ pathlen = pathlen-4;
+ }
+
+ thePath[pathlen] = '.';
+ thePath[pathlen+1] = 'z';
+ thePath[pathlen+2] = 'i';
+ thePath[pathlen+3] = 'p';
+ thePath[pathlen+4] = 0x0;
+ return;
+ }
+else
+ { /* path contains no folder */
+ FindDesktopFolder(thePath);
+ createArchiveName(thePath);
+ }
+}
+
+
+
+/*
+** finds the desktop-folder on a volume with
+** largest amount of free-space.
+*/
+
+void FindDesktopFolder(char *Path)
+{
+char buffer[255];
+FSSpec volumes[50]; /* 50 Volumes should be enough */
+short actVolCount, volIndex = 1, VolCount = 0;
+OSErr err;
+short i, foundVRefNum;
+FSSpec spec;
+UInt64 freeBytes;
+UInt64 totalBytes;
+UInt64 MaxFreeBytes;
+
+err = OnLine(volumes, 50, &actVolCount, &volIndex);
+printerr("OnLine:", (err != -35) && (err != 0), err, __LINE__, __FILE__, "");
+
+MaxFreeBytes = 0;
+
+for (i=0; i < actVolCount; i++)
+ {
+ XGetVInfo(volumes[i].vRefNum,
+ volumes[i].name,
+ &volumes[i].vRefNum,
+ &freeBytes,
+ &totalBytes);
+
+ if (MaxFreeBytes < freeBytes) {
+ MaxFreeBytes = freeBytes;
+ foundVRefNum = volumes[i].vRefNum;
+ }
+
+ if ((freeBytes == 0) && (MaxFreeBytes < freeBytes)) {
+ MaxFreeBytes = freeBytes;
+ foundVRefNum = volumes[i].vRefNum;
+ }
+
+}
+
+ FSpFindFolder(foundVRefNum, kDesktopFolderType,
+ kDontCreateFolder,&spec);
+
+ GetFullPathFromSpec(buffer, &spec , &err);
+ sstrcat(buffer,Path);
+ sstrcpy(Path,buffer);
+}
+
+
+/*
+** return the path without the filename
+**
+*/
+
+char *TruncFilename(char *DirPath, const char *FilePath)
+{
+char *tmpPtr;
+char *dirPtr = NULL;
+
+AssertStr(DirPath,"TruncFilename")
+Assert_it(Spec,"TruncFilename","")
+
+sstrcpy(DirPath, FilePath);
+
+for (tmpPtr = DirPath; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':')
+ dirPtr = tmpPtr;
+
+if (dirPtr)
+ *++dirPtr = '\0';
+else
+ printerr("TruncFilename: FilePath has no Folders", -1,
+ -1, __LINE__, __FILE__, FilePath);
+
+return DirPath;
+}
+
+
+
+/*
+** return only filename
+**
+*/
+
+char *GetFilename(char *FileName, const char *FilePath)
+{
+const char *tmpPtr;
+const char *dirPtr = NULL;
+
+Assert_it(FileName,"GetFilename","")
+Assert_it(FilePath,"GetFilename","")
+
+for (tmpPtr = FilePath; *tmpPtr; tmpPtr++)
+ {
+ if (*tmpPtr == ':')
+ {
+ dirPtr = tmpPtr;
+ }
+ }
+
+if (dirPtr)
+ {
+ ++dirPtr; /* jump over the ':' */
+ }
+else
+ {
+ return strcpy(FileName, FilePath); /* FilePath has no Folders */
+ }
+
+return strcpy(FileName, dirPtr);
+}
+
+
+
+/*
+** return fullpathname from folder/dir-id
+**
+*/
+
+char *GetFullPathFromID(char *CompletePath, short vRefNum, long dirID,
+ ConstStr255Param name, OSErr *err)
+{
+FSSpec spec;
+
+ *err = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
+ printerr("FSMakeFSSpecCompat:", (*err != -43) && (*err != 0), *err,
+ __LINE__, __FILE__, "");
+ if ( (*err == noErr) || (*err == fnfErr) )
+ {
+ return GetFullPathFromSpec(CompletePath, &spec, err);
+ }
+
+return NULL;
+}
+
+
+
+/*
+** convert real-filename to archive-filename
+**
+*/
+
+char *Real2RfDfFilen(char *RfDfFilen, const char *RealPath,
+ short CurrentFork, short MacZipMode, Boolean DataForkOnly)
+{
+
+AssertStr(RealPath,"Real2RfDfFilen")
+AssertStr(RfDfFilen,"Real2RfDfFilen")
+
+if (DataForkOnly) /* make no changes */
+ {
+ return sstrcpy(RfDfFilen, RealPath);
+ }
+
+switch (MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ sstrcpy(RfDfFilen, RealPath);
+ if (CurrentFork == DataFork) /* data-fork */
+ return sstrcat(RfDfFilen, "d");
+ if (CurrentFork == ResourceFork) /* resource-fork */
+ return sstrcat(RfDfFilen, "r");
+ break;
+ }
+
+ case NewZipMode_EF:
+ {
+ switch (CurrentFork)
+ {
+ case DataFork:
+ {
+ sstrcpy(RfDfFilen, RealPath);
+ return RfDfFilen; /* data-fork */
+ break;
+ }
+ case ResourceFork:
+ {
+ sstrcpy(RfDfFilen, ResourceMark);
+ sstrcat(RfDfFilen, RealPath); /* resource-fork */
+ return RfDfFilen;
+ break;
+ }
+ default:
+ {
+ printerr("Real2RfDfFilen:", -1, -1,
+ __LINE__, __FILE__, RealPath);
+ return NULL; /* function should never reach this point */
+ }
+ }
+ break;
+ }
+ default:
+ {
+ printerr("Real2RfDfFilen:", -1, -1, __LINE__, __FILE__, RealPath);
+ return NULL; /* function should never reach this point */
+ }
+ }
+
+printerr("Real2RfDfFilen:", -1, -1, __LINE__, __FILE__, RealPath);
+return NULL; /* function should never come reach this point */
+}
+
+
+
+/*
+** convert archive-filename into a real filename
+**
+*/
+
+char *RfDfFilen2Real(char *RealFn, const char *RfDfFilen, short MacZipMode,
+ Boolean DataForkOnly, short *CurrentFork)
+{
+short length;
+int result;
+
+AssertStr(RfDfFilen,"RfDfFilen2Real")
+
+if (DataForkOnly ||
+ (MacZipMode == UnKnown_EF) ||
+ (MacZipMode < JohnnyLee_EF))
+ {
+ *CurrentFork = DataFork;
+ return sstrcpy(RealFn,RfDfFilen);
+ }
+
+result = strncmp(RfDfFilen, ResourceMark, sizeof(ResourceMark)-2);
+if (result == 0)
+ {
+ MacZipMode = NewZipMode_EF;
+ }
+
+switch (MacZipMode)
+ {
+ case JohnnyLee_EF:
+ {
+ sstrcpy(RealFn, RfDfFilen);
+ length = strlen(RealFn); /* determine Fork type */
+ if (RealFn[length-1] == 'd') *CurrentFork = DataFork;
+ else *CurrentFork = ResourceFork;
+ RealFn[length-1] = '\0'; /* simply cut one char */
+ return RealFn;
+ break;
+ }
+
+ case NewZipMode_EF:
+ { /* determine Fork type */
+ result = strncmp(RfDfFilen, ResourceMark, sizeof(ResourceMark)-2);
+ if (result != 0)
+ {
+ *CurrentFork = DataFork;
+ sstrcpy(RealFn, RfDfFilen);
+ return RealFn; /* data-fork */
+ }
+ else
+ {
+ *CurrentFork = ResourceFork;
+ if (strlen(RfDfFilen) > (sizeof(ResourceMark) - 1))
+ {
+ sstrcpy(RealFn, &RfDfFilen[sizeof(ResourceMark)-1]);
+ }
+ else RealFn[0] = '\0';
+ return RealFn; /* resource-fork */
+ }
+ break;
+ }
+ default:
+ {
+ *CurrentFork = NoFork;
+ printerr("RfDfFilen2Real():", -1, MacZipMode,
+ __LINE__, __FILE__, RfDfFilen);
+ return NULL; /* function should never reach this point */
+ }
+ }
+
+printerr("RfDfFilen2Real():", -1, MacZipMode, __LINE__, __FILE__, RfDfFilen);
+return NULL; /* function should never reach this point */
+}
+
+
+
+/*
+** return the applications name (argv[0])
+**
+*/
+
+char *GetAppName(void)
+{
+ProcessSerialNumber psn;
+static Str255 AppName;
+ProcessInfoRec pinfo;
+OSErr err;
+
+GetCurrentProcess(&psn);
+pinfo.processName = AppName;
+pinfo.processInfoLength = sizeof(pinfo);
+pinfo.processAppSpec = NULL;
+
+err = GetProcessInformation(&psn,&pinfo);
+AppName[AppName[0]+1] = 0x00;
+
+return (char *)&AppName[1];
+}
+
+
+
+/*
+** return fullpathname from FSSpec
+**
+*/
+
+char *GetFullPathFromSpec(char *FullPath, FSSpec *Spec, OSErr *err)
+{
+Handle hFullPath;
+short len;
+
+Assert_it(Spec,"GetFullPathFromSpec","")
+
+*err = FSpGetFullPath(Spec, &len, &hFullPath);
+printerr("FSpGetFullPath:", (*err != -43) && (*err != 0), *err,
+ __LINE__, __FILE__, "");
+
+memmove(FullPath, (Handle) *hFullPath, len);
+FullPath[len] = '\0'; /* make c-string */
+
+DisposeHandle((Handle)hFullPath); /* we don't need it any more */
+
+printerr("Warning path length exceeds limit: ", len >= NAME_MAX, len,
+ __LINE__, __FILE__, " chars ");
+
+return FullPath;
+}
+
+
+
+
+/*
+* This function expands a given partial path to a complete path.
+* Path expansions are relative to the running app.
+* This function follows the notation:
+* 1. relative path:
+* a: ":subfolder:filename" -> ":current folder:subfolder:filename"
+* b: "::folder2:filename" -> folder2 is beside the current
+* folder on the same level
+* c: "filename" -> in current folder
+*
+* An absolute path will be returned.
+
+The following characteristics of Macintosh pathnames should be noted:
+
+ A full pathname never begins with a colon, but must contain at
+ least one colon.
+ A partial pathname always begins with a colon separator except in
+ the case where the file partial pathname is a simple file or
+ directory name.
+ Single trailing separator colons in full or partial pathnames are
+ ignored except in the case of full pathnames to volumes.
+ In full pathnames to volumes, the trailing separator colon is required.
+ Consecutive separator colons can be used to ascend a level from a
+ directory to its parent directory. Two consecutive separator colons
+ will ascend one level, three consecutive separator colons will ascend
+ two levels, and so on. Ascending can only occur from a directory;
+ not a file.
+*/
+
+char *GetCompletePath(char *CompletePath, const char *name, FSSpec *Spec,
+ OSErr *err)
+{
+Boolean hasDirName = false;
+char currentdir[NAME_MAX];
+char *tmpPtr;
+unsigned short pathlen;
+
+AssertStr(name,"GetCompletePath")
+Assert_it(Spec,"GetCompletePath","")
+Assert_it((CompletePath != name),"GetCompletePath","")
+
+for (tmpPtr = name; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == ':') hasDirName = true;
+
+if (name[0] != ':') /* case c: path including volume name or only filename */
+ {
+ if (hasDirName)
+ { /* okey, starts with volume name, so it must be a complete path */
+ sstrcpy(CompletePath, name);
+ }
+ else
+ { /* only filename: add cwd and return */
+ getcwd(currentdir, NAME_MAX);
+ sstrcat(currentdir, name);
+ sstrcpy(CompletePath, currentdir);
+ }
+ }
+else if (name[1] == ':') /* it's case b: "::folder2:filename" */
+ {
+ printerr("GetCompletePath ", -1, *err, __LINE__, __FILE__, "not implemented");
+ /* it's not yet implemented; do we really need this case ?*/
+ return NULL;
+ }
+else /* it's case a: ":subfolder:filename" */
+ {
+ getcwd(CompletePath, NAME_MAX); /* we don't need a second colon */
+ CompletePath[strlen(CompletePath)-1] = '\0';
+ sstrcat(CompletePath, name);
+ }
+
+pathlen = strlen(CompletePath);
+*err = FSpLocationFromFullPath(pathlen, CompletePath, Spec);
+
+return CompletePath;
+}
+
+
+
+char *MakeFilenameShorter(const char *LongFilename)
+{
+static char filename[35]; /* contents should be never longer than 32 chars */
+static unsigned char Num = 0; /* change the number for every call */
+ /* this var will rollover without a problem */
+char tempLongFilename[1024], charnum[5];
+char *last_dotpos = tempLongFilename;
+unsigned long full_length = strlen(LongFilename);
+unsigned long ext_length = 0;
+unsigned long num_to_cut = 0;
+long firstpart_length;
+char *tmpPtr;
+short MaxLength = 31;
+
+if (full_length <= MaxLength) /* filename is not long */
+ {
+ return strcpy(filename,LongFilename);
+ }
+
+Num++;
+strcpy(tempLongFilename,LongFilename);
+
+/* Look for the last extension pos */
+for (tmpPtr = tempLongFilename; *tmpPtr; tmpPtr++)
+ if (*tmpPtr == '.') last_dotpos = tmpPtr;
+
+ext_length = strlen(last_dotpos);
+firstpart_length = last_dotpos - tempLongFilename;
+
+if (ext_length > 6) /* up to 5 chars are treated as a */
+ { /* normal extension like ".html" or ".class" */
+ firstpart_length = 0;
+ }
+
+num_to_cut = full_length - MaxLength;
+
+/* number the files to make the names unique */
+sprintf(charnum,"~%x", Num);
+num_to_cut += strlen(charnum);
+
+if (firstpart_length == 0)
+ {
+ firstpart_length = full_length;
+ tempLongFilename[firstpart_length - num_to_cut] = 0;
+ sprintf(filename,"%s%s", tempLongFilename, charnum);
+ }
+else
+ {
+ tempLongFilename[firstpart_length - num_to_cut] = 0;
+ sprintf(filename,"%s%s%s", tempLongFilename, charnum, last_dotpos);
+ }
+
+return filename;
+}
diff --git a/macos/source/pathname.h b/macos/source/pathname.h
new file mode 100644
index 0000000..1a39ed3
--- /dev/null
+++ b/macos/source/pathname.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (c) 1990-2001 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+#ifndef PATHNAME_H
+#define PATHNAME_H 1
+
+
+char *StripPartialDir(char *CompletePath,
+ const char *PartialPath, const char *FullPath);
+
+char *Real2RfDfFilen(char *RfDfFilen, const char *RealPath, short CurrentFork,
+ short MacZipMode, Boolean DataForkOnly);
+char *RfDfFilen2Real(char *RealFn, const char *RfDfFilen, short MacZipMode,
+ Boolean DataForkOnly, short *CurrentFork);
+
+unsigned short GetVolumeFromPath(const char *FullPath, char *VolumeName);
+char *GetCompletePath(char *CompletePath, const char *name, FSSpec *Spec,
+ OSErr *err);
+char *TruncFilename(char *DirPath, const char *FilePath);
+char *GetFilename(char *CompletePath, const char *name);
+char *GetFullPathFromSpec(char *CompletePath, FSSpec *Spec, OSErr *err);
+char *GetFullPathFromID(char *CompletePath, short vRefNum, long dirID,
+ ConstStr255Param name, OSErr *err);
+
+char *GetAppName(void);
+void createArchiveName(char *Path);
+void FindDesktopFolder(char *Path);
+char *FindNewExtractFolder(char *ExtractPath, Boolean uniqueFolder);
+OSErr FSpFindFolder(
+ short vRefNum, /* Volume reference number. */
+ OSType folderType, /* Folder type taken by FindFolder. */
+ Boolean createFolder, /* Should we create it if non-existant. */
+ FSSpec *spec); /* Pointer to resulting directory. */
+
+char *MakeFilenameShorter(const char *LongFilename);
+
+/*
+Rule: UnKnown_EF should always be zero.
+ JohnnyLee_EF, NewZipMode_EF should always greater than all
+ other definitions
+*/
+#define UnKnown_EF 0
+#define TomBrownZipIt1_EF 10
+#define TomBrownZipIt2_EF 20
+#define JohnnyLee_EF 30
+#define NewZipMode_EF 40
+
+
+
+#define ResourceFork -1
+#define DataFork 1
+#define NoFork 0
+
+
+#ifndef NAME_MAX
+#define NAME_MAX 1024
+#endif
+
+#endif /* PATHNAME_H */
diff --git a/macos/source/recurse.c b/macos/source/recurse.c
new file mode 100644
index 0000000..e87db3c
--- /dev/null
+++ b/macos/source/recurse.c
@@ -0,0 +1,442 @@
+/*
+These functions are based on Jim Luther's IterateDirectory() found in MoreFiles
+However, it's heavily modified by Dirk Haase
+*/
+
+/*
+** IterateDirectory: File Manager directory iterator routines.
+**
+** by Jim Luther
+**
+** File: IterateDirectory.c
+**
+** Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc.
+** All rights reserved.
+**
+** You may incorporate this sample code into your applications without
+** restriction, though the sample code has been provided "AS IS" and the
+** responsibility for its operation is 100% yours.
+**
+** IterateDirectory is designed to drop into the MoreFiles sample code
+** library I wrote while in Apple Developer Technical Support
+*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Files.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#include "zip.h"
+#include "macstuff.h"
+#include "helpers.h"
+#include "recurse.h"
+#include "macglob.h"
+#include "pathname.h"
+
+
+
+
+/*****************************************************************************/
+/* Macros, typedefs */
+/*****************************************************************************/
+
+/* The RecurseGlobals structure is used to minimize the amount of
+** stack space used when recursively calling RecurseDirectoryLevel
+** and to hold global information that might be needed at any time.
+*/
+struct RecurseGlobals
+{
+ short vRefNum;
+ CInfoPBRec cPB; /* the parameter block used for
+ PBGetCatInfo calls */
+ unsigned char *itemName; /* the name of the current item */
+ char *FullPath;
+ short FullPathLen;
+ OSErr result; /* temporary holder of results -
+ saves 2 bytes of stack each level */
+ Boolean quitFlag; /* set to true if filter wants to
+ kill interation */
+ unsigned short maxLevels; /* Maximum levels to
+ iterate through */
+ unsigned short currentLevel; /* The current level
+ IterateLevel is on */
+};
+
+typedef struct RecurseGlobals RecurseGlobals;
+typedef RecurseGlobals *RecurseGlobalsPtr;
+
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+extern MacZipGlobals MacZip;
+extern const char ResourceMark[13]; /* "XtraStuf.mac:" var is initialized in file pathname.c */
+extern int extra_fields; /* do not create extra fields if false */
+
+static RecurseGlobals theGlobals;
+
+static unsigned long DirLevels = 0;
+static char *buffer;
+extern int verbose; /* 1=report oddities in zip file structure */
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+int procname(char *filename, int caseflag);
+int MatchWild( char *pPat, char *pStr, int case_sens);
+Boolean IsZipFile(char *name);
+
+static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals);
+static Boolean isRegularItem( RecurseGlobals *Globals);
+static void ProcessFiles(RecurseGlobals *Globals,
+ Boolean hasDataFork, Boolean hasResourceFork);
+static void ProcessDirectory(RecurseGlobals *Globals,
+ Boolean IncludeItem, long DirID);
+static void ProcessItem(RecurseGlobals *Globals, long DirID);
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals)
+{
+char buffer2[23];
+
+ /* if maxLevels is zero, we aren't checking levels */
+ if ( (Globals->maxLevels == 0) ||
+ /* if currentLevel < maxLevels, look at this level */
+ (Globals->currentLevel < Globals->maxLevels) )
+ {
+ short index = 1;
+
+ ++Globals->currentLevel; /* go to next level */
+ if (DirLevels < Globals->currentLevel) DirLevels = Globals->currentLevel;
+ sprintf(buffer2,"Globals->currentLevel: %d",Globals->currentLevel);
+
+ do
+ { /* Isn't C great... What I'd give for a "WITH
+ theGlobals DO" about now... */
+
+ /* Get next source item at the current directory level */
+ Globals->cPB.dirInfo.ioFDirIndex = index;
+ Globals->cPB.dirInfo.ioDrDirID = DirID;
+ Globals->result = PBGetCatInfoSync((CInfoPBPtr)&Globals->cPB);
+
+ ShowCounter(false);
+
+ if ( Globals->result == noErr )
+ {
+ ProcessItem(Globals, DirID);
+ } /* if ( Globals->result == noErr ) */
+
+ ++index; /* prepare to get next item */
+ /* time to fall back a level? */
+ } while ( (Globals->result == noErr) && (!Globals->quitFlag) );
+
+ if ( (Globals->result == fnfErr) || /* fnfErr is OK -
+ it only means we hit
+ the end of this level */
+ (Globals->result == afpAccessDenied) ) /* afpAccessDenied is OK,
+ too - it only means we cannot see inside a directory */
+ {
+ Globals->result = noErr;
+ }
+
+ --Globals->currentLevel; /* return to previous level as we leave */
+ }
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr RecurseDirectory(short vRefNum,
+ long thedirID,
+ ConstStr255Param name,
+ unsigned short maxLevels)
+{
+ OSErr result;
+ short theVRefNum;
+ Boolean isDirectory;
+ long DirID;
+
+ /* Get the real directory ID and make sure it is a directory */
+ result = GetDirectoryID(vRefNum, thedirID, name, &DirID, &isDirectory);
+ if ( result == noErr )
+ {
+ if ( isDirectory == true )
+ {
+ /* Get the real vRefNum */
+ result = DetermineVRefNum(name, vRefNum, &theVRefNum);
+ if ( result == noErr )
+ {
+ /* Set up the globals we need to access from
+ the recursive routine. */
+ theGlobals.cPB.hFileInfo.ioNamePtr = theGlobals.itemName;
+ theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
+ theGlobals.itemName[0] = 0;
+ theGlobals.result = noErr;
+ theGlobals.quitFlag = false;
+ theGlobals.maxLevels = maxLevels;
+ theGlobals.currentLevel = 0; /* start at level 0 */
+
+ /* Here we go into recursion land... */
+ RecurseDirectoryLevel(DirID, &theGlobals);
+
+ result = theGlobals.result; /* set the result */
+ }
+ }
+ else
+ {
+ result = dirNFErr; /* a file was passed instead
+ of a directory */
+ }
+ }
+
+ return ( result );
+}
+
+
+
+/*****************************************************************************/
+
+pascal OSErr FSpRecurseDirectory(const FSSpec *spec,
+ unsigned short maxLevels)
+{
+ OSErr rc;
+
+ theGlobals.vRefNum = spec->vRefNum;
+
+ /* make room for pathnames */
+ theGlobals.itemName = (unsigned char *) StrCalloc(NAME_MAX);
+ theGlobals.FullPath = StrCalloc(NAME_MAX);
+ buffer = StrCalloc(NAME_MAX);
+
+
+ if ((noisy) && (MacZip.DataForkOnly))
+ printf("\n Warning: Datafork only \n");
+
+ /* reset the count to zero */
+ ShowCounter(true);
+
+ if (noisy) leftStatusString("Build File List; Items done:");
+ if (noisy) printf("\n Collecting Filenames ...");
+ rc = RecurseDirectory(spec->vRefNum, spec->parID, spec->name,maxLevels);
+ printerr("RecurseDirectory:",rc,rc,__LINE__,__FILE__,"");
+
+ if (noisy) printf("\n... done \n\n %6d matched files found \n",
+ MacZip.FoundFiles);
+ if (noisy) printf(" %6d folders found in %d Levels \n",
+ MacZip.FoundDirectories,DirLevels);
+
+ if (MacZip.BytesOfData > (1024*1024))
+ if (noisy) printf(" %4.3f MBytes unzipped size\n\n",
+ (float) MacZip.BytesOfData/(1024*1024));
+ else
+ if (noisy) printf(" %4.3f KBytes unzipped size\n\n",
+ (float) MacZip.BytesOfData/1024);
+
+ /* free all memory of pathnames */
+ theGlobals.itemName = (unsigned char *) StrFree((char *)theGlobals.itemName);
+ theGlobals.FullPath = StrFree(theGlobals.FullPath);
+ buffer = StrFree(buffer);
+
+ return rc;
+}
+
+
+
+
+/*
+* Return true if filename == zipfile
+* After the first match no further check will be done !
+*
+*/
+Boolean IsZipFile(char *filen)
+{
+static firstMatch = false;
+
+if (filen == NULL)
+ firstMatch = false;
+
+if (!firstMatch)
+ {
+ if (stricmp(filen, MacZip.ZipFullPath) == 0)
+ {
+ firstMatch = true;
+ return true;
+ }
+ }
+
+return false;
+}
+
+
+
+static Boolean isRegularItem( RecurseGlobals *Globals)
+{
+Boolean isInvisible = false,
+ isAlias = false,
+ isSystem = false;
+
+isSystem = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+ (1 << 12)) == 0 );
+isInvisible = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+ (1 << 14)) == 0 );
+isAlias = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
+ (1 << 15)) == 0);
+
+if (isAlias == true)
+ {
+ return false;
+ }
+
+if (MacZip.IncludeInvisible == true)
+ {
+ return true;
+ }
+
+if ((isSystem == true) ||
+ (isInvisible == true))
+ {
+ return false;
+ }
+
+return true;
+}
+
+
+
+
+static void ProcessFiles(RecurseGlobals *Globals,
+ Boolean hasDataFork, Boolean hasResourceFork)
+{
+ /* some file statistics */
+MacZip.FoundFiles++;
+
+if (hasDataFork == true)
+ {
+ MacZip.BytesOfData =
+ Globals->cPB.hFileInfo.ioFlLgLen +
+ MacZip.BytesOfData;
+ MacZip.CurrentFork = DataFork;
+ MacZip.RawCountOfItems++;
+
+ if (MacZip.DataForkOnly == true)
+ {
+ procname(Globals->FullPath, false);
+ hasResourceFork = false;
+ }
+ else
+ {
+ procname(Real2RfDfFilen(buffer,Globals->FullPath,
+ DataFork, MacZip.MacZipMode,
+ MacZip.DataForkOnly), false);
+ }
+ }
+
+if (hasResourceFork == true)
+ {
+ MacZip.BytesOfData =
+ Globals->cPB.hFileInfo.ioFlRLgLen +
+ MacZip.BytesOfData;
+ MacZip.CurrentFork = ResourceFork;
+ MacZip.RawCountOfItems++;
+
+ procname(Real2RfDfFilen(buffer, Globals->FullPath,
+ ResourceFork, MacZip.MacZipMode,
+ MacZip.DataForkOnly), false);
+ }
+}
+
+
+
+
+static void ProcessDirectory(RecurseGlobals *Globals,
+ Boolean IncludeItem, long DirID)
+{
+OSErr rc;
+
+MacZip.isDirectory = true;
+
+GetFullPathFromID(Globals->FullPath,Globals->vRefNum, DirID,
+ Globals->itemName, &rc);
+
+MacZip.RawCountOfItems++;
+MacZip.FoundDirectories++;
+
+if (MacZip.StoreFoldersAlso)
+ {
+ procname(Globals->FullPath, false);
+ }
+
+ /* We have a directory */
+ if ( !Globals->quitFlag && IncludeItem)
+ {
+ /* Dive again if the IterateFilterProc didn't say "quit" and dir is
+ not an alias */
+ RecurseDirectoryLevel(Globals->cPB.dirInfo.ioDrDirID,
+ Globals);
+ }
+}
+
+
+
+static void ProcessItem(RecurseGlobals *Globals, long DirID)
+{
+OSErr rc;
+Boolean IncludeItem = false, hasDataFork = false;
+Boolean hasResourceFork = false;
+
+IncludeItem = isRegularItem(Globals);
+
+/* Is it a File? */
+if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) == 0 )
+ {
+ PToCCpy(Globals->itemName,MacZip.FileName);
+ MacZip.isDirectory = false;
+
+ hasDataFork = (Globals->cPB.hFileInfo.ioFlLgLen != 0);
+ hasResourceFork = (Globals->cPB.hFileInfo.ioFlRLgLen != 0);
+
+ /* include also files with zero recource- and data-fork */
+ if ((hasDataFork == 0) && (hasResourceFork == 0))
+ hasDataFork = true;
+
+ if ((hasDataFork == 0) &&
+ (hasResourceFork != 0) &&
+ (extra_fields == false))
+ {
+ IncludeItem = false;
+ }
+
+ GetFullPathFromID(Globals->FullPath,Globals->vRefNum,
+ DirID, Globals->itemName, &rc);
+ printerr("GetFullPathFromID:",rc,rc,__LINE__,
+ __FILE__,MacZip.FileName);
+
+ if (IncludeItem && /* don't include the zipfile itself */
+ (!IsZipFile(Globals->FullPath)) )
+ {
+ if (MATCH(MacZip.Pattern, MacZip.FileName, false) == true)
+ {
+ ProcessFiles(Globals, hasDataFork, hasResourceFork);
+ } /* if (MatchWild( MacZip.FileName,MacZip.Pattern ) ==
+ true) */
+ } /* if (!IsZipFile(Globals->FullPath)) */
+ } /* Is it a File? */
+
+/* Is it a directory? */
+if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+ {
+ ProcessDirectory(Globals,IncludeItem, DirID);
+ } /* Is it a directory? */
+}
diff --git a/macos/source/recurse.h b/macos/source/recurse.h
new file mode 100644
index 0000000..cfbc4b0
--- /dev/null
+++ b/macos/source/recurse.h
@@ -0,0 +1,129 @@
+/*
+** IterateDirectory: File Manager directory iterator routines.
+**
+** by Jim Luther
+**
+** File: IterateDirectory.h
+**
+** Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc.
+** All rights reserved.
+**
+** You may incorporate this sample code into your applications without
+** restriction, though the sample code has been provided "AS IS" and the
+** responsibility for its operation is 100% yours.
+**
+** IterateDirectory is designed to drop into the MoreFiles sample code
+** library I wrote while in Apple Developer Technical Support
+*/
+
+#ifndef __RECURSEDIRECTORY__
+#define __RECURSEDIRECTORY__
+
+#include <Types.h>
+#include <Files.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*****************************************************************************/
+
+pascal OSErr RecurseDirectory(short vRefNum,
+ long dirID,
+ ConstStr255Param name,
+ unsigned short maxLevels );
+/* Iterate (scan) through a directory's content.
+ The IterateDirectory function performs a recursive iteration (scan) of
+ the specified directory and calls your IterateFilterProc function once
+ for each file and directory found.
+
+ The maxLevels parameter lets you control how deep the recursion goes.
+ If maxLevels is 1, IterateDirectory only scans the specified directory;
+ if maxLevels is 2, IterateDirectory scans the specified directory and
+ one subdirectory below the specified directory; etc. Set maxLevels to
+ zero to scan all levels.
+
+ The yourDataPtr parameter can point to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ vRefNum input: Volume specification.
+ dirID input: Directory ID.
+ name input: Pointer to object name, or nil when dirID
+ specifies a directory that's the object.
+ maxLevels input: Maximum number of directory levels to scan or
+ zero to scan all directory levels.
+ iterateFilter input: A pointer to the routine you want called once
+ for each file and directory found by
+ IterateDirectory.
+ yourDataPtr input: A pointer to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ Result Codes
+ noErr 0 No error
+ nsvErr -35 No such volume
+ ioErr -36 I/O error
+ bdNamErr -37 Bad filename
+ fnfErr -43 File not found
+ paramErr -50 No default volume or iterateFilter was NULL
+ dirNFErr -120 Directory not found or incomplete pathname
+ or a file was passed instead of a directory
+ afpAccessDenied -5000 User does not have the correct access
+ afpObjectTypeErr -5025 Directory not found or incomplete pathname
+
+ __________
+
+ See also: RecurseFilterProcPtr, FSpRecurseDirectory
+*/
+
+/*****************************************************************************/
+
+pascal OSErr FSpRecurseDirectory(const FSSpec *spec,
+ unsigned short maxLevels);
+/* Iterate (scan) through a directory's content.
+ The FSpIterateDirectory function performs a recursive iteration (scan)
+ of the specified directory and calls your IterateFilterProc function once
+ for each file and directory found.
+
+ The maxLevels parameter lets you control how deep the recursion goes.
+ If maxLevels is 1, FSpIterateDirectory only scans the specified directory;
+ if maxLevels is 2, FSpIterateDirectory scans the specified directory and
+ one subdirectory below the specified directory; etc. Set maxLevels to
+ zero to scan all levels.
+
+ The yourDataPtr parameter can point to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ spec input: An FSSpec record specifying the directory to scan.
+ maxLevels input: Maximum number of directory levels to scan or
+ zero to scan all directory levels.
+ iterateFilter input: A pointer to the routine you want called once
+ for each file and directory found by
+ FSpIterateDirectory.
+ yourDataPtr input: A pointer to whatever data structure you might
+ want to access from within the IterateFilterProc.
+
+ Result Codes
+ noErr 0 No error
+ nsvErr -35 No such volume
+ ioErr -36 I/O error
+ bdNamErr -37 Bad filename
+ fnfErr -43 File not found
+ paramErr -50 No default volume or iterateFilter was NULL
+ dirNFErr -120 Directory not found or incomplete pathname
+ afpAccessDenied -5000 User does not have the correct access
+ afpObjectTypeErr -5025 Directory not found or incomplete pathname
+
+ __________
+
+ See also: RecurseFilterProcPtr, RecurseDirectory
+*/
+
+
+
+/*****************************************************************************/
+
+
+
+#endif /* __RECURSEDIRECTORY__ */
diff --git a/macos/source/unixlike.c b/macos/source/unixlike.c
new file mode 100644
index 0000000..4eb55da
--- /dev/null
+++ b/macos/source/unixlike.c
@@ -0,0 +1,313 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ unixlike.c
+
+ Macintosh-specific routines to emulate unixfunctions.
+
+ ---------------------------------------------------------------------------*/
+
+/*****************************************************************************/
+/* Includes */
+/*****************************************************************************/
+
+#include "zip.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <sound.h>
+
+#include "unixlike.h"
+#include "helpers.h"
+#include "pathname.h"
+#include "macstuff.h"
+#include "macglob.h"
+#include "mactime.h"
+
+/*****************************************************************************/
+/* Global Vars */
+/*****************************************************************************/
+
+extern MacZipGlobals MacZip;
+extern int errno;
+
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MacStat --
+ *
+ * This function replaces the library version of stat. The stat
+ * function provided by most Mac compiliers is rather broken and
+ * incomplete.
+ *
+ * Results:
+ * See stat documentation.
+ *
+ * Side effects:
+ * See stat documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int Zmacstat(const char *Fname, struct stat *buf)
+{
+ OSErr err, rc;
+ short fullPathLength;
+ Handle hFullPath;
+ char path[NAME_MAX], path2[NAME_MAX];
+ HVolumeParam vpb;
+ static unsigned long count_of_files = 0;
+
+ AssertStr(Fname,Fname)
+ Assert_it(buf,"","")
+
+ UserStop();
+
+ memset(buf, 0, sizeof(buf)); /* zero out all fields */
+
+ RfDfFilen2Real(path2, Fname, MacZip.MacZipMode, MacZip.DataForkOnly,
+ &MacZip.CurrentFork);
+ GetCompletePath(path, path2, &MacZip.fileSpec, &err);
+ err = PrintUserHFSerr((err != -43) && (err != 0), err, path);
+ printerr("GetCompletePath:", err, err, __LINE__, __FILE__, path);
+
+ if (err != noErr) {
+ errno = err;
+ return -1;
+ }
+
+ /* Collect here some more information, it's not related to Macstat.
+ (note: filespec gets changed later in this function) */
+ /* clear string-buffer */
+ memset(MacZip.FullPath, 0x00, sizeof(MacZip.FullPath));
+ rc = FSpGetFullPath(&MacZip.fileSpec, &fullPathLength, &hFullPath);
+ strncpy(MacZip.FullPath, *hFullPath, fullPathLength);
+ DisposeHandle(hFullPath); /* we don't need it any more */
+ /* Collect some more information not related to Macstat */
+
+
+ /*
+ * Fill the fpb & vpb struct up with info about file or directory.
+ */
+
+ FSpGetDirectoryID(&MacZip.fileSpec, &MacZip.dirID, &MacZip.isDirectory);
+ vpb.ioVRefNum = MacZip.fpb.hFileInfo.ioVRefNum = MacZip.fileSpec.vRefNum;
+ vpb.ioNamePtr = MacZip.fpb.hFileInfo.ioNamePtr = MacZip.fileSpec.name;
+
+ if (MacZip.isDirectory) {
+ MacZip.fpb.hFileInfo.ioDirID = MacZip.fileSpec.parID;
+ /*
+ * Directories are executable by everyone.
+ */
+ buf->st_mode |= UNX_IXUSR | UNX_IXGRP | UNX_IXOTH | UNX_IFDIR;
+ } else {
+ MacZip.fpb.hFileInfo.ioDirID = MacZip.dirID;
+ }
+
+ MacZip.fpb.hFileInfo.ioFDirIndex = 0;
+ err = PBGetCatInfoSync((CInfoPBPtr)&MacZip.fpb);
+
+ if (err == noErr) {
+ vpb.ioVolIndex = 0;
+ err = PBHGetVInfoSync((HParmBlkPtr)&vpb);
+ if (err == noErr && buf != NULL) {
+ /*
+ * Files are always readable by everyone.
+ */
+ buf->st_mode |= UNX_IRUSR | UNX_IRGRP | UNX_IROTH;
+
+ /*
+ * Use the Volume Info & File Info to fill out stat buf.
+ */
+ if (MacZip.fpb.hFileInfo.ioFlAttrib & 0x10) {
+ buf->st_mode |= UNX_IFDIR;
+ buf->st_nlink = 2;
+ } else {
+ buf->st_nlink = 1;
+ if (MacZip.fpb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) {
+ buf->st_mode |= UNX_IFLNK;
+ } else {
+ buf->st_mode |= UNX_IFREG;
+ }
+ }
+
+ if (MacZip.fpb.hFileInfo.ioFlFndrInfo.fdType == 'APPL') {
+ /*
+ * Applications are executable by everyone.
+ */
+ buf->st_mode |= UNX_IXUSR | UNX_IXGRP | UNX_IXOTH;
+ }
+ if ((MacZip.fpb.hFileInfo.ioFlAttrib & 0x01) == 0){
+ /*
+ * If not locked, then everyone has write acces.
+ */
+ buf->st_mode |= UNX_IWUSR | UNX_IWGRP | UNX_IWOTH;
+ }
+
+ buf->st_ino = MacZip.fpb.hFileInfo.ioDirID;
+ buf->st_dev = MacZip.fpb.hFileInfo.ioVRefNum;
+ buf->st_uid = -1;
+ buf->st_gid = -1;
+ buf->st_rdev = 0;
+
+ if (MacZip.CurrentFork == ResourceFork)
+ buf->st_size = MacZip.fpb.hFileInfo.ioFlRLgLen;
+ else
+ buf->st_size = MacZip.fpb.hFileInfo.ioFlLgLen;
+
+ buf->st_blksize = vpb.ioVAlBlkSiz;
+ buf->st_blocks = (buf->st_size + buf->st_blksize - 1)
+ / buf->st_blksize;
+
+ /*
+ * The times returned by the Mac file system are in the
+ * local time zone. We convert them to GMT so that the
+ * epoch starts from GMT. This is also consistent with
+ * what is returned from "clock seconds".
+ */
+ if (!MacZip.isDirectory) {
+ MacZip.CreatDate = MacZip.fpb.hFileInfo.ioFlCrDat;
+ MacZip.ModDate = MacZip.fpb.hFileInfo.ioFlMdDat;
+ MacZip.BackDate = MacZip.fpb.hFileInfo.ioFlBkDat;
+ } else {
+ MacZip.CreatDate = MacZip.fpb.dirInfo.ioDrCrDat;
+ MacZip.ModDate = MacZip.fpb.dirInfo.ioDrMdDat;
+ MacZip.BackDate = MacZip.fpb.dirInfo.ioDrBkDat;
+ }
+
+#ifdef IZ_CHECK_TZ
+ if (!zp_tz_is_valid)
+ {
+ MacZip.HaveGMToffset = false;
+ MacZip.Md_UTCoffs = 0L;
+ MacZip.Cr_UTCoffs = 0L;
+ MacZip.Bk_UTCoffs = 0L;
+ }
+ else
+#endif
+ {
+ /* Do not use GMT offsets when Md_UTCoffs calculation
+ * fails, since this time stamp is used for time
+ * comparisons in Zip and UnZip operations.
+ * We do not bother when GMT offset calculation fails for
+ * any other time stamp value. Instead we simply assume
+ * a default value of 0.
+ */
+ MacZip.HaveGMToffset =
+ GetGMToffsetMac(MacZip.ModDate, &MacZip.Md_UTCoffs);
+ if (MacZip.HaveGMToffset) {
+ GetGMToffsetMac(MacZip.CreatDate, &MacZip.Cr_UTCoffs);
+ GetGMToffsetMac(MacZip.BackDate, &MacZip.Bk_UTCoffs);
+ } else {
+ MacZip.Cr_UTCoffs = 0L;
+ MacZip.Bk_UTCoffs = 0L;
+ }
+ }
+#ifdef DEBUG_TIME
+ {
+ printf("\nZmacstat: MacZip.HaveGMToffset: %d",
+ MacZip.HaveGMToffset);
+ printf("\nZmacstat: Mac modif: %lu local -> UTOffset: %d",
+ MacZip.ModDate, MacZip.Md_UTCoffs);
+ printf("\nZmacstat: Mac creat: %lu local -> UTOffset: %d",
+ MacZip.CreatDate, MacZip.Cr_UTCoffs);
+ printf("\nZmacstat: Mac back: %lu local -> UTOffset: %d",
+ MacZip.BackDate, MacZip.Bk_UTCoffs);
+ }
+#endif /* DEBUG_TIME */
+
+
+ buf->st_mtime = MacFtime2UnixFtime(MacZip.ModDate);
+ buf->st_ctime = MacFtime2UnixFtime(MacZip.CreatDate);
+ buf->st_atime = buf->st_mtime;
+
+#ifdef DEBUG_TIME
+ {
+ printf("\nZmacstat: Unix modif: %lu UTC; Mac: %lu local",
+ buf->st_mtime, MacZip.ModDate);
+ printf("\nZmacstat: Unix creat: %lu UTC; Mac: %lu local\n",
+ buf->st_ctime, MacZip.CreatDate);
+ }
+#endif /* DEBUG_TIME */
+
+ if (noisy)
+ {
+ if (MacZip.StatingProgress)
+ {
+ count_of_files++;
+ InformProgress(MacZip.RawCountOfItems, count_of_files );
+ }
+ else
+ count_of_files = 0;
+ }
+ }
+ }
+
+ if (err != noErr) {
+ errno = err;
+ }
+
+ MacZip.isMacStatValid = true;
+ return (err == noErr ? 0 : -1);
+}
+
+
+
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * chmod --
+ *
+ * Results:
+ * See chmod documentation.
+ *
+ * Side effects:
+ * See chmod documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int chmod(char *path, int mode)
+{
+ HParamBlockRec hpb;
+ OSErr err;
+
+ hpb.fileParam.ioNamePtr = C2PStr(path);
+ hpb.fileParam.ioVRefNum = 0;
+ hpb.fileParam.ioDirID = 0;
+
+ if (mode & 0200) {
+ err = PBHRstFLockSync(&hpb);
+ } else {
+ err = PBHSetFLockSync(&hpb);
+ }
+
+ if (err != noErr) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/macos/source/unixlike.h b/macos/source/unixlike.h
new file mode 100644
index 0000000..e61a354
--- /dev/null
+++ b/macos/source/unixlike.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+/*
+ * Directory Operations for Mac based on BSD 4.3 <macdir.h>
+ * By Jason Linhart, January 1997
+ */
+
+#ifndef _UNIXLIKE_H
+#define _UNIXLIKE_H 1
+
+#include <stat.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX 2048
+#endif
+
+#define UNX_IFMT 0170000 /* Unix file type mask */
+#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */
+#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */
+#define UNX_IFREG 0100000 /* Unix regular file */
+#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */
+#define UNX_IFDIR 0040000 /* Unix directory */
+#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */
+#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */
+
+#define UNX_ISUID 04000 /* Unix set user id on execution */
+#define UNX_ISGID 02000 /* Unix set group id on execution */
+#define UNX_ISVTX 01000 /* Unix directory permissions control */
+#define UNX_ENFMT UNX_ISGID /* Unix record locking enforcement flag */
+
+#define UNX_IRWXU 00700 /* Unix read, write, execute: owner */
+#define UNX_IRUSR 00400 /* Unix read permission: owner */
+#define UNX_IWUSR 00200 /* Unix write permission: owner */
+#define UNX_IXUSR 00100 /* Unix execute permission: owner */
+
+#define UNX_IRWXG 00070 /* Unix read, write, execute: group */
+#define UNX_IRGRP 00040 /* Unix read permission: group */
+#define UNX_IWGRP 00020 /* Unix write permission: group */
+#define UNX_IXGRP 00010 /* Unix execute permission: group */
+
+#define UNX_IRWXO 00007 /* Unix read, write, execute: other */
+#define UNX_IROTH 00004 /* Unix read permission: other */
+#define UNX_IWOTH 00002 /* Unix write permission: other */
+#define UNX_IXOTH 00001 /* Unix execute permission: other */
+
+/* historical file modes */
+#define S_IREAD 0x100
+#define S_IWRITE 0x80
+#define S_IEXEC 0x40
+
+
+#define isatty(arg) 1
+
+
+#define EINVAL 22 /* Invalid argument */
+#define ENAMETOOLONG 63 /* File name too long */
+
+
+struct dirent {
+ char d_name[NAME_MAX];
+};
+
+/*
+ * The following definitions are usually found in fcntl.h.
+ * However, MetroWerks has screwed that file up a couple of times
+ * and all we need are the defines.
+ */
+#define O_APPEND 0x0100 /* open the file in append mode */
+#define O_CREAT 0x0200 /* create the file if it doesn't exist */
+#define O_EXCL 0x0400 /* if the file exists don't create it again */
+#define O_TRUNC 0x0800 /* truncate the file after opening it */
+
+
+int Zmacstat (const char *path, struct stat *buf);
+int chmod(char *path, int mode);
+
+
+#include "macstuff.h"
+
+#endif /* _UNIXLIKE_H */
diff --git a/macos/source/zip_rc.hqx b/macos/source/zip_rc.hqx
new file mode 100644
index 0000000..99e0d25
--- /dev/null
+++ b/macos/source/zip_rc.hqx
@@ -0,0 +1,43 @@
+(This file must be converted with BinHex 4.0)
+:#RTTF#jbBbjcDA3!8dP84&0*9#%!N!3([`#3"&(E8dP8)3!"!!!([h*-BA8#Q3#
+3!aDCQ3d!"RTTF#jbB`!!&[Bi"2[rG!"-5QS!N!1!!*!%"32,j+m2!*!Drj!%8P0
+53e*6483"",#mXHDaqlGG!!!GmJ#3"JFj!*!%6Mi!N!MGc!`!P@6pq1R*k4&+Z,d
+p"5$(b(-Upcc#j%EiHCfjPTq%8h+X8d)MR$`rF[b9Vh`pTLc2jqZ9r'RNq9VN1'&
+'MMmj6Sk6#5HFc0J4lN8iHFU2--,*K%Z1NIR+#1XNR("#bE-)2I+FF$*G@H6BL+`
+*!&6IV1ml1d+22#-$4UEm*#01"T`m*4`Ji(03ThM'$-EBilf-V8-e6Q8bXEVD@Xi
+2bilcmGEY"lV6QGjZrK)I1CKZ$BfR4pSbLD'f`F'qVPKb+*(-*V2CPLfaGj1CE+a
+Z+-$kpr4hpHrCf@d%f66E!A2P-rA6phmUj)QrdYP4r[6)H+cZF"hRV``NHSG5`b!
+F6-0YBZ$!JH&%#frIb,2TmH4`LVGN4c1(%U1Q8#cf)P44dU"#-`D)I($H4I5qc[j
+NJLI5)qpN5)Ic[S(-`-&1H(U2L*U'-H`1Y1p&qc#*YVk4(RNUbp(ae(#'R,B[d%B
+(Nd40$id1C`FhmUlKNBmbkAf$Sra8qpDYcm0,H%GIhbiej(!EESbmC+a*'3dqdlC
+j)%*H#+!,D!K4#J#3!$9H-J)mB*6L!50R"%"&hi6DD*61[-qq22%f1hkXPq@r)'`
+(1hjQJ19cKP'bY0#60RQ3!&kd,r))mj-X,LBCCa&CeiX#f`ibZ$9##+[1HUJ34G5
+584+#&@p9i[UDj-&PD2rAi0qYdMpMQ""M8FLBT`#FUMje-i6rVXl2qI`jK@XY#eH
++%JH[5(`6,qEcH@K,(FfA4rZDNG,4mp60fALH@TT,SC!!5Sf0$HHP31&mP"AfKN)
+K-!N[&XjM@##`1I,(a"V"#L%@#U9'*'lT-5CaU8GqpLTFkUP"%klmfMLJ1QpH5r2
+djNdfhIXJFIqqN!!&1QHe$jUlHF`jZ2I41X8k$@ZbKF1C2"Cq6YZaF(Z+5Yra&63
+"alCh62Vm6N(RqR90&)#m`cE3mILqV`@qBmcQkf0"9Ei%#**RRRpcS0DmV!N6DB-
+&#R112Ym4-1d)GJ(R0,i,0!TEJ!%$#Mj$SFqp80)XU4&"+j!!DmFJk)S2*[(KNMR
+mHApd)4Im@I2aqEBrpd,EVi3ehd@qETI[eprhmmlp0UGjqhe`q#[[Ljk#GDclAll
+[P91j$d[[ir`4X1LcbmVcI$8cCd49rY*`E2l+F1l-Uk0CV,edY8%d('d@pD*qVRk
+L@64FE9KlU9Q%E`3$i@+cD"BSp)'26f,8K%[iL[#3!$-h&aDPY5L2CJBBpF5Kh5k
++ASJVqckQ9kG`*C95rEka+29B5U+f"eYIqF&ZC()P-%GbHXQ44)a!l[Z9q3[c5Z!
+aN!!pGHT"X#q,IJ$8lG#i224dkNXMhd,#3I"ap4JkEk@YlrKEp1r14erRqIYVJY@
+RbX4G0GVTc4A5A20`[E`GcX60GGI#0@$KHMqfFB9BIV4&%kr6+kH*J`(FR3lKcJj
+pNqpN!JiZ-`'&1jQ!a*e-31RCQB$%R8c!dY1CJ19(C`+@AjGIa[qCCq8qH,K8FA%
+LH$LpGbZiFpp0ehUR[lZTL-[HU3T8q*FVkd5&AaDBjrX##ha2S$UImK6,r-Z9MDM
+#PaVqNfUH+VqmXplAGpG!G`k,I&I!i[ZC`J,Iba3@rEQC`J,Iba5@rFQGIhNq5h`
+r-lM2ArAJIYjp(jEjYX!5he+i`cIhZRrjYq)%rjNh@"K4Ej!!V8&p!,8@0C*$l3L
+bk#`f"%i9DMaRk,i*YC&aj0dFH6G(hXf4Gh2Nh4ajYp5aY(5[I@a#hBBDeh9E'*X
+Kq3q,)QS*99$0SCj&R68Va[9Ie6lJ9444KDk%dDE9%CrPQhJ,hbD#)RJ8936RJK1
+bjb%HMTILXr&#r&Um++SIZ#*1fAP1hM-c'CG*VekG*BkGApkj'DZA13GkPA1JPcN
+(iC4c%*m@1&[2l0@LLCK%pFUBG%kj4M@2,@pY&UjA+*Y2#Zil5%pF&GI[LBAVh-2
+$3I"aCG,5ekC[qL[MlZ1QRP32Ga5YQFY`Cf-[rZ!JX+GrCir-1R)J6J!jdY[ekRU
+IXFT6',*jNmH[B69Hq&&6$N-NlS3K8Xm03mM2+VTKb253!iSqNDRHIKqNq$hqV6$
+%pVF8KPMc@68N$0Q#[KXH1UJL$1P'',*PpB``C"5M'eXG)JbTfDal(BB!AfdN$-'
+cjq2P-%6bli8Kq,pej"NCErJr%NGk[[Pkpa44M+pBl4Mq$SC![ij'pZ[3j20d)N[
+i$qR%J5hSI`01r3hJcl+!m54`kMY9f'+N1PrYaRqe4SCq@E8Hr)$%dK,,5@`LdR2
+b$cBKPr+"5-q*AH`)BBm-4AUqlG-DHk"a9QQ`Yi"0+Beefb-pTlj6'Z(2`,ZS0"j
++!KY9'SpQ-0f,5U2Q'(Lr+Sd(h`3fV65DpX2VT0+)[!EHKdUMS4ABTdVMX4IJG8T
+T'*pJ6K'P8IXk0+iTMFB8I'L[i9r!Qp6c`!dlH9,2idGJTp9PD'b(MjH9AZ0cQ02
+TqYdI$#8c2*2-$Kr+**,r!`#3!dm4!!!:
diff --git a/macos/zipup.h b/macos/zipup.h
new file mode 100644
index 0000000..ce2af4a
--- /dev/null
+++ b/macos/zipup.h
@@ -0,0 +1,25 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#ifndef O_RDONLY
+# include <fcntl.h>
+#endif
+
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+
+typedef int ftype;
+
+
+#define zopen(n,p) MacOpen(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0
+
+