Browse Source

+ Initial implementation

michael 25 years ago
parent
commit
48db2151bf
5 changed files with 4892 additions and 0 deletions
  1. 1117 0
      packages/zip/Makefile
  2. 16 0
      packages/zip/Makefile.fpc
  3. 3357 0
      packages/zip/unzip.pas
  4. 187 0
      packages/zip/unzipdll.pas
  5. 215 0
      packages/zip/ziptypes.pas

+ 1117 - 0
packages/zip/Makefile

@@ -0,0 +1,1117 @@
+#
+# Makefile generated by fpcmake v0.99.13 [2000/02/18]
+#
+
+defaultrule: all
+
+#####################################################################
+# Autodetect OS (Linux or Dos or Windows NT)
+# define inlinux when running under linux
+# define inWinNT when running under WinNT
+#####################################################################
+
+# We need only / in the path
+override PATH:=$(subst \,/,$(PATH))
+
+# Search for PWD and determine also if we are under linux
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(subst ;, ,$(PATH)))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(subst :, ,$(PATH)))))
+ifeq ($(PWD),)
+nopwd:
+	@echo You need the GNU utils package to use this Makefile!
+	@echo Get ftp://ftp.freepascal.org/pub/fpc/dist/go32v2/utilgo32.zip
+	@exit
+else
+inlinux=1
+endif
+else
+PWD:=$(firstword $(PWD))
+endif
+
+# Detect NT - NT sets OS to Windows_NT
+ifndef inlinux
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+endif
+endif
+
+# Detect OS/2 - OS/2 has OS2_SHELL defined
+ifndef inlinux
+ifndef inWinNT
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+endif
+
+# The extension of executables
+ifdef inlinux
+EXEEXT=
+else
+EXEEXT=.exe
+endif
+
+# The path which is searched separated by spaces
+ifdef inlinux
+SEARCHPATH=$(subst :, ,$(PATH))
+else
+SEARCHPATH=$(subst ;, ,$(PATH))
+endif
+
+# Base dir
+ifdef PWD
+BASEDIR:=$(shell $(PWD))
+else
+BASEDIR=.
+endif
+
+#####################################################################
+# FPC version/target Detection
+#####################################################################
+
+# What compiler to use ?
+ifndef FPC
+# Compatibility with old makefiles
+ifdef PP
+FPC=$(PP)
+else
+ifdef inOS2
+FPC=ppos2
+else
+FPC=ppc386
+endif
+endif
+endif
+override FPC:=$(subst $(EXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(EXEEXT)
+
+# Target OS
+ifndef OS_TARGET
+OS_TARGET:=$(shell $(FPC) -iTO)
+endif
+
+# Source OS
+ifndef OS_SOURCE
+OS_SOURCE:=$(shell $(FPC) -iSO)
+endif
+
+# Target CPU
+ifndef CPU_TARGET
+CPU_TARGET:=$(shell $(FPC) -iTP)
+endif
+
+# Source CPU
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(shell $(FPC) -iSP)
+endif
+
+# FPC version
+ifndef FPC_VERSION
+FPC_VERSION:=$(shell $(FPC) -iV)
+endif
+
+export FPC OS_TARGET OS_SOURCE CPU_TARGET CPU_SOURCE FPC_VERSION
+
+#####################################################################
+# FPCDIR Setting
+#####################################################################
+
+# Test FPCDIR to look if the RTL dir exists
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=wrong
+endif
+endif
+else
+override FPCDIR=wrong
+endif
+
+# Default FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR=../..
+ifeq ($(wildcard $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=wrong
+endif
+endif
+endif
+
+# Detect FPCDIR
+ifeq ($(FPCDIR),wrong)
+ifdef inlinux
+override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=/usr/lib/fpc/$(FPC_VERSION)
+endif
+else
+override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))))
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(FPCDIR)/rtl),)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+endif
+
+ifndef PACKAGESDIR
+PACKAGESDIR=$(FPCDIR)/packages
+endif
+ifndef TOOLKITSDIR
+TOOLKITSDIR=
+endif
+ifndef COMPONENTSDIR
+COMPONENTSDIR=
+endif
+
+# Create units dir
+ifneq ($(FPCDIR),.)
+UNITSDIR=$(FPCDIR)/units/$(OS_TARGET)
+endif
+
+#####################################################################
+# User Settings
+#####################################################################
+
+
+# Targets
+
+override UNITOBJECTS+=ziptypes unzip
+ifeq ($(OS_TARGET),os2)
+override UNITOBJECTS+=unzipdll
+endif
+
+# Clean
+
+
+# Install
+
+ZIPTARGET=install
+
+# Defaults
+
+
+# Directories
+
+
+# Packages
+
+override PACKAGES+=rtl
+
+# Libraries
+
+
+# Info
+
+INFOTARGET=fpc_infocfg fpc_infoobjects fpc_infoinstall 
+
+#####################################################################
+# Shell tools
+#####################################################################
+
+# echo
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=echo
+ECHOE:=echo
+else
+ECHO:=$(firstword $(ECHO))
+ECHOE=$(ECHO) -E
+endif
+else
+ECHO:=$(firstword $(ECHO))
+ECHOE=$(ECHO) -E
+endif
+endif
+
+# To copy pograms
+ifndef COPY
+COPY:=cp -fp
+endif
+
+# Copy a whole tree
+ifndef COPYTREE
+COPYTREE:=cp -rfp
+endif
+
+# To move pograms
+ifndef MOVE
+MOVE:=mv -f
+endif
+
+# Check delete program
+ifndef DEL
+DEL:=rm -f
+endif
+
+# Check deltree program
+ifndef DELTREE
+DELTREE:=rm -rf
+endif
+
+# To install files
+ifndef INSTALL
+ifdef inlinux
+INSTALL:=install -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+
+# To install programs
+ifndef INSTALLEXE
+ifdef inlinux
+INSTALLEXE:=install -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+
+# To make a directory.
+ifndef MKDIR
+ifdef inlinux
+MKDIR:=install -m 755 -d
+else
+MKDIR:=ginstall -m 755 -d
+endif
+endif
+
+export ECHO ECHOE COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+
+#####################################################################
+# Default Tools
+#####################################################################
+
+# assembler, redefine it if cross compiling
+ifndef AS
+AS=as
+endif
+
+# linker, but probably not used
+ifndef LD
+LD=ld
+endif
+
+# ppas.bat / ppas.sh
+ifdef inlinux
+PPAS=ppas.sh
+else
+ifdef inOS2
+PPAS=ppas.cmd
+else
+PPAS=ppas.bat
+endif
+endif
+
+# ldconfig to rebuild .so cache
+ifdef inlinux
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+
+# ppumove
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE=
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+
+# ppufiles
+ifndef PPUFILES
+PPUFILES:=$(strip $(wildcard $(addsuffix /ppufiles$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUFILES),)
+PPUFILES=
+else
+PPUFILES:=$(firstword $(PPUFILES))
+endif
+endif
+export PPUFILES
+
+# Look if UPX is found for go32v2 and win32. We can't use $UPX becuase
+# upx uses that one itself (PFV)
+ifndef UPXPROG
+ifeq ($(OS_TARGET),go32v2)
+UPXPROG:=1
+endif
+ifeq ($(OS_TARGET),win32)
+UPXPROG:=1
+endif
+ifdef UPXPROG
+UPXPROG:=$(strip $(wildcard $(addsuffix /upx$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(UPXPROG),)
+UPXPROG=
+else
+UPXPROG:=$(firstword $(UPXPROG))
+endif
+else
+UPXPROG=
+endif
+endif
+export UPXPROG
+
+# ZipProg, you can't use Zip as the var name (PFV)
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG=
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+
+ZIPOPT=-9
+ZIPEXT=.zip
+
+# Tar
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(EXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG=
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+
+ifeq ($(USETAR),bz2)
+TAROPT=vI
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+
+#####################################################################
+# Default extensions
+#####################################################################
+
+# Default needed extensions (Go32v2,Linux)
+LOADEREXT=.as
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+RSTEXT=.rst
+FPCMADE=fpcmade
+
+# Go32v1
+ifeq ($(OS_TARGET),go32v1)
+PPUEXT=.pp1
+OEXT=.o1
+ASMEXT=.s1
+SMARTEXT=.sl1
+STATICLIBEXT=.a1
+SHAREDLIBEXT=.so1
+FPCMADE=fpcmade.v1
+endif
+
+# Go32v2
+ifeq ($(OS_TARGET),go32v2)
+FPCMADE=fpcmade.dos
+endif
+
+# Linux
+ifeq ($(OS_TARGET),linux)
+FPCMADE=fpcmade.lnx
+endif
+
+# Win32
+ifeq ($(OS_TARGET),win32)
+PPUEXT=.ppw
+OEXT=.ow
+ASMEXT=.sw
+SMARTEXT=.slw
+STATICLIBEXT=.aw
+SHAREDLIBEXT=.dll
+FPCMADE=fpcmade.w32
+endif
+
+# OS/2
+ifeq ($(OS_TARGET),os2)
+PPUEXT=.ppo
+ASMEXT=.so2
+OEXT=.oo2
+SMARTEXT=.so
+STATICLIBEXT=.ao2
+SHAREDLIBEXT=.dll
+FPCMADE=fpcmade.os2
+endif
+
+# library prefix
+LIBPREFIX=lib
+ifeq ($(OS_TARGET),go32v2)
+LIBPREFIX=
+endif
+ifeq ($(OS_TARGET),go32v1)
+LIBPREFIX=
+endif
+
+# determine which .pas extension is used
+ifndef PASEXT
+ifdef EXEOBJECTS
+override TESTPAS:=$(strip $(wildcard $(addsuffix .pas,$(firstword $(EXEOBJECTS)))))
+else
+override TESTPAS:=$(strip $(wildcard $(addsuffix .pas,$(firstword $(UNITOBJECTS)))))
+endif
+ifeq ($(TESTPAS),)
+PASEXT=.pp
+else
+PASEXT=.pas
+endif
+endif
+
+
+# Check if the dirs really exists, else turn it off
+ifeq ($(wildcard $(UNITSDIR)),)
+UNITSDIR=
+endif
+ifeq ($(wildcard $(TOOLKITSDIR)),)
+TOOLKITSDIR=
+endif
+ifeq ($(wildcard $(PACKAGESDIR)),)
+PACKAGESDIR=
+endif
+ifeq ($(wildcard $(COMPONENTSDIR)),)
+COMPONENTSDIR=
+endif
+
+
+# PACKAGESDIR packages
+
+PACKAGERTL=1
+
+ifdef PACKAGERTL
+ifneq ($(wildcard $(FPCDIR)/rtl),)
+ifneq ($(wildcard $(FPCDIR)/rtl/$(OS_TARGET)),)
+PACKAGEDIR_RTL=$(FPCDIR)/rtl/$(OS_TARGET)
+else
+PACKAGEDIR_RTL=$(FPCDIR)/rtl
+endif
+ifeq ($(wildcard $(PACKAGEDIR_RTL)/$(FPCMADE)),)
+override COMPILEPACKAGES+=package_rtl
+package_rtl:
+	$(MAKE) -C $(PACKAGEDIR_RTL) all
+endif
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+else
+PACKAGEDIR_RTL=
+ifneq ($(wildcard $(UNITSDIR)/rtl),)
+ifneq ($(wildcard $(UNITSDIR)/rtl/$(OS_TARGET)),)
+UNITDIR_RTL=$(UNITSDIR)/rtl/$(OS_TARGET)
+else
+UNITDIR_RTL=$(UNITSDIR)/rtl
+endif
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override NEEDUNITDIR+=$(UNITDIR_RTL)
+endif
+endif
+
+
+#####################################################################
+# Default Directories
+#####################################################################
+
+# set the prefix directory where to install everything
+ifndef PREFIXINSTALLDIR
+ifdef inlinux
+PREFIXINSTALLDIR=/usr
+else
+PREFIXINSTALLDIR=/pp
+endif
+endif
+export PREFIXINSTALLDIR
+
+# Where to place the resulting zip files
+ifndef DESTZIPDIR
+DESTZIPDIR:=$(BASEDIR)
+endif
+export DESTZIPDIR
+
+#####################################################################
+# Install Directories
+#####################################################################
+
+# set the base directory where to install everything
+ifndef BASEINSTALLDIR
+ifdef inlinux
+BASEINSTALLDIR=$(PREFIXINSTALLDIR)/lib/fpc/$(FPC_VERSION)
+else
+BASEINSTALLDIR=$(PREFIXINSTALLDIR)
+endif
+endif
+
+# set the directory where to install the binaries
+ifndef BININSTALLDIR
+ifdef inlinux
+BININSTALLDIR=$(PREFIXINSTALLDIR)/bin
+else
+BININSTALLDIR=$(BASEINSTALLDIR)/bin/$(OS_TARGET)
+endif
+endif
+
+# set the directory where to install the units.
+ifndef UNITINSTALLDIR
+UNITINSTALLDIR=$(BASEINSTALLDIR)/units/$(OS_TARGET)
+ifdef UNITSUBDIR
+UNITINSTALLDIR:=$(UNITINSTALLDIR)/$(UNITSUBDIR)
+endif
+endif
+
+# Where to install shared libraries
+ifndef LIBINSTALLDIR
+ifdef inlinux
+LIBINSTALLDIR=$(PREFIXINSTALLDIR)/lib
+else
+LIBINSTALLDIR=$(UNITINSTALLDIR)
+endif
+endif
+
+# Where the source files will be stored
+ifndef SOURCEINSTALLDIR
+ifdef inlinux
+SOURCEINSTALLDIR=$(PREFIXINSTALLDIR)/src/fpc-$(FPC_VERSION)
+else
+SOURCEINSTALLDIR=$(BASEINSTALLDIR)/source
+endif
+ifdef SOURCESUBDIR
+SOURCEINSTALLDIR:=$(SOURCEINSTALLDIR)/$(SOURCESUBDIR)
+endif
+endif
+
+# Where the doc files will be stored
+ifndef DOCINSTALLDIR
+ifdef inlinux
+DOCINSTALLDIR=$(PREFIXINSTALLDIR)/doc/fpc-$(FPC_VERSION)
+else
+DOCINSTALLDIR=$(BASEINSTALLDIR)/doc
+endif
+endif
+
+# Where the some extra (data)files will be stored
+ifndef DATAINSTALLDIR
+DATAINSTALLDIR=$(BASEINSTALLDIR)
+endif
+
+#####################################################################
+# Redirection
+#####################################################################
+
+ifndef REDIRFILE
+REDIRFILE=log
+endif
+
+ifdef REDIR
+ifndef inlinux
+override FPC=redir -eo $(FPC)
+endif
+# set the verbosity to max
+override FPCOPT+=-va
+override REDIR:= >> $(REDIRFILE)
+endif
+
+
+#####################################################################
+# Compiler Command Line
+#####################################################################
+
+# Load commandline OPTDEF and add FPC_CPU define
+override FPCOPTDEF:=-d$(CPU_TARGET)
+
+# Load commandline OPT and add target and unit dir to be sure
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+
+ifdef NEEDUNITDIR
+override FPCOPT+=$(addprefix -Fu,$(NEEDUNITDIR))
+endif
+
+ifdef UNITSDIR
+override FPCOPT+=-Fu$(UNITSDIR)
+endif
+
+# Smartlinking
+ifdef LINKSMART
+override FPCOPT+=-CX
+endif
+
+# Smartlinking
+ifdef CREATESMART
+override FPCOPT+=-XX
+endif
+
+# Debug
+ifdef DEBUG
+override FPCOPT+=-g -dDEBUG
+endif
+
+# Release mode (strip, optimize and don't load ppc386.cfg)
+# 0.99.12b has a bug in the optimizer so don't use it by default
+ifdef RELEASE
+ifeq ($(FPC_VERSION),0.99.12)
+override FPCOPT+=-Xs -OGp3 -n
+else
+override FPCOPT+=-Xs -OG2p3 -n
+endif
+endif
+
+# Strip
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+
+# Optimizer
+ifdef OPTIMIZE
+override FPCOPT+=-OG2p3
+endif
+
+# Verbose settings (warning,note,info)
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+
+# Add commandline options
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+ifdef UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(UNITDIR))
+endif
+ifdef LIBDIR
+override FPCOPT+=$(addprefix -Fl,$(LIBDIR))
+endif
+ifdef OBJDIR
+override FPCOPT+=$(addprefix -Fo,$(OBJDIR))
+endif
+ifdef INCDIR
+override FPCOPT+=$(addprefix -Fi,$(INCDIR))
+endif
+
+# Add defines from FPCOPTDEF to FPCOPT
+ifdef FPCOPTDEF
+override FPCOPT+=$(FPCOPTDEF)
+endif
+
+# Error file ?
+ifdef ERRORFILE
+override FPCOPT+=-Fr$(ERRORFILE)
+endif
+
+# Was a config file specified ?
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+
+# For win32 the options are passed using the environment FPCEXTCMD
+ifeq ($(OS_SOURCE),win32)
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+
+# Compiler commandline
+override COMPILER:=$(FPC) $(FPCOPT)
+
+# also call ppas if with command option -s
+ifeq (,$(findstring -s ,$(COMPILER)))
+EXECPPAS=
+else
+EXECPPAS:=@$(PPAS)
+endif
+
+#####################################################################
+# Standard rules
+#####################################################################
+
+all: fpc_all
+
+debug: fpc_debug
+
+smart: fpc_smart
+
+shared: fpc_shared
+
+showinstall: fpc_showinstall
+
+install: fpc_install
+
+sourceinstall: fpc_sourceinstall
+
+zipinstall: fpc_zipinstall
+
+zipsourceinstall: fpc_zipsourceinstall
+
+clean: fpc_clean
+
+distclean: fpc_distclean
+
+cleanall: fpc_cleanall
+
+info: fpc_info
+
+.PHONY:  all debug smart shared showinstall install sourceinstall zipinstall zipsourceinstall clean distclean cleanall info
+
+#####################################################################
+# Units
+#####################################################################
+
+.PHONY: fpc_units
+
+override ALLTARGET+=fpc_units
+
+override UNITPPUFILES=$(addsuffix $(PPUEXT),$(UNITOBJECTS))
+override INSTALLPPUFILES+=$(UNITPPUFILES)
+override CLEANPPUFILES+=$(UNITPPUFILES)
+
+fpc_units: $(UNITPPUFILES)
+
+#####################################################################
+# General compile rules
+#####################################################################
+
+.PHONY: fpc_packages fpc_all fpc_debug
+
+$(FPCMADE): $(ALLTARGET)
+	@$(ECHO) Compiled > $(FPCMADE)
+
+fpc_packages: $(COMPILEPACKAGES)
+
+fpc_all: fpc_packages $(FPCMADE)
+
+fpc_debug:
+	$(MAKE) all DEBUG=1
+
+# General compile rules, available for both possible PASEXT
+
+.SUFFIXES: $(EXEEXT) $(PPUEXT) $(OEXT) .pas .pp
+
+%$(PPUEXT): %.pp
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+%$(PPUEXT): %.pas
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+%$(EXEEXT): %.pp
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+%$(EXEEXT): %.pas
+	$(COMPILER) $< $(REDIR)
+	$(EXECPPAS)
+
+#####################################################################
+# Library
+#####################################################################
+
+.PHONY: fpc_smart fpc_shared
+
+# Default sharedlib units are all unit objects
+ifndef SHAREDLIBUNITOBJECTS
+SHAREDLIBUNITOBJECTS:=$(UNITOBJECTS)
+endif
+
+fpc_smart:
+	$(MAKE) all LINKSMART=1 CREATESMART=1
+
+fpc_shared: all
+ifdef inlinux
+ifndef LIBNAME
+	@$(ECHO) "LIBNAME not set"
+else
+	$(PPUMOVE) $(SHAREDLIBUNITOBJECTS) -o$(LIBNAME)
+endif
+else
+	@$(ECHO) "Shared Libraries not supported"
+endif
+
+#####################################################################
+# Install rules
+#####################################################################
+
+.PHONY: fpc_showinstall fpc_install
+
+ifdef EXTRAINSTALLUNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(EXTRAINSTALLUNITS))
+endif
+
+ifdef INSTALLPPUFILES
+ifdef PPUFILES
+ifdef inlinux
+INSTALLPPULINKFILES:=$(shell $(PPUFILES) -S -O $(INSTALLPPUFILES))
+INSTALLPPULIBFILES:=$(shell $(PPUFILES) -L $(INSTALLPPUFILES))
+else
+INSTALLPPULINKFILES:=$(shell $(PPUFILES) $(INSTALLPPUFILES))
+endif
+else
+INSTALLPPULINKFILES:=$(wildcard $(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)))
+endif
+endif
+
+fpc_showinstall: $(SHOWINSTALLTARGET)
+ifdef INSTALLEXEFILES
+	@$(ECHO) -e $(addprefix "\n"$(BININSTALLDIR)/,$(INSTALLEXEFILES))
+endif
+ifdef INSTALLPPUFILES
+	@$(ECHO) -e $(addprefix "\n"$(UNITINSTALLDIR)/,$(INSTALLPPUFILES))
+ifneq ($(INSTALLPPULINKFILES),)
+	@$(ECHO) -e $(addprefix "\n"$(UNITINSTALLDIR)/,$(INSTALLPPULINKFILES))
+endif
+ifneq ($(INSTALLPPULIBFILES),)
+	@$(ECHO) -e $(addprefix "\n"$(LIBINSTALLDIR)/,$(INSTALLPPULIBFILES))
+endif
+endif
+ifdef EXTRAINSTALLFILES
+	@$(ECHO) -e $(addprefix "\n"$(DATAINSTALLDIR)/,$(EXTRAINSTALLFILES))
+endif
+
+fpc_install: $(INSTALLTARGET)
+# Create UnitInstallFiles
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(BININSTALLDIR)
+# Compress the exes if upx is defined
+ifdef UPXPROG
+	-$(UPXPROG) $(INSTALLEXEFILES)
+endif
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(BININSTALLDIR)
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(UNITINSTALLDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(UNITINSTALLDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(UNITINSTALLDIR)
+endif
+ifneq ($(INSTALLPPULIBFILES),)
+	$(MKDIR) $(LIBINSTALLDIR)
+	$(INSTALL) $(INSTALLPPULIBFILES) $(LIBINSTALLDIR)
+endif
+endif
+ifdef EXTRAINSTALLFILES
+	$(MKDIR) $(DATAINSTALLDIR)
+	$(INSTALL) $(EXTRAINSTALLFILES) $(DATAINSTALLDIR)
+endif
+
+#####################################################################
+# SourceInstall rules
+#####################################################################
+
+.PHONY: fpc_sourceinstall
+
+ifndef SOURCETOPDIR
+SOURCETOPDIR=$(BASEDIR)
+endif
+
+fpc_sourceinstall: clean
+	$(MKDIR) $(SOURCEINSTALLDIR)
+	$(COPYTREE) $(SOURCETOPDIR) $(SOURCEINSTALLDIR)
+
+#####################################################################
+# Zip
+#####################################################################
+
+.PHONY: fpc_zipinstall
+
+# Create suffix to add
+ifndef PACKAGESUFFIX
+PACKAGESUFFIX=$(OS_TARGET)
+ifeq ($(OS_TARGET),go32v2)
+PACKAGESUFFIX=go32
+endif
+ifeq ($(OS_TARGET),win32)
+PACKAGESUFFIX=w32
+endif
+endif
+
+# Temporary path to pack a file
+ifndef PACKDIR
+ifndef inlinux
+PACKDIR=$(BASEDIR)/pack_tmp
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+
+# Maybe create default zipname from packagename
+ifndef ZIPNAME
+ifdef PACKAGENAME
+ZIPNAME=$(PACKAGEPREFIX)$(PACKAGENAME)$(PACKAGESUFFIX)
+endif
+endif
+
+# Use tar by default under linux
+ifndef USEZIP
+ifdef inlinux
+USETAR=1
+endif
+endif
+
+fpc_zipinstall:
+ifndef ZIPNAME
+	@$(ECHO) "Please specify ZIPNAME!"
+	@exit 1
+else
+	$(MAKE) $(ZIPTARGET) PREFIXINSTALLDIR=$(PACKDIR)
+ifdef USETAR
+	$(DEL) $(DESTZIPDIR)/$(ZIPNAME)$(TAREXT)
+	cd $(PACKDIR) ; $(TARPROG) c$(TAROPT) --file $(DESTZIPDIR)/$(ZIPNAME)$(TAREXT) * ; cd $(BASEDIR)
+else
+	$(DEL) $(DESTZIPDIR)/$(ZIPNAME)$(ZIPEXT)
+	cd $(PACKDIR) ; $(ZIPPROG) -Dr $(ZIPOPT) $(DESTZIPDIR)/$(ZIPNAME)$(ZIPEXT) * ; cd $(BASEDIR)
+endif
+	$(DELTREE) $(PACKDIR)
+endif
+
+.PHONY:  fpc_zipsourceinstall
+
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall PACKAGESUFFIX=src
+
+#####################################################################
+# Clean rules
+#####################################################################
+
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+
+ifdef EXTRACLEANUNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(EXTRACLEANUNITS))
+endif
+
+ifdef CLEANPPUFILES
+ifdef PPUFILES
+CLEANPPULINKFILES:=$(shell $(PPUFILES) $(CLEANPPUFILES))
+else
+CLEANPPULINKFILES:=$(wildcard $(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)))
+endif
+endif
+
+fpc_clean: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(CLEANRSTFILES)
+endif
+ifdef EXTRACLEANFILES
+	-$(DEL) $(EXTRACLEANFILES)
+endif
+	-$(DEL) $(FPCMADE) $(PPAS) link.res $(FPCEXTFILE) $(REDIRFILE)
+
+fpc_distclean: fpc_clean
+
+fpc_cleanall: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) $(FPCMADE) $(PPAS) link.res $(FPCEXTFILE) $(REDIRFILE)
+
+#####################################################################
+# Info rules
+#####################################################################
+
+.PHONY: fpc_info fpc_cfginfo fpc_objectinfo fpc_toolsinfo fpc_installinfo \
+	fpc_dirinfo
+
+fpc_info: $(INFOTARGET)
+
+fpc_infocfg:
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC....... $(FPC)
+	@$(ECHO)  Version... $(FPC_VERSION)
+	@$(ECHO)  CPU....... $(CPU_TARGET)
+	@$(ECHO)  Source.... $(OS_SOURCE)
+	@$(ECHO)  Target.... $(OS_TARGET)
+	@$(ECHO)
+
+fpc_infoobjects:
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  LoaderObjects..... $(LOADEROBJECTS)
+	@$(ECHO)  UnitObjects....... $(UNITOBJECTS)
+	@$(ECHO)  ExeObjects........ $(EXEOBJECTS)
+	@$(ECHO)
+	@$(ECHO)  ExtraCleanUnits... $(EXTRACLEANUNITS)
+	@$(ECHO)  ExtraCleanFiles... $(EXTRACLEANFILES)
+	@$(ECHO)
+	@$(ECHO)  ExtraInstallUnits. $(EXTRAINSTALLUNITS)
+	@$(ECHO)  ExtraInstallFiles. $(EXTRAINSTALLFILES)
+	@$(ECHO)
+
+fpc_infoinstall:
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+ifdef DATE
+	@$(ECHO)  DateStr.............. $(DATESTR)
+endif
+ifdef PACKAGEPREFIX
+	@$(ECHO)  PackagePrefix........ $(PACKAGEPREFIX)
+endif
+ifdef PACKAGENAME
+	@$(ECHO)  PackageName.......... $(PACKAGENAME)
+endif
+	@$(ECHO)  PackageSuffix........ $(PACKAGESUFFIX)
+	@$(ECHO)
+	@$(ECHO)  BaseInstallDir....... $(BASEINSTALLDIR)
+	@$(ECHO)  BinInstallDir........ $(BININSTALLDIR)
+	@$(ECHO)  LibInstallDir........ $(LIBINSTALLDIR)
+	@$(ECHO)  UnitInstallDir....... $(UNITINSTALLDIR)
+	@$(ECHO)  SourceInstallDir..... $(SOURCEINSTALLDIR)
+	@$(ECHO)  DocInstallDir........ $(DOCINSTALLDIR)
+	@$(ECHO)  DataInstallDir....... $(DATAINSTALLDIR)
+	@$(ECHO)
+	@$(ECHO)  DestZipDir........... $(DESTZIPDIR)
+	@$(ECHO)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)
+
+#####################################################################
+# Local Makefile
+#####################################################################
+
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+
+#####################################################################
+# Users rules
+#####################################################################
+
+
+unzip$(PPUEXT): unzip$(PASEXT) ziptypes$(PPUEXT)
+
+unzipdll$(PPUEXT):  unzipdll$(PASEXT) ziptypes$(PPUEXT)

+ 16 - 0
packages/zip/Makefile.fpc

@@ -0,0 +1,16 @@
+#
+#   Makefile.fpc for ZLib (LibC version)
+#
+
+[targets]
+units=ziptypes unzip
+units_os2=unzipdll
+
+[dirs]
+fpcdir=../..
+
+[rules]
+
+unzip$(PPUEXT): unzip$(PASEXT) ziptypes$(PPUEXT)
+
+unzipdll$(PPUEXT):  unzipdll$(PASEXT) ziptypes$(PPUEXT)

+ 3357 - 0
packages/zip/unzip.pas

@@ -0,0 +1,3357 @@
+{
+  $Id$
+}
+UNIT Unzip;
+{
+Unzips deflated, imploded, shrunk and stored files
+  ** COMPATIBLE WITH
+        * Turbo Pascal v7.x     (DOS)
+        * Borland Pascal v7.x   (Dos, DPMI, and Windows)
+        * Delphi v1.x
+        * Delphi v2.x
+        * Delphi v3.x
+        * Virtual Pascal v2.0   (OS/2, Win32)
+        * Free Pascal Compiler  (DOS, OS/2, Win32, Linux)
+}
+
+{
+  Original version (1.x): Christian Ghisler
+   C code by info-zip group, translated to pascal by Christian Ghisler
+   based on unz51g.zip;
+   Special thanks go to Mark Adler,who wrote the main inflate and
+   explode code, and did NOT copyright it!!!
+
+ v2.00: March 1998: Dr Abimbola Olowofoyeku (The African Chief)
+        Homepage: http://ourworld.compuserve.com/homepages/African_Chief
+   * modified to compile for Delphi v2.x and Delphi v3.x
+
+ v2.01: April 1998: Dr Abimbola Olowofoyeku (The African Chief)
+   * source files merged into a single source (this) file
+   * several high level functions added - i.e.,
+              FileUnzip()
+              FileUnzipEx()
+              ViewZip()
+              UnzipSize()
+              SetUnzipReportProc()
+              SetUnzipQuestionProc()
+              ChfUnzip_Init()
+   * callbacks added
+   * modified to support Virtual Pascal v2.0 (Win32)
+   * Delphi component added (chfunzip.pas)
+ v2.01a: December 1998: Tomas Hajny, [email protected]
+   * extended to support other 32-bit compilers/platforms (OS/2, GO32, ...);
+     search for (* TH ... *)
+ v2.01b: December 1998: Peter Vreman
+   * modifications needed for Linux
+}
+
+INTERFACE
+
+{$IFDEF FPC}
+ {$DEFINE BIT32}
+{$ENDIF}
+
+{$IFDEF OS2}
+ {$DEFINE BIT32}
+{$ENDIF}
+
+{$IFDEF WIN32}
+ {$DEFINE BIT32}
+{$ENDIF}
+
+{$IFNDEF FPC}
+  {$F+}
+{$ENDIF}
+
+{$R-}         {No range checking}
+
+USES
+{$ifdef windows}
+wintypes,
+winprocs,
+{$ifdef Delphi}
+Messages,
+Sysutils,
+{$else Delphi}
+strings,
+windos,
+{$endif Delphi}
+{$else Windows}
+strings,
+crt,
+dos,
+{$endif Windows}
+ziptypes;
+
+{**********************************************************************}
+{**********************************************************************}
+{****** HIGH LEVEL FUNCTIONS: BY THE AFRICAN CHIEF ********************}
+{**********************************************************************}
+{**********************************************************************}
+FUNCTION FileUnzip
+( SourceZipFile, TargetDirectory, FileSpecs : pChar;
+ Report : UnzipReportProc;Question : UnzipQuestionProc ) : integer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+
+{
+high level unzip
+usage:
+SourceZipFile: source zip file;
+TargetDirectory: target directory
+FileSpecs: "*.*", etc.
+Report: Report callback or Nil;
+Question: Question callback (for confirmation of whether to replace existing
+          files) or Nil;
+
+* REFER to ZIPTYPES.PAS for information on callback functions
+
+e.g.,
+   Count := FileUnzip('test.zip', 'c:\temp', '*.*', MyReportProc, Nil);
+
+}
+
+FUNCTION FileUnzipEx ( SourceZipFile, TargetDirectory, FileSpecs : pChar ) : integer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+high level unzip with no callback parameters;
+passes ZipReport & ZipQuestion internally, so you
+can use SetZipReportProc and SetZipQuestionProc before calling this;
+
+e.g.,
+   Count := FileUnzipEx('test.zip', 'c:\temp', '*.*');
+}
+
+FUNCTION ViewZip ( SourceZipFile, FileSpecs : pChar; Report : UnzipReportProc ) : integer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+view contents of zip file
+usage:
+SourceZipFile: source zip file;
+FileSpecs: "*.*", etc.
+Report: callback procedure to process the reported contents of ZIP file;
+
+* REFER to ZIPTYPES.PAS for information on callback functions
+
+e.g.,
+  ViewZip('test.zip', '*.*', MyReportProc);
+}
+
+FUNCTION  SetUnZipReportProc ( aProc : UnzipReportProc ) : Pointer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+sets the internal unzip report procedure to aproc
+Returns: pointer to the original report procedure
+(return value should normally be ignored)
+
+e.g.,
+   SetUnZipReportProc(MyReportProc);
+}
+
+FUNCTION  SetUnZipQuestionProc ( aProc : UnzipQuestionProc ) : Pointer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+sets the internal unzip question procedure to aproc
+Returns: pointer to the original "question" procedure
+(return value should normally be ignored)
+
+e.g.,
+SetUnZipQuestionProc(QueryFileExistProc);
+}
+
+FUNCTION UnzipSize ( SourceZipFile : pChar;VAR Compressed : Longint ) : longint;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{ uncompressed and compressed zip size
+ usage:
+ SourceZipFile  = the zip file
+ Compressed     = the compressed size of the files in the archive
+ Returns:         the uncompressed size of the ZIP archive
+
+e.g.,
+  Var
+  Size,CSize:longint;
+  begin
+     Size := UnzipSize('test.zip', CSize);
+  end;
+}
+
+PROCEDURE ChfUnzip_Init;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+initialise or reinitialise the shared data: !!! use with care !!!
+}
+
+FUNCTION SetNoRecurseDirs ( DontRecurse : Boolean ) : Boolean;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+determine whether the UNZIP function should recreate
+the subdirectory structure;
+ DontRecurse = TRUE :  don't recurse
+ DontRecurse = FALSE : recurse (default)
+}
+
+{**********************************************************************}
+{**********************************************************************}
+{************ LOW LEVEL FUNCTIONS: BY CHRISTIAN GHISLER ***************}
+{**********************************************************************}
+{**********************************************************************}
+FUNCTION GetSupportedMethods : longint;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{Checks which pack methods are supported by the dll}
+{bit 8=1 -> Format 8 supported, etc.}
+
+FUNCTION UnzipFile ( in_name : pchar;out_name : pchar;offset : longint;hFileAction : word;cm_index : integer ) : integer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{usage:
+ in_name:      name of zip file with full path
+ out_name:     desired name for out file
+ offset:       header position of desired file in zipfile
+ hFileAction:  handle to dialog box showing advance of decompression (optional)
+ cm_index:     notification code sent in a wm_command message to the dialog
+               to update percent-bar
+ Return value: one of the above unzip_xxx codes
+
+ Example for handling the cm_index message in a progress dialog:
+
+ unzipfile(......,cm_showpercent);
+
+ ...
+
+ procedure TFileActionDialog.wmcommand(var msg:tmessage);
+ var ppercent:^word;
+ begin
+   TDialog.WMCommand(msg);
+   if msg.wparam=cm_showpercent then begin
+     ppercent:=pointer(lparam);
+     if ppercent<>nil then begin
+       if (ppercent^>=0) and (ppercent^<=100) then
+         SetProgressBar(ppercent^);
+       if UserPressedAbort then
+         ppercent^:=$ffff
+       else
+         ppercent^:=0;
+       end;
+     end;
+   end;
+ end;
+}
+
+FUNCTION  GetFirstInZip ( zipfilename : pchar;VAR zprec : tZipRec ) : integer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+ Get first entry from ZIP file
+ e.g.,
+   rc:=GetFirstInZip('test.zip', myZipRec);
+}
+
+FUNCTION  GetNextInZip ( VAR Zprec : tZiprec ) : integer;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+  Get next entry from ZIP file
+
+ e.g.,
+   rc:=GetNextInZip(myZipRec);
+}
+
+FUNCTION  IsZip ( filename : pchar ) : boolean;
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+  VERY simple test for zip file
+
+  e.g.,
+   ItsaZipFile := IsZip('test.zip');
+}
+
+PROCEDURE CloseZipFile ( VAR Zprec : tZiprec );  {Only free buffer, file only open in Getfirstinzip}
+{$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
+{$ifdef DPMI} EXPORT; {$endif DPMI}
+{
+  free ZIP buffers
+
+  e.g.,
+  CloseZipFile(myZipRec);
+}
+
+IMPLEMENTATION
+
+VAR
+ZipReport : UnzipReportProc;        {Global Status Report Callback}
+ZipQuestion : UnzipQuestionProc;    {Global "Question" Callback}
+ZipRec : TReportRec;                {Global ZIP record for callbacks}
+NoRecurseDirs : Boolean;              {Global Recurse variable}
+
+{*************************************************************************}
+{$ifdef Delphi}
+PROCEDURE SetCurDir ( p : pChar );
+BEGIN
+   Chdir ( strpas ( p ) );
+END;
+
+FUNCTION DosError : integer;  {Delphi DosError kludge}
+BEGIN
+   Result := Ioresult;
+END;
+
+FUNCTION SetFTime ( VAR f : File; CONST l : longint ) : integer;
+BEGIN
+   {$ifdef Win32}Result := {$endif}FileSetDate ( TFileRec ( f ) .Handle, l );
+END;
+
+PROCEDURE CreateDir ( p : pchar );
+BEGIN
+  mkdir ( strpas ( p ) );
+END;
+
+{/////////////////////////////////////////////////////////}
+{$endif Delphi}
+
+{.$I z_global.pas}  {global constants, types and variables}
+{Include file for unzip.pas: global constants, types and variables}
+
+{C code by info-zip group, translated to pascal by Christian Ghisler}
+{based on unz51g.zip}
+
+CONST   {Error codes returned by huft_build}
+  huft_complete  = 0;   {Complete tree}
+  huft_incomplete = 1;   {Incomplete tree <- sufficient in some cases!}
+  huft_error     = 2;   {bad tree constructed}
+  huft_outofmem  = 3;   {not enough memory}
+(* TH - use of the new BIT32 conditional (was WIN32 only previously) *)
+  MaxMax = {$ifdef BIT32}256 * 1024    {BIT32 =  256kb buffer}
+           {$else}Maxint -1{$endif}; {16-bit = 32kb buffer}
+
+CONST wsize = $8000;          {Size of sliding dictionary}
+      INBUFSIZ = 1024 * 4;      {Size of input buffer}
+
+CONST lbits : integer = 9;
+      dbits : integer = 6;
+
+CONST b_max = 16;
+      n_max = 288;
+      BMAX = 16;
+
+TYPE push = ^ush;
+     ush = word;
+     pbyte = ^byte;
+     pushlist = ^ushlist;
+     ushlist = ARRAY [ 0..maxmax ] of ush;  {only pseudo-size!!}
+     pword = ^word;
+     pwordarr = ^twordarr;
+     twordarr = ARRAY [ 0..maxmax ] of word;
+     iobuf = ARRAY [ 0..inbufsiz -1 ] of byte;
+
+TYPE pphuft = ^phuft;
+     phuft = ^huft;
+     phuftlist = ^huftlist;
+     huft = PACKED RECORD
+       e,             {# of extra bits}
+       b : byte;        {# of bits in code}
+       v_n : ush;
+       v_t : phuftlist; {Linked List}
+     END;
+     huftlist = ARRAY [ 0..8190 ] of huft;
+
+TYPE li = PACKED RECORD
+       lo, hi : word;
+     END;
+
+{pkzip header in front of every file in archive}
+TYPE
+  plocalheader = ^tlocalheader;
+  tlocalheader = PACKED RECORD
+    signature : ARRAY [ 0..3 ] of char;  {'PK'#1#2}
+    extract_ver,
+    bit_flag,
+    zip_type : word;
+    file_timedate : longint;
+    crc_32,
+    compress_size,
+    uncompress_size : longint;
+    filename_len,
+    extra_field_len : word;
+  END;
+
+VAR slide : pchar;            {Sliding dictionary for unzipping}
+    inbuf : iobuf;            {input buffer}
+    inpos, readpos : integer;  {position in input buffer, position read from file}
+{$ifdef windows}
+    dlghandle : word;         {optional: handle of a cancel and "%-done"-dialog}
+{$endif}
+    dlgnotify : integer;      {notification code to tell dialog how far the decompression is}
+
+VAR w : longint;                 {Current Position in slide}
+    b : longint;              {Bit Buffer}
+    k : byte;                 {Bits in bit buffer}
+    infile,                 {handle to zipfile}
+    outfile : file;           {handle to extracted file}
+    compsize,               {comressed size of file}
+    reachedsize,            {number of bytes read from zipfile}
+    uncompsize : longint;     {uncompressed size of file}
+    crc32val : longint;       {crc calculated from data}
+    hufttype : word;          {coding type=bit_flag from header}
+    totalabort,             {User pressed abort button, set in showpercent!}
+    zipeof : boolean;         {read over end of zip section for this file}
+    inuse : boolean;          {is unit already in use -> don't call it again!!!}
+{$ifdef windows}
+    oldpercent : integer;     {last percent value shown}
+    lastusedtime : longint;   {Time of last usage in timer ticks for timeout!}
+{$endif}
+
+(***************************************************************************)
+{.$I z_tables.pas}  {Tables for bit masking, huffman codes and CRC checking}
+
+{include file for unzip.pas: Tables for bit masking, huffman codes and CRC checking}
+
+{C code by info-zip group, translated to Pascal by Christian Ghisler}
+{based on unz51g.zip}
+
+{b and mask_bits[i] gets lower i bits out of i}
+CONST mask_bits : ARRAY [ 0..16 ] of word =
+   ( $0000,
+    $0001, $0003, $0007, $000f, $001f, $003f, $007f, $00ff,
+    $01ff, $03ff, $07ff, $0fff, $1fff, $3fff, $7fff, $ffff );
+
+{ Tables for deflate from PKZIP's appnote.txt. }
+
+CONST border : ARRAY [ 0..18 ] of byte =   { Order of the bit length code lengths }
+        ( 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 );
+CONST cplens : ARRAY [ 0..30 ] of word =    { Copy lengths for literal codes 257..285 }
+        ( 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 );
+        { note: see note #13 above about the 258 in this list.}
+CONST cplext : ARRAY [ 0..30 ] of word =    { Extra bits for literal codes 257..285 }
+        ( 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 ); { 99==invalid }
+CONST cpdist : ARRAY [ 0..29 ] of word =     { Copy offsets for distance codes 0..29 }
+        ( 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577 );
+CONST cpdext : ARRAY [ 0..29 ] of word =    { Extra bits for distance codes }
+        ( 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13 );
+
+{ Tables for explode }
+
+CONST cplen2 : ARRAY [ 0..63 ] of word = ( 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+        18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65 );
+CONST cplen3 : ARRAY [ 0..63 ] of word = ( 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+        19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+        36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+        53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66 );
+CONST extra : ARRAY [ 0..63 ] of word = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        8 );
+CONST cpdist4 : ARRAY [ 0..63 ] of word = ( 1, 65, 129, 193, 257, 321, 385, 449, 513, 577, 641, 705,
+        769, 833, 897, 961, 1025, 1089, 1153, 1217, 1281, 1345, 1409, 1473,
+        1537, 1601, 1665, 1729, 1793, 1857, 1921, 1985, 2049, 2113, 2177,
+        2241, 2305, 2369, 2433, 2497, 2561, 2625, 2689, 2753, 2817, 2881,
+        2945, 3009, 3073, 3137, 3201, 3265, 3329, 3393, 3457, 3521, 3585,
+        3649, 3713, 3777, 3841, 3905, 3969, 4033 );
+CONST cpdist8 : ARRAY [ 0..63 ] of word = ( 1, 129, 257, 385, 513, 641, 769, 897, 1025, 1153, 1281,
+        1409, 1537, 1665, 1793, 1921, 2049, 2177, 2305, 2433, 2561, 2689,
+        2817, 2945, 3073, 3201, 3329, 3457, 3585, 3713, 3841, 3969, 4097,
+        4225, 4353, 4481, 4609, 4737, 4865, 4993, 5121, 5249, 5377, 5505,
+        5633, 5761, 5889, 6017, 6145, 6273, 6401, 6529, 6657, 6785, 6913,
+        7041, 7169, 7297, 7425, 7553, 7681, 7809, 7937, 8065 );
+
+{************************************ CRC-Calculation ************************************}
+
+CONST crc_32_tab : ARRAY [ 0..255 ] of longint =
+(
+   $00000000, $77073096, $ee0e612c, $990951ba, $076dc419,
+   $706af48f, $e963a535, $9e6495a3, $0edb8832, $79dcb8a4,
+   $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07,
+   $90bf1d91, $1db71064, $6ab020f2, $f3b97148, $84be41de,
+   $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7, $136c9856,
+   $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9,
+   $fa0f3d63, $8d080df5, $3b6e20c8, $4c69105e, $d56041e4,
+   $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
+   $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3,
+   $45df5c75, $dcd60dcf, $abd13d59, $26d930ac, $51de003a,
+   $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599,
+   $b8bda50f, $2802b89e, $5f058808, $c60cd9b2, $b10be924,
+   $2f6f7c87, $58684c11, $c1611dab, $b6662d3d, $76dc4190,
+   $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f,
+   $9fbfe4a5, $e8b8d433, $7807c9a2, $0f00f934, $9609a88e,
+   $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
+   $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed,
+   $1b01a57b, $8208f4c1, $f50fc457, $65b0d9c6, $12b7e950,
+   $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3,
+   $fbd44c65, $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2,
+   $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb, $4369e96a,
+   $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5,
+   $aa0a4c5f, $dd0d7cc9, $5005713c, $270241aa, $be0b1010,
+   $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
+   $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17,
+   $2eb40d81, $b7bd5c3b, $c0ba6cad, $edb88320, $9abfb3b6,
+   $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615,
+   $73dc1683, $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8,
+   $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1, $f00f9344,
+   $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb,
+   $196c3671, $6e6b06e7, $fed41b76, $89d32be0, $10da7a5a,
+   $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
+   $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1,
+   $a6bc5767, $3fb506dd, $48b2364b, $d80d2bda, $af0a1b4c,
+   $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef,
+   $4669be79, $cb61b38c, $bc66831a, $256fd2a0, $5268e236,
+   $cc0c7795, $bb0b4703, $220216b9, $5505262f, $c5ba3bbe,
+   $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31,
+   $2cd99e8b, $5bdeae1d, $9b64c2b0, $ec63f226, $756aa39c,
+   $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
+   $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b,
+   $e5d5be0d, $7cdcefb7, $0bdbdf21, $86d3d2d4, $f1d4e242,
+   $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1,
+   $18b74777, $88085ae6, $ff0f6a70, $66063bca, $11010b5c,
+   $8f659eff, $f862ae69, $616bffd3, $166ccf45, $a00ae278,
+   $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7,
+   $4969474d, $3e6e77db, $aed16a4a, $d9d65adc, $40df0b66,
+   $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
+   $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605,
+   $cdd70693, $54de5729, $23d967bf, $b3667a2e, $c4614ab8,
+   $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b,
+   $2d02ef8d ); { end crc_32_tab[] }
+(***************************************************************************)
+{.$I z_generl.pas}  {General functions used by both inflate and explode}
+{include for unzip.pas: General functions used by both inflate and explode}
+
+{C code by info-zip group, translated to Pascal by Christian Ghisler}
+{based on unz51g.zip}
+
+{*********************************** CRC Checking ********************************}
+
+PROCEDURE UpdateCRC ( VAR s : iobuf;len : word );
+VAR i : word;
+BEGIN
+{$ifndef assembler}
+ FOR i := 0 TO Pred ( len ) DO BEGIN
+    { update running CRC calculation with contents of a buffer }
+    crc32val := crc_32_tab [  ( byte ( crc32val ) XOR s [ i ] ) AND $ff ] XOR ( crc32val SHR 8 );
+  END;
+{$else}
+  ASM
+    les di, s
+    mov ax, li.lo ( crc32val )
+    mov dx, li.hi ( crc32val )
+    mov si, offset crc_32_tab      {Segment remains DS!!!}
+    mov cx, len
+    OR cx, cx
+    jz @finished
+@again :
+    mov bl, al           {byte(crcval)}
+    mov al, ah           {shift DX:AX by 8 bits to the right}
+    mov ah, dl
+    mov dl, dh
+    XOR dh, dh
+
+    XOR bh, bh
+    XOR bl, es : [ di ]  {xor s^}
+    inc di
+    SHL bx, 1            {Offset: Index*4}
+    SHL bx, 1
+    XOR ax, [ si + bx ]
+    XOR dx, [ si + bx + 2 ]
+    dec cx
+    jnz @again
+@finished :
+    mov li.lo ( crc32val ), ax
+    mov li.hi ( crc32val ), dx
+  END;
+{$endif}
+END;
+
+{************************ keep other programs running ***************************}
+
+PROCEDURE messageloop;
+{$ifdef windows}
+VAR msg : tmsg;
+BEGIN
+  lastusedtime := gettickcount;
+  WHILE PeekMessage ( Msg, 0, 0, 0, PM_Remove ) DO
+    IF ( dlghandle = 0 ) OR NOT IsDialogMessage ( dlghandle, msg ) THEN BEGIN
+      TranslateMessage ( Msg );
+      DispatchMessage ( Msg );
+    END;
+END;
+{$else}
+VAR ch : word;
+BEGIN
+  IF keypressed THEN BEGIN
+    ch := byte ( readkey );
+    IF ch = 0 THEN ch := 256 + byte ( readkey );  {Extended code}
+    IF ch = dlgnotify THEN totalabort := TRUE;
+  END
+END;
+{$endif}
+
+{************************* tell dialog to show % ******************************}
+{$ifdef windows}
+PROCEDURE showpercent; {use this with the low level functions only !!!}
+VAR percent : word;
+BEGIN
+  IF compsize <> 0 THEN BEGIN
+    percent := reachedsize * 100 DIV compsize;
+    IF percent > 100 THEN percent := 100;
+    IF ( percent <> oldpercent ) THEN BEGIN
+      oldpercent := percent;
+      IF dlghandle <> 0 THEN BEGIN     {Use dialog box for aborting}
+        {Sendmessage returns directly -> ppercent contains result}
+        sendmessage ( dlghandle, wm_command, dlgnotify, longint ( @percent ) );
+        totalabort := ( percent = $FFFF );   {Abort pressed!}
+      END ELSE
+        IF dlgnotify <> 0 THEN
+          totalabort := getasynckeystate ( dlgnotify ) < 0;  {break Key pressed!}
+    END;
+  END;
+END;
+{$endif}
+
+{************************** fill inbuf from infile *********************}
+
+PROCEDURE readbuf;
+BEGIN
+  IF reachedsize > compsize + 2 THEN BEGIN {+2: last code is smaller than requested!}
+    readpos := sizeof ( inbuf ); {Simulates reading -> no blocking}
+    zipeof := TRUE
+  END ELSE BEGIN
+    messageloop;      {Other programs, or in DOS: keypressed?}
+    {$ifdef windows}
+    showpercent;      {Before, because it shows the data processed, not read!}
+    {$endif}
+    {$I-}
+    blockread ( infile, inbuf, sizeof ( inbuf ), readpos );
+    {$I+}
+    IF ( ioresult <> 0 ) OR ( readpos = 0 ) THEN BEGIN  {readpos=0: kein Fehler gemeldet!!!}
+      readpos := sizeof ( inbuf ); {Simulates reading -> CRC error}
+      zipeof := TRUE;
+    END;
+    inc ( reachedsize, readpos );
+    dec ( readpos );    {Reason: index of inbuf starts at 0}
+  END;
+  inpos := 0;
+END;
+
+{**** read byte, only used by explode ****}
+
+PROCEDURE READBYTE ( VAR bt : byte );
+BEGIN
+  IF inpos > readpos THEN readbuf;
+  bt := inbuf [ inpos ];
+  inc ( inpos );
+END;
+
+{*********** read at least n bits into the global variable b *************}
+
+PROCEDURE NEEDBITS ( n : byte );
+VAR nb : longint;
+BEGIN
+{$ifndef assembler}
+  WHILE k < n DO BEGIN
+    IF inpos > readpos THEN readbuf;
+    nb := inbuf [ inpos ];
+    inc ( inpos );
+    b := b OR nb SHL k;
+    inc ( k, 8 );
+  END;
+{$else}
+  ASM
+    mov si, offset inbuf
+    mov ch, n
+    mov cl, k
+    mov bx, inpos    {bx=inpos}
+@again :
+    cmp cl, ch
+    JAE @finished   {k>=n -> finished}
+    cmp bx, readpos
+    jg @readbuf
+@fullbuf :
+    mov al, [ si + bx ]  {dx:ax=nb}
+    XOR ah, ah
+    XOR dx, dx
+    cmp cl, 8      {cl>=8 -> shift into DX or directly by 1 byte}
+    JAE @bigger8
+    SHL ax, cl     {Normal shifting!}
+    jmp @continue
+@bigger8 :
+    mov di, cx     {save cx}
+    mov ah, al     {shift by 8}
+    XOR al, al
+    sub cl, 8      {8 bits shifted}
+@rotate :
+    OR cl, cl
+    jz @continue1 {all shifted -> finished}
+    SHL ah, 1      {al ist empty!}
+    rcl dx, 1
+    dec cl
+    jmp @rotate
+@continue1 :
+    mov cx, di
+@continue :
+    OR li.hi ( b ), dx {b=b or nb shl k}
+    OR li.lo ( b ), ax
+    inc bx         {inpos}
+    add cl, 8       {inc k by 8 Bits}
+    jmp @again
+
+@readbuf :
+    push si
+    push cx
+    call readbuf   {readbuf not critical, called only every 2000 bytes}
+    pop cx
+    pop si
+    mov bx, inpos   {New inpos}
+    jmp @fullbuf
+
+@finished :
+    mov k, cl
+    mov inpos, bx
+  END;
+{$endif}
+END;
+
+{***************** dump n bits no longer needed from global variable b *************}
+
+PROCEDURE DUMPBITS ( n : byte );
+BEGIN
+{$ifndef assembler}
+  b := b SHR n;
+  k := k -n;
+{$else}
+  ASM
+    mov cl, n
+    mov ax, li.lo ( b )
+    mov dx, li.hi ( b )
+
+    mov ch, cl
+    OR ch, ch
+    jz @finished
+@rotate :
+    SHR dx, 1           {Lower Bit in Carry}
+    rcr ax, 1
+    dec ch
+    jnz @rotate
+@finished :
+    mov li.lo ( b ), ax
+    mov li.hi ( b ), dx
+    sub k, cl
+  END;
+{$endif}
+END;
+
+{********************* Flush w bytes directly from slide to file ******************}
+FUNCTION flush ( w : word ) : boolean;
+VAR n : nword;          {True wenn OK}
+b : boolean;
+BEGIN
+  {$I-}
+  blockwrite ( outfile, slide [ 0 ], w, n );
+  {$I+}
+  b := ( n = w ) AND ( ioresult = 0 );  {True-> alles ok}
+  UpdateCRC ( iobuf ( pointer ( @slide [ 0 ] ) ^ ), w );
+  {--}
+{$IFDEF FPC}
+  IF ( b = TRUE ) AND Assigned(ZipReport)  {callback report for high level functions}
+{$ELSE}
+  IF ( b = TRUE ) AND ( @ZipReport <> NIL )  {callback report for high level functions}
+{$ENDIF}
+  THEN BEGIN
+      WITH ZipRec DO BEGIN
+           Status := file_unzipping;
+           ZipReport ( n, @ZipRec );  {report the actual bytes written}
+      END;
+  END; {report}
+  flush := b;
+END;
+
+{******************************* Break string into tokens ****************************}
+
+VAR
+  _Token : PChar;
+
+FUNCTION StrTok ( Source : PChar; Token : CHAR ) : PChar;
+  VAR P : PChar;
+BEGIN
+  IF Source <> NIL THEN _Token := Source;
+  IF _Token = NIL THEN BEGIN
+    strTok := NIL;
+    exit
+  END;
+  P := StrScan ( _Token, Token );
+  StrTok := _Token;
+  IF P <> NIL THEN BEGIN
+    P^ := #0;
+    Inc ( P );
+  END;
+  _Token := P;
+END;
+
+(***************************************************************************)
+{.$I z_huft.pas}    {Huffman tree generating and destroying}
+{include for unzip.pas: Huffman tree generating and destroying}
+
+{C code by info-zip group, translated to Pascal by Christian Ghisler}
+{based on unz51g.zip}
+
+{*************** free huffman tables starting with table where t points to ************}
+
+PROCEDURE huft_free ( t : phuftlist );
+
+VAR p, q : phuftlist;
+    z : integer;
+
+BEGIN
+  p := pointer ( t );
+  WHILE p <> NIL DO BEGIN
+    dec ( longint ( p ), sizeof ( huft ) );
+    q := p^ [ 0 ].v_t;
+    z := p^ [ 0 ].v_n;   {Size in Bytes, required by TP ***}
+    freemem ( p, ( z + 1 ) * sizeof ( huft ) );
+    p := q
+  END;
+END;
+
+{*********** build huffman table from code lengths given by array b^ *******************}
+
+FUNCTION huft_build ( b : pword;n : word;s : word;d, e : pushlist;t : pphuft;VAR m : integer ) : integer;
+VAR a : word;                        {counter for codes of length k}
+    c : ARRAY [ 0..b_max + 1 ] of word;   {bit length count table}
+    f : word;                        {i repeats in table every f entries}
+    g,                             {max. code length}
+    h : integer;                     {table level}
+    i,                             {counter, current code}
+    j : word;                        {counter}
+    k : integer;                     {number of bits in current code}
+    p : pword;                       {pointer into c, b and v}
+    q : phuftlist;                   {points to current table}
+    r : huft;                        {table entry for structure assignment}
+    u : ARRAY [ 0..b_max ] of phuftlist;{table stack}
+    v : ARRAY [ 0..n_max ] of word;     {values in order of bit length}
+    w : integer;                     {bits before this table}
+    x : ARRAY [ 0..b_max + 1 ] of word;   {bit offsets, then code stack}
+    l : ARRAY [  -1..b_max + 1 ] of word;  {l[h] bits in table of level h}
+    xp : ^word;                      {pointer into x}
+    y : integer;                     {number of dummy codes added}
+    z : word;                        {number of entries in current table}
+    tryagain : boolean;              {bool for loop}
+    pt : phuft;                      {for test against bad input}
+    el : word;                       {length of eob code=code 256}
+
+BEGIN
+  IF n > 256 THEN el := pword ( longint ( b ) + 256 * sizeof ( word ) ) ^
+           ELSE el := BMAX;
+  {generate counts for each bit length}
+  fillchar ( c, sizeof ( c ), #0 );
+  p := b; i := n;                      {p points to array of word}
+  REPEAT
+    IF p^ > b_max THEN BEGIN
+      t^ := NIL;
+      m := 0;
+      huft_build := huft_error;
+      exit
+    END;
+    inc ( c [ p^ ] );
+    inc ( longint ( p ), sizeof ( word ) );   {point to next item}
+    dec ( i );
+  UNTIL i = 0;
+  IF c [ 0 ] = n THEN BEGIN
+    t^ := NIL;
+    m := 0;
+    huft_build := huft_complete;
+    exit
+  END;
+
+  {find minimum and maximum length, bound m by those}
+  j := 1;
+  WHILE ( j <= b_max ) AND ( c [ j ] = 0 ) DO inc ( j );
+  k := j;
+  IF m < j THEN m := j;
+  i := b_max;
+  WHILE ( i > 0 ) AND ( c [ i ] = 0 ) DO dec ( i );
+  g := i;
+  IF m > i THEN m := i;
+
+  {adjust last length count to fill out codes, if needed}
+  y := 1 SHL j;
+  WHILE j < i DO BEGIN
+    y := y -c [ j ];
+    IF y < 0 THEN BEGIN
+      huft_build := huft_error;
+      exit
+    END;
+    y := y SHL 1;
+    inc ( j );
+  END;
+  dec ( y, c [ i ] );
+  IF y < 0 THEN BEGIN
+    huft_build := huft_error;
+    exit
+  END;
+  inc ( c [ i ], y );
+
+  {generate starting offsets into the value table for each length}
+  x [ 1 ] := 0;
+  j := 0;
+  p := @c; inc ( longint ( p ), sizeof ( word ) );
+  xp := @x;inc ( longint ( xp ), 2 * sizeof ( word ) );
+  dec ( i );
+  WHILE i <> 0 DO BEGIN
+    inc ( j, p^ );
+    xp^ := j;
+    inc ( longint ( p ), 2 );
+    inc ( longint ( xp ), 2 );
+    dec ( i );
+  END;
+
+  {make table of values in order of bit length}
+  p := b; i := 0;
+  REPEAT
+    j := p^;
+    inc ( longint ( p ), sizeof ( word ) );
+    IF j <> 0 THEN BEGIN
+      v [ x [ j ] ] := i;
+      inc ( x [ j ] );
+    END;
+    inc ( i );
+  UNTIL i >= n;
+
+  {generate huffman codes and for each, make the table entries}
+  x [ 0 ] := 0; i := 0;
+  p := @v;
+  h := -1;
+  l [  -1 ] := 0;
+  w := 0;
+  u [ 0 ] := NIL;
+  q := NIL;
+  z := 0;
+
+  {go through the bit lengths (k already is bits in shortest code)}
+  FOR k := k TO g DO BEGIN
+    FOR a := c [ k ] DOWNTO 1 DO BEGIN
+      {here i is the huffman code of length k bits for value p^}
+      WHILE k > w + l [ h ] DO BEGIN
+        inc ( w, l [ h ] ); {Length of tables to this position}
+        inc ( h );
+        z := g -w;
+        IF z > m THEN z := m;
+        j := k -w;
+        f := 1 SHL j;
+        IF f > a + 1 THEN BEGIN
+          dec ( f, a + 1 );
+          xp := @c [ k ];
+          inc ( j );
+          tryagain := TRUE;
+          WHILE ( j < z ) AND tryagain DO BEGIN
+            f := f SHL 1;
+            inc ( longint ( xp ), sizeof ( word ) );
+            IF f <= xp^ THEN tryagain := FALSE
+                      ELSE BEGIN
+                        dec ( f, xp^ );
+                        inc ( j );
+                      END;
+          END;
+        END;
+        IF ( w + j > el ) AND ( w < el ) THEN
+          j := el -w;       {Make eob code end at table}
+        IF w = 0 THEN BEGIN
+          j := m;  {*** Fix: main table always m bits!}
+        END;
+        z := 1 SHL j;
+        l [ h ] := j;
+
+        {allocate and link new table}
+        getmem ( q, ( z + 1 ) * sizeof ( huft ) );
+        IF q = NIL THEN BEGIN
+          IF h <> 0 THEN huft_free ( pointer ( u [ 0 ] ) );
+          huft_build := huft_outofmem;
+          exit
+        END;
+        fillchar ( q^, ( z + 1 ) * sizeof ( huft ), #0 );
+        q^ [ 0 ].v_n := z;  {Size of table, needed in freemem ***}
+        t^ := @q^ [ 1 ];     {first item starts at 1}
+        t := @q^ [ 0 ].v_t;
+        t^ := NIL;
+        q := @q^ [ 1 ];   {pointer(longint(q)+sizeof(huft));} {???}
+        u [ h ] := q;
+        {connect to last table, if there is one}
+        IF h <> 0 THEN BEGIN
+          x [ h ] := i;
+          r.b := l [ h -1 ];
+          r.e := 16 + j;
+          r.v_t := q;
+          j := ( i AND ( ( 1 SHL w ) -1 ) ) SHR ( w -l [ h -1 ] );
+
+          {test against bad input!}
+          pt := phuft ( longint ( u [ h -1 ] ) -sizeof ( huft ) );
+          IF j > pt^.v_n THEN BEGIN
+            huft_free ( pointer ( u [ 0 ] ) );
+            huft_build := huft_error;
+            exit
+          END;
+
+          pt := @u [ h -1 ]^ [ j ];
+          pt^ := r;
+        END;
+      END;
+
+      {set up table entry in r}
+      r.b := word ( k -w );
+      r.v_t := NIL;   {Unused}   {***********}
+      IF longint ( p ) >= longint ( @v [ n ] ) THEN r.e := 99
+      ELSE IF p^ < s THEN BEGIN
+        IF p^ < 256 THEN r.e := 16 ELSE r.e := 15;
+        r.v_n := p^;
+        inc ( longint ( p ), sizeof ( word ) );
+      END ELSE BEGIN
+        IF ( d = NIL ) OR ( e = NIL ) THEN BEGIN
+          huft_free ( pointer ( u [ 0 ] ) );
+          huft_build := huft_error;
+          exit
+        END;
+        r.e := word ( e^ [ p^ -s ] );
+        r.v_n := d^ [ p^ -s ];
+        inc ( longint ( p ), sizeof ( word ) );
+      END;
+
+      {fill code like entries with r}
+      f := 1 SHL ( k -w );
+      j := i SHR w;
+      WHILE j < z DO BEGIN
+        q^ [ j ] := r;
+        inc ( j, f );
+      END;
+
+      {backwards increment the k-bit code i}
+      j := 1 SHL ( k -1 );
+      WHILE ( i AND j ) <> 0 DO BEGIN
+        {i:=i^j;}
+        i := i XOR j;
+        j := j SHR 1;
+      END;
+      i := i XOR j;
+
+      {backup over finished tables}
+      WHILE ( ( i AND ( ( 1 SHL w ) -1 ) ) <> x [ h ] ) DO BEGIN
+        dec ( h );
+        dec ( w, l [ h ] ); {Size of previous table!}
+      END;
+    END;
+  END;
+  IF ( y <> 0 ) AND ( g <> 1 ) THEN huft_build := huft_incomplete
+                       ELSE huft_build := huft_complete;
+END;
+
+(***************************************************************************)
+{.$I z_inflat.pas}  {Inflate deflated file}
+{include for unzip.pas: Inflate deflated file}
+
+{C code by info-zip group, translated to Pascal by Christian Ghisler}
+{based on unz51g.zip}
+
+FUNCTION inflate_codes ( tl, td : phuftlist;bl, bd : integer ) : integer;
+VAR
+    n, d, e1,          {length and index for copy}
+    ml, md : longint;      {masks for bl and bd bits}
+    t : phuft;         {pointer to table entry}
+    e : byte;          {table entry flag/number of extra bits}
+
+BEGIN
+  { inflate the coded data }
+  ml := mask_bits [ bl ];          {precompute masks for speed}
+  md := mask_bits [ bd ];
+  WHILE NOT ( totalabort OR zipeof ) DO BEGIN
+    NEEDBITS ( bl );
+    t := @tl^ [ b AND ml ];
+    e := t^.e;
+    IF e > 16 THEN REPEAT       {then it's a literal}
+      IF e = 99 THEN BEGIN
+        inflate_codes := unzip_ZipFileErr;
+        exit
+      END;
+      DUMPBITS ( t^.b );
+      dec ( e, 16 );
+      NEEDBITS ( e );
+      t := @t^.v_t^ [ b AND mask_bits [ e ] ];
+      e := t^.e;
+    UNTIL e <= 16;
+    DUMPBITS ( t^.b );
+    IF e = 16 THEN BEGIN
+      slide [ w ] := char ( t^.v_n );
+      inc ( w );
+      IF w = WSIZE THEN BEGIN
+        IF NOT flush ( w ) THEN BEGIN
+          inflate_codes := unzip_WriteErr;
+          exit;
+        END;
+        w := 0
+      END;
+    END ELSE BEGIN                {it's an EOB or a length}
+      IF e = 15 THEN BEGIN {Ende}   {exit if end of block}
+        inflate_codes := unzip_Ok;
+        exit;
+      END;
+      NEEDBITS ( e );                 {get length of block to copy}
+      n := t^.v_n + ( b AND mask_bits [ e ] );
+      DUMPBITS ( e );
+
+      NEEDBITS ( bd );                {decode distance of block to copy}
+      t := @td^ [ b AND md ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          inflate_codes := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [ b AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+      DUMPBITS ( t^.b );
+      NEEDBITS ( e );
+      d := w -t^.v_n -b AND mask_bits [ e ];
+      DUMPBITS ( e );
+      {do the copy}
+      REPEAT
+        d := d AND ( WSIZE -1 );
+        IF d > w THEN e1 := WSIZE -d
+               ELSE e1 := WSIZE -w;
+        IF e1 > n THEN e1 := n;
+        dec ( n, e1 );
+        IF ( longint(w) -d >= e1 ) THEN BEGIN
+          move ( slide [ d ], slide [ w ], e1 );
+          inc ( w, e1 );
+          inc ( d, e1 );
+        END ELSE REPEAT
+          slide [ w ] := slide [ d ];
+          inc ( w );
+          inc ( d );
+          dec ( e1 );
+        UNTIL ( e1 = 0 );
+        IF w = WSIZE THEN BEGIN
+          IF NOT flush ( w ) THEN BEGIN
+            inflate_codes := unzip_WriteErr;
+            exit;
+          END;
+          w := 0;
+        END;
+      UNTIL n = 0;
+    END;
+  END;
+  IF totalabort THEN
+    inflate_codes := unzip_userabort
+  ELSE
+    inflate_codes := unzip_readErr;
+END;
+
+{**************************** "decompress" stored block **************************}
+
+FUNCTION inflate_stored : integer;
+VAR n : word;            {number of bytes in block}
+
+BEGIN
+  {go to byte boundary}
+  n := k AND 7;
+  dumpbits ( n );
+  {get the length and its complement}
+  NEEDBITS ( 16 );
+  n := b AND $ffff;
+  DUMPBITS ( 16 );
+  NEEDBITS ( 16 );
+  IF ( n <> ( NOT b ) AND $ffff ) THEN BEGIN
+    inflate_stored := unzip_zipFileErr;
+    exit
+  END;
+  DUMPBITS ( 16 );
+  WHILE ( n > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN {read and output the compressed data}
+    dec ( n );
+    NEEDBITS ( 8 );
+    slide [ w ] := char ( b );
+    inc ( w );
+    IF w = WSIZE THEN BEGIN
+      IF NOT flush ( w ) THEN BEGIN
+        inflate_stored := unzip_WriteErr;
+        exit
+      END;
+      w := 0;
+    END;
+    DUMPBITS ( 8 );
+  END;
+  IF totalabort THEN inflate_stored := unzip_UserAbort
+    ELSE IF zipeof THEN inflate_stored := unzip_readErr
+      ELSE inflate_stored := unzip_Ok;
+END;
+
+{**************************** decompress fixed block **************************}
+
+FUNCTION inflate_fixed : integer;
+VAR i : integer;               {temporary variable}
+    tl,                      {literal/length code table}
+    td : phuftlist;                {distance code table}
+    bl, bd : integer;           {lookup bits for tl/bd}
+    l : ARRAY [ 0..287 ] of word; {length list for huft_build}
+
+BEGIN
+  {set up literal table}
+  FOR i := 0 TO 143 DO l [ i ] := 8;
+  FOR i := 144 TO 255 DO l [ i ] := 9;
+  FOR i := 256 TO 279 DO l [ i ] := 7;
+  FOR i := 280 TO 287 DO l [ i ] := 8; {make a complete, but wrong code set}
+  bl := 7;
+  i := huft_build ( pword ( @l ), 288, 257, pushlist ( @cplens ), pushlist ( @cplext ), @tl, bl );
+  IF i <> huft_complete THEN BEGIN
+    inflate_fixed := i;
+    exit
+  END;
+  FOR i := 0 TO 29 DO l [ i ] := 5;    {make an incomplete code set}
+  bd := 5;
+  i := huft_build ( pword ( @l ), 30, 0, pushlist ( @cpdist ), pushlist ( @cpdext ), @td, bd );
+  IF i > huft_incomplete THEN BEGIN
+    huft_free ( tl );
+    inflate_fixed := unzip_ZipFileErr;
+    exit
+  END;
+  inflate_fixed := inflate_codes ( tl, td, bl, bd );
+  huft_free ( tl );
+  huft_free ( td );
+END;
+
+{**************************** decompress dynamic block **************************}
+
+FUNCTION inflate_dynamic : integer;
+VAR i : integer;                      {temporary variables}
+    j,
+    l,                              {last length}
+    m,                              {mask for bit length table}
+    n : word;                         {number of lengths to get}
+    tl,                             {literal/length code table}
+    td : phuftlist;                   {distance code table}
+    bl, bd : integer;                  {lookup bits for tl/bd}
+    nb, nl, nd : word;                  {number of bit length/literal length/distance codes}
+    ll : ARRAY [ 0..288 + 32 -1 ] of word;  {literal/length and distance code lengths}
+
+BEGIN
+  {read in table lengths}
+  NEEDBITS ( 5 );
+  nl := 257 + word ( b ) AND $1f;
+  DUMPBITS ( 5 );
+  NEEDBITS ( 5 );
+  nd := 1 + word ( b ) AND $1f;
+  DUMPBITS ( 5 );
+  NEEDBITS ( 4 );
+  nb := 4 + word ( b ) AND $f;
+  DUMPBITS ( 4 );
+  IF ( nl > 288 ) OR ( nd > 32 ) THEN BEGIN
+    inflate_dynamic := 1;
+    exit
+  END;
+  fillchar ( ll, sizeof ( ll ), #0 );
+
+  {read in bit-length-code lengths}
+  FOR j := 0 TO nb -1 DO BEGIN
+    NEEDBITS ( 3 );
+    ll [ border [ j ] ] := b AND 7;
+    DUMPBITS ( 3 );
+  END;
+  FOR j := nb TO 18 DO ll [ border [ j ] ] := 0;
+
+  {build decoding table for trees--single level, 7 bit lookup}
+  bl := 7;
+  i := huft_build ( pword ( @ll ), 19, 19, NIL, NIL, @tl, bl );
+  IF i <> huft_complete THEN BEGIN
+    IF i = huft_incomplete THEN huft_free ( tl ); {other errors: already freed}
+    inflate_dynamic := unzip_ZipFileErr;
+    exit
+  END;
+
+  {read in literal and distance code lengths}
+  n := nl + nd;
+  m := mask_bits [ bl ];
+  i := 0; l := 0;
+  WHILE word ( i ) < n DO BEGIN
+    NEEDBITS ( bl );
+    td := @tl^ [ b AND m ];
+    j := phuft ( td ) ^.b;
+    DUMPBITS ( j );
+    j := phuft ( td ) ^.v_n;
+    IF j < 16 THEN BEGIN            {length of code in bits (0..15)}
+      l := j;                       {ave last length in l}
+      ll [ i ] := l;
+      inc ( i )
+    END ELSE IF j = 16 THEN BEGIN   {repeat last length 3 to 6 times}
+      NEEDBITS ( 2 );
+      j := 3 + b AND 3;
+      DUMPBITS ( 2 );
+      IF i + j > n THEN BEGIN
+        inflate_dynamic := 1;
+        exit
+      END;
+      WHILE j > 0 DO BEGIN
+        ll [ i ] := l;
+        dec ( j );
+        inc ( i );
+      END;
+    END ELSE IF j = 17 THEN BEGIN   {3 to 10 zero length codes}
+      NEEDBITS ( 3 );
+      j := 3 + b AND 7;
+      DUMPBITS ( 3 );
+      IF i + j > n THEN BEGIN
+        inflate_dynamic := 1;
+        exit
+      END;
+      WHILE j > 0 DO BEGIN
+        ll [ i ] := 0;
+        inc ( i );
+        dec ( j );
+      END;
+      l := 0;
+    END ELSE BEGIN                {j == 18: 11 to 138 zero length codes}
+      NEEDBITS ( 7 );
+      j := 11 + b AND $7f;
+      DUMPBITS ( 7 );
+      IF i + j > n THEN BEGIN
+        inflate_dynamic := unzip_zipfileErr;
+        exit
+      END;
+      WHILE j > 0 DO BEGIN
+        ll [ i ] := 0;
+        dec ( j );
+        inc ( i );
+      END;
+      l := 0;
+    END;
+  END;
+  huft_free ( tl );        {free decoding table for trees}
+
+  {build the decoding tables for literal/length and distance codes}
+  bl := lbits;
+  i := huft_build ( pword ( @ll ), nl, 257, pushlist ( @cplens ), pushlist ( @cplext ), @tl, bl );
+  IF i <> huft_complete THEN BEGIN
+    IF i = huft_incomplete THEN huft_free ( tl );
+    inflate_dynamic := unzip_ZipFileErr;
+    exit
+  END;
+  bd := dbits;
+  i := huft_build ( pword ( @ll [ nl ] ), nd, 0, pushlist ( @cpdist ), pushlist ( @cpdext ), @td, bd );
+  IF i > huft_incomplete THEN BEGIN {pkzip bug workaround}
+    IF i = huft_incomplete THEN huft_free ( td );
+    huft_free ( tl );
+    inflate_dynamic := unzip_ZipFileErr;
+    exit
+  END;
+  {decompress until an end-of-block code}
+  inflate_dynamic := inflate_codes ( tl, td, bl, bd );
+  huft_free ( tl );
+  huft_free ( td );
+END;
+
+{**************************** decompress a block ******************************}
+
+FUNCTION inflate_block ( VAR e : integer ) : integer;
+VAR t : word;           {block type}
+
+BEGIN
+  NEEDBITS ( 1 );
+  e := b AND 1;
+  DUMPBITS ( 1 );
+
+  NEEDBITS ( 2 );
+  t := b AND 3;
+  DUMPBITS ( 2 );
+
+  CASE t of
+    2 : inflate_block := inflate_dynamic;
+    0 : inflate_block := inflate_stored;
+    1 : inflate_block := inflate_fixed;
+  ELSE
+    inflate_block := unzip_ZipFileErr;  {bad block type}
+  END;
+END;
+
+{**************************** decompress an inflated entry **************************}
+
+FUNCTION inflate : integer;
+VAR e,                 {last block flag}
+    r : integer;         {result code}
+
+BEGIN
+  inpos := 0;            {Input buffer position}
+  readpos := -1;         {Nothing read}
+
+  {initialize window, bit buffer}
+  w := 0;
+  k := 0;
+  b := 0;
+
+  {decompress until the last block}
+  REPEAT
+    r := inflate_block ( e );
+    IF r <> 0 THEN BEGIN
+      inflate := r;
+      exit
+    END;
+  UNTIL e <> 0;
+  {flush out slide}
+  IF NOT flush ( w ) THEN inflate := unzip_WriteErr
+  ELSE inflate := unzip_Ok;
+END;
+(***************************************************************************)
+{.$I z_copyst.pas}  {Copy stored file}
+{include for unzip.pas: Copy stored file}
+
+{C code by info-zip group, translated to Pascal by Christian Ghisler}
+{based on unz51g.zip}
+
+{************************* copy stored file ************************************}
+FUNCTION copystored : integer;
+VAR readin : longint;
+    outcnt : nword;
+BEGIN
+  WHILE ( reachedsize < compsize ) AND NOT totalabort DO BEGIN
+    readin := compsize -reachedsize;
+    IF readin > wsize THEN readin := wsize;
+    {$I-}
+    blockread ( infile, slide [ 0 ], readin, outcnt );  {Use slide as buffer}
+    {$I+}
+    IF ( outcnt <> readin ) OR ( ioresult <> 0 ) THEN BEGIN
+      copystored := unzip_ReadErr;
+      exit
+    END;
+    IF NOT flush ( outcnt ) THEN BEGIN  {Flushoutput takes care of CRC too}
+      copystored := unzip_WriteErr;
+      exit
+    END;
+    inc ( reachedsize, outcnt );
+    messageloop;      {Other programs, or in DOS: keypressed?}
+    {$ifdef windows}
+    showpercent;
+    {$endif}
+  END;
+  IF NOT totalabort THEN
+    copystored := unzip_Ok
+  ELSE
+    copystored := unzip_Userabort;
+END;
+(***************************************************************************)
+{.$I z_explod.pas}  {Explode imploded file}
+{include for unzip.pas: Explode imploded file}
+
+{C code by info-zip group, translated to Pascal by Christian Ghisler}
+{based on unz51g.zip}
+
+{************************************* explode ********************************}
+
+{*********************************** read in tree *****************************}
+FUNCTION get_tree ( l : pword;n : word ) : integer;
+VAR i, k, j, b : word;
+    bytebuf : byte;
+
+BEGIN
+  READBYTE ( bytebuf );
+  i := bytebuf;
+  inc ( i );
+  k := 0;
+  REPEAT
+    READBYTE ( bytebuf );
+    j := bytebuf;
+    b := ( j AND $F ) + 1;
+    j := ( ( j AND $F0 ) SHR 4 ) + 1;
+    IF ( k + j ) > n THEN BEGIN
+      get_tree := 4;
+      exit
+    END;
+    REPEAT
+      l^ := b;
+      inc ( longint ( l ), sizeof ( word ) );
+      inc ( k );
+      dec ( j );
+    UNTIL j = 0;
+    dec ( i );
+  UNTIL i = 0;
+  IF k <> n THEN get_tree := 4 ELSE get_tree := 0;
+END;
+
+{******************exploding, method: 8k slide, 3 trees ***********************}
+
+FUNCTION explode_lit8 ( tb, tl, td : phuftlist;bb, bl, bd : integer ) : integer;
+VAR s : longint;
+    e : word;
+    n, d : word;
+    w : word;
+    t : phuft;
+    mb, ml, md : word;
+    u : word;
+
+BEGIN
+  b := 0; k := 0; w := 0;
+  u := 1;
+  mb := mask_bits [ bb ];
+  ml := mask_bits [ bl ];
+  md := mask_bits [ bd ];
+  s := uncompsize;
+  WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
+    NEEDBITS ( 1 );
+    IF ( b AND 1 ) <> 0 THEN BEGIN  {Litteral}
+      DUMPBITS ( 1 );
+      dec ( s );
+      NEEDBITS ( bb );
+      t := @tb^ [  ( NOT b ) AND mb ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_lit8 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+      DUMPBITS ( t^.b );
+      slide [ w ] := char ( t^.v_n );
+      inc ( w );
+      IF w = WSIZE THEN BEGIN
+        IF NOT flush ( w ) THEN BEGIN
+          explode_lit8 := unzip_WriteErr;
+          exit
+        END;
+        w := 0; u := 0;
+      END;
+    END ELSE BEGIN
+      DUMPBITS ( 1 );
+      NEEDBITS ( 7 );
+      d := b AND $7F;
+      DUMPBITS ( 7 );
+      NEEDBITS ( bd );
+      t := @td^ [  ( NOT b ) AND md ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_lit8 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+      DUMPBITS ( t^.b );
+
+      d := w -d -t^.v_n;
+      NEEDBITS ( bl );
+      t := @tl^ [  ( NOT b ) AND ml ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_lit8 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+
+      DUMPBITS ( t^.b );
+
+      n := t^.v_n;
+      IF e <> 0 THEN BEGIN
+        NEEDBITS ( 8 );
+        inc ( n, byte ( b ) AND $ff );
+        DUMPBITS ( 8 );
+      END;
+      dec ( s, n );
+      REPEAT
+        d := d AND pred ( WSIZE );
+        IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
+        IF e > n THEN e := n;
+        dec ( n, e );
+        IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
+          fillchar ( slide [ w ], e, #0 );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE IF ( w -d >= e ) THEN BEGIN
+          move ( slide [ d ], slide [ w ], e );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE REPEAT
+          slide [ w ] := slide [ d ];
+          inc ( w );
+          inc ( d );
+          dec ( e );
+        UNTIL e = 0;
+        IF w = WSIZE THEN BEGIN
+          IF NOT flush ( w ) THEN BEGIN
+            explode_lit8 := unzip_WriteErr;
+            exit
+          END;
+          w := 0; u := 0;
+        END;
+      UNTIL n = 0;
+    END;
+  END;
+  IF totalabort THEN explode_lit8 := unzip_userabort
+  ELSE
+    IF NOT flush ( w ) THEN explode_lit8 := unzip_WriteErr
+  ELSE
+    IF zipeof THEN explode_lit8 := unzip_readErr
+  ELSE
+    explode_lit8 := unzip_Ok;
+END;
+
+{******************exploding, method: 4k slide, 3 trees ***********************}
+
+FUNCTION explode_lit4 ( tb, tl, td : phuftlist;bb, bl, bd : integer ) : integer;
+VAR s : longint;
+    e : word;
+    n, d : word;
+    w : word;
+    t : phuft;
+    mb, ml, md : word;
+    u : word;
+
+BEGIN
+  b := 0; k := 0; w := 0;
+  u := 1;
+  mb := mask_bits [ bb ];
+  ml := mask_bits [ bl ];
+  md := mask_bits [ bd ];
+  s := uncompsize;
+  WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
+    NEEDBITS ( 1 );
+    IF ( b AND 1 ) <> 0 THEN BEGIN  {Litteral}
+      DUMPBITS ( 1 );
+      dec ( s );
+      NEEDBITS ( bb );
+      t := @tb^ [  ( NOT b ) AND mb ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_lit4 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+      DUMPBITS ( t^.b );
+      slide [ w ] := char ( t^.v_n );
+      inc ( w );
+      IF w = WSIZE THEN BEGIN
+        IF NOT flush ( w ) THEN BEGIN
+          explode_lit4 := unzip_WriteErr;
+          exit
+        END;
+        w := 0; u := 0;
+      END;
+    END ELSE BEGIN
+      DUMPBITS ( 1 );
+      NEEDBITS ( 6 );
+      d := b AND $3F;
+      DUMPBITS ( 6 );
+      NEEDBITS ( bd );
+      t := @td^ [  ( NOT b ) AND md ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_lit4 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+      DUMPBITS ( t^.b );
+      d := w -d -t^.v_n;
+      NEEDBITS ( bl );
+      t := @tl^ [  ( NOT b ) AND ml ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_lit4 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+
+      DUMPBITS ( t^.b );
+      n := t^.v_n;
+      IF e <> 0 THEN BEGIN
+        NEEDBITS ( 8 );
+        inc ( n, b AND $ff );
+        DUMPBITS ( 8 );
+      END;
+      dec ( s, n );
+      REPEAT
+        d := d AND pred ( WSIZE );
+        IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
+        IF e > n THEN e := n;
+        dec ( n, e );
+        IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
+          fillchar ( slide [ w ], e, #0 );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE IF ( w -d >= e ) THEN BEGIN
+          move ( slide [ d ], slide [ w ], e );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE REPEAT
+          slide [ w ] := slide [ d ];
+          inc ( w );
+          inc ( d );
+          dec ( e );
+        UNTIL e = 0;
+        IF w = WSIZE THEN BEGIN
+          IF NOT flush ( w ) THEN BEGIN
+            explode_lit4 := unzip_WriteErr;
+            exit
+          END;
+          w := 0; u := 0;
+        END;
+      UNTIL n = 0;
+    END;
+  END;
+  IF totalabort THEN explode_lit4 := unzip_userabort
+  ELSE
+  IF NOT flush ( w ) THEN explode_lit4 := unzip_WriteErr
+  ELSE
+    IF zipeof THEN explode_lit4 := unzip_readErr
+  ELSE explode_lit4 := unzip_Ok;
+END;
+
+{******************exploding, method: 8k slide, 2 trees ***********************}
+
+FUNCTION explode_nolit8 ( tl, td : phuftlist;bl, bd : integer ) : integer;
+VAR s : longint;
+    e : word;
+    n, d : word;
+    w : word;
+    t : phuft;
+    ml, md : word;
+    u : word;
+
+BEGIN
+  b := 0; k := 0; w := 0;
+  u := 1;
+  ml := mask_bits [ bl ];
+  md := mask_bits [ bd ];
+  s := uncompsize;
+  WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
+    NEEDBITS ( 1 );
+    IF ( b AND 1 ) <> 0 THEN BEGIN  {Litteral}
+      DUMPBITS ( 1 );
+      dec ( s );
+      NEEDBITS ( 8 );
+      slide [ w ] := char ( b );
+      inc ( w );
+      IF w = WSIZE THEN BEGIN
+        IF NOT flush ( w ) THEN BEGIN
+          explode_nolit8 := unzip_WriteErr;
+          exit
+        END;
+        w := 0; u := 0;
+      END;
+      DUMPBITS ( 8 );
+    END ELSE BEGIN
+      DUMPBITS ( 1 );
+      NEEDBITS ( 7 );
+      d := b AND $7F;
+      DUMPBITS ( 7 );
+      NEEDBITS ( bd );
+      t := @td^ [  ( NOT b ) AND md ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_nolit8 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+      DUMPBITS ( t^.b );
+
+      d := w -d -t^.v_n;
+      NEEDBITS ( bl );
+      t := @tl^ [  ( NOT b ) AND ml ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_nolit8 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+
+      DUMPBITS ( t^.b );
+
+      n := t^.v_n;
+      IF e <> 0 THEN BEGIN
+        NEEDBITS ( 8 );
+        inc ( n, b AND $ff );
+        DUMPBITS ( 8 );
+      END;
+      dec ( s, n );
+      REPEAT
+        d := d AND pred ( WSIZE );
+        IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
+        IF e > n THEN e := n;
+        dec ( n, e );
+        IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
+          fillchar ( slide [ w ], e, #0 );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE IF ( w -d >= e ) THEN BEGIN
+          move ( slide [ d ], slide [ w ], e );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE REPEAT
+          slide [ w ] := slide [ d ];
+          inc ( w );
+          inc ( d );
+          dec ( e );
+        UNTIL e = 0;
+        IF w = WSIZE THEN BEGIN
+          IF NOT flush ( w ) THEN BEGIN
+            explode_nolit8 := unzip_WriteErr;
+            exit
+          END;
+          w := 0; u := 0;
+        END;
+      UNTIL n = 0;
+    END;
+  END;
+  IF totalabort THEN explode_nolit8 := unzip_userabort
+  ELSE
+  IF NOT flush ( w ) THEN explode_nolit8 := unzip_WriteErr
+  ELSE
+    IF zipeof THEN explode_nolit8 := unzip_readErr
+  ELSE explode_nolit8 := unzip_Ok;
+END;
+
+{******************exploding, method: 4k slide, 2 trees ***********************}
+
+FUNCTION explode_nolit4 ( tl, td : phuftlist;bl, bd : integer ) : integer;
+VAR s : longint;
+    e : word;
+    n, d : word;
+    w : word;
+    t : phuft;
+    ml, md : word;
+    u : word;
+
+BEGIN
+  b := 0; k := 0; w := 0;
+  u := 1;
+  ml := mask_bits [ bl ];
+  md := mask_bits [ bd ];
+  s := uncompsize;
+  WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
+    NEEDBITS ( 1 );
+    IF ( b AND 1 ) <> 0 THEN BEGIN  {Litteral}
+      DUMPBITS ( 1 );
+      dec ( s );
+      NEEDBITS ( 8 );
+      slide [ w ] := char ( b );
+      inc ( w );
+      IF w = WSIZE THEN BEGIN
+        IF NOT flush ( w ) THEN BEGIN
+          explode_nolit4 := unzip_WriteErr;
+          exit
+        END;
+        w := 0; u := 0;
+      END;
+      DUMPBITS ( 8 );
+    END ELSE BEGIN
+      DUMPBITS ( 1 );
+      NEEDBITS ( 6 );
+      d := b AND $3F;
+      DUMPBITS ( 6 );
+      NEEDBITS ( bd );
+      t := @td^ [  ( NOT b ) AND md ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_nolit4 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+      DUMPBITS ( t^.b );
+      d := w -d -t^.v_n;
+      NEEDBITS ( bl );
+      t := @tl^ [  ( NOT b ) AND ml ];
+      e := t^.e;
+      IF e > 16 THEN REPEAT
+        IF e = 99 THEN BEGIN
+          explode_nolit4 := unzip_ZipFileErr;
+          exit
+        END;
+        DUMPBITS ( t^.b );
+        dec ( e, 16 );
+        NEEDBITS ( e );
+        t := @t^.v_t^ [  ( NOT b ) AND mask_bits [ e ] ];
+        e := t^.e;
+      UNTIL e <= 16;
+
+      DUMPBITS ( t^.b );
+      n := t^.v_n;
+      IF e <> 0 THEN BEGIN
+        NEEDBITS ( 8 );
+        inc ( n, b AND $ff );
+        DUMPBITS ( 8 );
+      END;
+      dec ( s, n );
+      REPEAT
+        d := d AND pred ( WSIZE );
+        IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
+        IF e > n THEN e := n;
+        dec ( n, e );
+        IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
+          fillchar ( slide [ w ], e, #0 );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE IF ( w -d >= e ) THEN BEGIN
+          move ( slide [ d ], slide [ w ], e );
+          inc ( w, e );
+          inc ( d, e );
+        END ELSE REPEAT
+          slide [ w ] := slide [ d ];
+          inc ( w );
+          inc ( d );
+          dec ( e );
+        UNTIL e = 0;
+        IF w = WSIZE THEN BEGIN
+          IF NOT flush ( w ) THEN BEGIN
+            explode_nolit4 := unzip_WriteErr;
+            exit
+          END;
+          w := 0; u := 0;
+        END;
+      UNTIL n = 0;
+    END;
+  END;
+  IF totalabort THEN explode_nolit4 := unzip_userabort
+  ELSE
+  IF NOT flush ( w ) THEN explode_nolit4 := unzip_WriteErr
+  ELSE
+    IF zipeof THEN explode_nolit4 := unzip_readErr
+  ELSE explode_nolit4 := unzip_Ok;
+END;
+
+{****************************** explode *********************************}
+
+FUNCTION explode : integer;
+VAR r : integer;
+    tb, tl, td : phuftlist;
+    bb, bl, bd : integer;
+    l : ARRAY [ 0..255 ] of word;
+
+BEGIN
+  inpos := 0;
+  readpos := -1;  {Nothing read in}
+  bl := 7;
+  IF compsize > 200000 THEN bd := 8 ELSE bd := 7;
+  IF hufttype AND 4 <> 0 THEN BEGIN
+    bb := 9;
+    r := get_tree ( @l [ 0 ], 256 );
+    IF r <> 0 THEN BEGIN
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+    r := huft_build ( @l, 256, 256, NIL, NIL, @tb, bb );
+    IF r <> 0 THEN BEGIN
+      IF r = huft_incomplete THEN huft_free ( tb );
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+    r := get_tree ( @l [ 0 ], 64 );
+    IF r <> 0 THEN BEGIN
+      huft_free ( tb );
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+    r := huft_build ( @l, 64, 0, pushlist ( @cplen3 ), pushlist ( @extra ), @tl, bl );
+    IF r <> 0 THEN BEGIN
+      IF r = huft_incomplete THEN huft_free ( tl );
+      huft_free ( tb );
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+    r := get_tree ( @l [ 0 ], 64 );
+    IF r <> 0 THEN BEGIN
+      huft_free ( tb );
+      huft_free ( tl );
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+    IF hufttype AND 2 <> 0 THEN BEGIN {8k}
+      r := huft_build ( @l, 64, 0, pushlist ( @cpdist8 ), pushlist ( @extra ), @td, bd );
+      IF r <> 0 THEN BEGIN
+        IF r = huft_incomplete THEN huft_free ( td );
+        huft_free ( tb );
+        huft_free ( tl );
+        explode := unzip_ZipFileErr;
+        exit
+      END;
+      r := explode_lit8 ( tb, tl, td, bb, bl, bd );
+    END ELSE BEGIN
+      r := huft_build ( @l, 64, 0, pushlist ( @cpdist4 ), pushlist ( @extra ), @td, bd );
+      IF r <> 0 THEN BEGIN
+        IF r = huft_incomplete THEN huft_free ( td );
+        huft_free ( tb );
+        huft_free ( tl );
+        explode := unzip_ZipFileErr;
+        exit
+      END;
+      r := explode_lit4 ( tb, tl, td, bb, bl, bd );
+    END;
+    huft_free ( td );
+    huft_free ( tl );
+    huft_free ( tb );
+  END ELSE BEGIN       {No literal tree}
+    r := get_tree ( @l [ 0 ], 64 );
+    IF r <> 0 THEN BEGIN
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+    r := huft_build ( @l, 64, 0, pushlist ( @cplen2 ), pushlist ( @extra ), @tl, bl );
+    IF r <> 0 THEN BEGIN
+      IF r = huft_incomplete THEN huft_free ( tl );
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+
+    r := get_tree ( @l [ 0 ], 64 );
+    IF r <> 0 THEN BEGIN
+      huft_free ( tl );
+      explode := unzip_ZipFileErr;
+      exit
+    END;
+    IF hufttype AND 2 <> 0 THEN BEGIN {8k}
+      r := huft_build ( @l, 64, 0, pushlist ( @cpdist8 ), pushlist ( @extra ), @td, bd );
+      IF r <> 0 THEN BEGIN
+        IF r = huft_incomplete THEN huft_free ( td );
+        huft_free ( tl );
+        explode := unzip_ZipFileErr;
+        exit
+      END;
+      r := explode_nolit8 ( tl, td, bl, bd );
+    END ELSE BEGIN
+      r := huft_build ( @l, 64, 0, pushlist ( @cpdist4 ), pushlist ( @extra ), @td, bd );
+      IF r <> 0 THEN BEGIN
+        IF r = huft_incomplete THEN huft_free ( td );
+        huft_free ( tl );
+        explode := unzip_ZipFileErr;
+        exit
+      END;
+      r := explode_nolit4 ( tl, td, bl, bd );
+    END;
+    huft_free ( td );
+    huft_free ( tl );
+  END;
+  explode := r;
+END;
+(***************************************************************************)
+{.$I z_shrunk.pas}  {Unshrink function}
+{*************************** unshrink **********************************}
+{Written and NOT copyrighted by Christian Ghisler.
+ I have rewritten unshrink because the original
+ function was copyrighted by Mr. Smith of Info-zip
+ This funtion here is now completely FREE!!!!
+ The only right I claim on this code is that
+ noone else claims a copyright on it!}
+
+
+CONST max_code = 8192;
+      max_stack = 8192;
+      initial_code_size = 9;
+      final_code_size = 13;
+      write_max = wsize -3 * ( max_code -256 ) -max_stack -2;  {Rest of slide=write buffer}
+                                                     {=766 bytes}
+
+TYPE prev = ARRAY [ 257..max_code ] of integer;
+     pprev = ^prev;
+     cds = ARRAY [ 257..max_code ] of char;
+     pcds = ^cds;
+     stacktype = ARRAY [ 0..max_stack ] of char;
+     pstacktype = ^stacktype;
+     writebuftype = ARRAY [ 0..write_max ] of char;   {write buffer}
+     pwritebuftype = ^writebuftype;
+
+VAR previous_code : pprev;       {previous code trie}
+    actual_code : pcds;          {actual code trie}
+    stack : pstacktype;          {Stack for output}
+    writebuf : pwritebuftype;    {Write buffer}
+    next_free,                 {Next free code in trie}
+    write_ptr : integer;         {Pointer to output buffer}
+
+FUNCTION unshrink_flush : boolean;
+VAR
+n : nword;
+b : boolean;
+BEGIN
+  {$I-}
+  blockwrite ( outfile, writebuf^ [ 0 ], write_ptr, n );
+  {$I+}
+  b := ( n = write_ptr ) AND ( ioresult = 0 );  {True-> alles ok}
+  UpdateCRC ( iobuf ( pointer ( @writebuf^ [ 0 ] ) ^ ), write_ptr );
+  {--}
+{$IFDEF FPC}
+  IF ( b = TRUE ) AND Assigned(ZipReport)  {callback report for high level functions}
+{$ELSE}
+  IF ( b = TRUE ) AND ( @ZipReport <> NIL )  {callback report for high level functions}
+{$ENDIF}
+  THEN BEGIN
+      WITH ZipRec DO BEGIN
+           Status := file_unzipping;
+           ZipReport ( n, @ZipRec );    {report the actual bytes written}
+      END;
+  END; {report}
+  unshrink_flush := b;
+END;
+
+FUNCTION write_char ( c : char ) : boolean;
+BEGIN
+  writebuf^ [ write_ptr ] := c;
+  inc ( write_ptr );
+  IF write_ptr > write_max THEN BEGIN
+    write_char := unshrink_flush;
+    write_ptr := 0;
+  END ELSE write_char := TRUE;
+END;
+
+PROCEDURE ClearLeafNodes;
+VAR pc,                    {previous code}
+    i,                     {index}
+    act_max_code : integer;  {max code to be searched for leaf nodes}
+    previous : pprev;   {previous code trie}
+
+BEGIN
+  previous := previous_code;
+  act_max_code := next_free -1;
+  FOR i := 257 TO act_max_code DO
+    previous^ [ i ] := previous^ [ i ] OR $8000;
+  FOR i := 257 TO act_max_code DO BEGIN
+    pc := previous^ [ i ] AND NOT $8000;
+    IF pc > 256 THEN
+      previous^ [ pc ] := previous^ [ pc ] AND ( NOT $8000 );
+  END;
+  {Build new free list}
+  pc := -1;
+  next_free := -1;
+  FOR i := 257 TO act_max_code DO
+    IF previous^ [ i ] AND $C000 <> 0 THEN BEGIN {Either free before or marked now}
+      IF pc <> -1 THEN previous^ [ pc ] := -i     {Link last item to this item}
+                ELSE next_free := i;
+      pc := i;
+    END;
+  IF pc <> -1 THEN
+    previous^ [ pc ] := -act_max_code -1;
+END;
+
+
+FUNCTION unshrink : integer;
+
+VAR incode : integer;            {code read in}
+    lastincode : integer;        {last code read in}
+    lastoutcode : char;          {last code emitted}
+    code_size : byte;            {Actual code size}
+    stack_ptr,                 {Stackpointer}
+    new_code,                  {Save new code read}
+    code_mask,                 {mask for coding}
+    i : integer;                 {Index}
+    bits_to_read : longint;
+
+BEGIN
+  IF compsize = maxlongint THEN BEGIN   {Compressed Size was not in header!}
+    unshrink := unzip_NotSupported;
+    exit
+  END;
+  inpos := 0;            {Input buffer position}
+  readpos := -1;         {Nothing read}
+
+  {initialize window, bit buffer}
+  w := 0;
+  k := 0;
+  b := 0;
+
+  {Initialize pointers for various buffers}
+  previous_code := @slide [ 0 ];
+  actual_code := @slide [ sizeof ( prev ) ];
+  stack := @slide [ sizeof ( prev ) + sizeof ( cds ) ];
+  writebuf := @slide [ sizeof ( prev ) + sizeof ( cds ) + sizeof ( stacktype ) ];
+  fillchar ( slide^, wsize, #0 );
+
+  {initialize free codes list}
+  FOR i := 257 TO max_code DO
+    previous_code^ [ i ] := - ( i + 1 );
+  next_free := 257;
+  stack_ptr := max_stack;
+  write_ptr := 0;
+  code_size := initial_code_size;
+  code_mask := mask_bits [ code_size ];
+
+  NEEDBITS ( code_size );
+  incode := b AND code_mask;
+  DUMPBITS ( code_size );
+
+  lastincode := incode;
+  lastoutcode := char ( incode );
+  IF NOT write_char ( lastoutcode ) THEN BEGIN
+    unshrink := unzip_writeErr;
+    exit
+  END;
+
+  bits_to_read := 8 * compsize -code_size;   {Bits to be read}
+
+  WHILE NOT totalabort AND ( bits_to_read >= code_size ) DO BEGIN
+    NEEDBITS ( code_size );
+    incode := b AND code_mask;
+    DUMPBITS ( code_size );
+    dec ( bits_to_read, code_size );
+    IF incode = 256 THEN BEGIN            {Special code}
+      NEEDBITS ( code_size );
+      incode := b AND code_mask;
+      DUMPBITS ( code_size );
+      dec ( bits_to_read, code_size );
+      CASE incode of
+        1 : BEGIN
+          inc ( code_size );
+          IF code_size > final_code_size THEN BEGIN
+            unshrink := unzip_ZipFileErr;
+            exit
+          END;
+          code_mask := mask_bits [ code_size ];
+        END;
+        2 : BEGIN
+          ClearLeafNodes;
+        END;
+      ELSE
+        unshrink := unzip_ZipFileErr;
+        exit
+      END;
+    END ELSE BEGIN
+      new_code := incode;
+      IF incode < 256 THEN BEGIN          {Simple char}
+        lastoutcode := char ( incode );
+        IF NOT write_char ( lastoutcode ) THEN BEGIN
+          unshrink := unzip_writeErr;
+          exit
+        END;
+      END ELSE BEGIN
+        IF previous_code^ [ incode ] < 0 THEN BEGIN
+          stack^ [ stack_ptr ] := lastoutcode;
+          dec ( stack_ptr );
+          incode := lastincode;
+        END;
+        WHILE incode > 256 DO BEGIN
+          stack^ [ stack_ptr ] := actual_code^ [ incode ];
+          dec ( stack_ptr );
+          incode := previous_code^ [ incode ];
+        END;
+        lastoutcode := char ( incode );
+        IF NOT write_char ( lastoutcode ) THEN BEGIN
+          unshrink := unzip_writeErr;
+          exit
+        END;
+        FOR i := stack_ptr + 1 TO max_stack DO
+          IF NOT write_char ( stack^ [ i ] ) THEN BEGIN
+            unshrink := unzip_writeErr;
+            exit
+          END;
+        stack_ptr := max_stack;
+      END;
+      incode := next_free;
+      IF incode <= max_code THEN BEGIN
+        next_free := -previous_code^ [ incode ];   {Next node in free list}
+        previous_code^ [ incode ] := lastincode;
+        actual_code^ [ incode ] := lastoutcode;
+      END;
+      lastincode := new_code;
+    END;
+  END;
+  IF totalabort THEN
+    unshrink := unzip_UserAbort
+  ELSE IF unshrink_flush THEN
+    unshrink := unzip_ok
+  ELSE
+    unshrink := unzip_WriteErr;
+END;
+(***************************************************************************)
+{***************************************************************************}
+FUNCTION GetSupportedMethods : longint;
+BEGIN
+  GetSupportedMethods := 1 + ( 1 SHL 1 ) + ( 1 SHL 6 ) + ( 1 SHL 8 );
+  {stored, shrunk, imploded and deflated}
+END;
+
+{******************** main low level function: unzipfile ********************}
+{written and not copyrighted by Christian Ghisler}
+FUNCTION unzipfile ( in_name : pchar;out_name : pchar;offset : longint;
+  hFileAction : word;cm_index : integer ) : integer;
+VAR err : integer;
+    header : plocalheader;
+    buf : ARRAY [ 0..80 ] of char;
+{$ifndef linux}
+    buf0 : ARRAY [ 0..3 ] of char;
+{$endif}
+    timedate : longint;
+    originalcrc : longint;    {crc from zip-header}
+    ziptype, aResult : integer;
+    p, p1 : pchar;
+    isadir : boolean;
+    oldcurdir : string [ 80 ];
+
+BEGIN
+  {$ifdef windows}
+  IF inuse THEN BEGIN
+    {take care of crashed applications!}
+    IF ( lastusedtime <> 0 ) AND
+      ( abs ( gettickcount -lastusedtime ) > 30000 ) THEN BEGIN {1/2 minute timeout!!!}
+      {do not close files or free slide, they were already freed when application crashed!}
+      inuse := FALSE;
+      {memory for huffman trees is lost}
+    END ELSE BEGIN
+      unzipfile := unzip_inuse;
+      exit
+    END;
+  END;{inuse}
+
+  inuse := TRUE;
+  {$endif}
+  getmem ( slide, wsize );
+  fillchar ( slide [ 0 ], wsize, #0 );
+  assign ( infile, in_name );
+  filemode := 0;
+  {$I-}
+  reset ( infile, 1 );
+  {$I+}
+  IF ioresult <> 0 THEN BEGIN
+    freemem ( slide, wsize );
+    unzipfile := unzip_ReadErr;
+    inuse := FALSE;
+    exit
+  END;
+  {$I-}
+  seek ( infile, offset );       {seek to header position}
+  {$I+}
+  IF ioresult <> 0 THEN BEGIN
+    freemem ( slide, wsize );
+    close ( infile );
+    unzipfile := unzip_ZipFileErr;
+    inuse := FALSE;
+    exit
+  END;
+  header := @inbuf;
+  {$I-}
+  blockread ( infile, header^, sizeof ( header^ ) );  {read in local header}
+  {$I+}
+  IF ioresult <> 0 THEN BEGIN
+    freemem ( slide, wsize );
+    close ( infile );
+    unzipfile := unzip_ZipFileErr;
+    inuse := FALSE;
+    exit
+  END;
+
+  IF strlcomp ( header^.signature, 'PK'#3#4, 4 ) <> 0 THEN BEGIN
+    freemem ( slide, wsize );
+    close ( infile );
+    unzipfile := unzip_ZipFileErr;
+    inuse := FALSE;
+    exit
+  END;
+
+  {calculate offset of data}
+  offset := offset + header^.filename_len + header^.extra_field_len + sizeof ( tlocalheader );
+  timedate := header^.file_timedate;
+  IF ( hufttype AND 8 ) = 0 THEN BEGIN  {Size and crc at the beginning}
+    compsize := header^.compress_size;
+    uncompsize := header^.uncompress_size;
+    originalcrc := header^.crc_32;
+  END ELSE BEGIN
+    compsize := maxlongint;           {Don't get a sudden zipeof!}
+    uncompsize := maxlongint;
+    originalcrc := 0
+  END;
+  ziptype := header^.zip_type;     {0=stored, 6=imploded, 8=deflated}
+  IF ( 1 SHL ziptype ) AND GetSupportedMethods = 0 THEN BEGIN  {Not Supported!!!}
+    freemem ( slide, wsize );
+    close ( infile );
+    unzipfile := unzip_NotSupported;
+    inuse := FALSE;
+    exit;
+  END;
+  hufttype := header^.bit_flag;
+  IF ( hufttype AND 1 ) <> 0 THEN BEGIN {encrypted}
+    freemem ( slide, wsize );
+    close ( infile );
+    unzipfile := unzip_Encrypted;
+    inuse := FALSE;
+    exit;
+  END;
+
+  reachedsize := 0;
+  seek ( infile, offset );
+
+  assign ( outfile, out_name );
+  {$I-}
+  rewrite ( outfile, 1 );
+  {$I+}
+  err := ioresult;
+  {create directories not yet in path}
+  isadir := ( out_name [ strlen ( out_name ) -1 ] in ['/','\'] );
+  IF ( err = 3 ) OR isadir THEN BEGIN  {path not found}
+    {$I-}
+    getdir ( 0, oldcurdir );
+    {$I+}
+    err := ioresult;
+    strcopy ( buf, out_name );
+    p1 := strrscan ( buf, DirSep );
+    IF p1 <> NIL THEN inc ( p1 );  {pointer to filename}
+    p := strtok ( buf, DirSep );
+{$ifndef linux}
+    IF ( p <> NIL ) AND ( p [ 1 ] = ':' ) THEN BEGIN
+      strcopy ( buf0, 'c:\' );    {set drive}
+      buf0 [ 0 ] := p [ 0 ];
+      {$ifdef windows}
+      setcurdir ( buf0 );
+      {$else}
+      {$I-}
+      chdir ( buf0 );
+      {$I+}
+      err := ioresult;
+      {$endif}
+      p := strtok ( NIL, '\' );
+    END;
+{$endif}
+    WHILE ( p <> NIL ) AND ( p <> p1 ) DO BEGIN
+      {$ifdef windows}
+       {$ifdef Delphi}
+      {$I-}
+         chdir ( strpas ( p ) );
+      {$I+}
+         err := ioresult;
+       {$else Delphi}
+        setcurdir ( p );
+        err := doserror;
+       {$endif Delphi}
+      {$else Windows}
+      {$I-}
+      chdir ( strpas ( p ) );
+      {$I+}
+      err := ioresult;
+      {$endif}
+      IF err <> 0 THEN BEGIN
+        {$ifdef windows}
+        createdir ( p );
+        err := doserror;
+        {$else}
+        {$I-}
+        mkdir ( strpas ( p ) );
+        {$I+}
+        err := ioresult;
+        {$endif}
+        IF err = 0 THEN
+          {$I-}
+          chdir ( strpas ( p ) );
+          {$I+}
+          err := ioresult;
+      END;
+      IF err = 0 THEN
+        p := strtok ( NIL, DirSep )
+      ELSE
+        p := NIL;
+    END;
+    {$I-}
+    chdir ( oldcurdir );
+    {$I+}
+    err := ioresult;
+    IF isadir THEN BEGIN
+      freemem ( slide, wsize );
+      unzipfile := unzip_Ok;    {A directory -> ok}
+      close ( infile );
+      inuse := FALSE;
+      exit;
+    END;
+    {$I-}
+    rewrite ( outfile, 1 );
+    {$I+}
+    err := ioresult;
+  END;
+
+  IF err <> 0 THEN BEGIN
+    freemem ( slide, wsize );
+    unzipfile := unzip_WriteErr;
+    close ( infile );
+    inuse := FALSE;
+    exit
+  END;
+
+  totalabort := FALSE;
+  zipeof := FALSE;
+
+  {$ifdef windows}
+  dlghandle := hFileAction;
+  dlgnotify := cm_index;
+  messageloop;
+  oldpercent := 0;
+  {$endif}
+
+  crc32val := $FFFFFFFF;
+
+  {Unzip correct type}
+  CASE ziptype of
+    0 : aResult := copystored;
+    1 : aResult := unshrink;
+    6 : aResult := explode;
+    8 : aResult := inflate;
+  ELSE
+    aResult := unzip_NotSupported;
+  END;
+  unzipfile := aResult;
+
+  IF ( aResult = unzip_ok ) AND ( ( hufttype AND 8 ) <> 0 ) THEN BEGIN {CRC at the end}
+    dumpbits ( k AND 7 );
+    needbits ( 16 );
+    originalcrc := b AND $FFFF;
+    dumpbits ( 16 );
+    needbits ( 16 );
+    originalcrc := ( b AND $FFFF ) SHL 16;
+    dumpbits ( 16 );
+  END;
+
+  close ( infile );
+  close ( outfile );
+  crc32val := NOT ( crc32val );  {one's complement}
+  IF aResult <> 0 THEN BEGIN
+    erase ( outfile );
+  END ELSE IF ( originalcrc <> crc32val ) THEN BEGIN
+    unzipfile := unzip_CRCErr;
+    erase ( outfile );
+  END ELSE BEGIN
+    {$ifdef windows}
+    oldpercent := 100;       {100 percent}
+    IF dlghandle <> 0 THEN
+      sendmessage ( dlghandle, wm_command, dlgnotify, longint ( @oldpercent ) );
+    {$endif}
+    filemode := 0;
+    reset ( outfile );
+    setftime ( outfile, timedate ); {set zipped time and date of oufile}
+    close ( outfile );
+  END;
+  freemem ( slide, wsize );
+  inuse := FALSE;
+END;
+{***************************************************************************}
+{***************************************************************************}
+{***************************************************************************}
+{ other functions; zipread.pas }
+CONST mainheader : pchar = 'PK'#5#6;
+      maxbufsize = 64000;  {Can be as low as 500 Bytes; however, }
+                         {this would lead to extensive disk reading!}
+                         {If one entry (including Extra field) is bigger}
+                         {than maxbufsize, you cannot read it :-( }
+
+TYPE
+  pheader = ^theader;
+  pmainheader = ^tmainheader;
+  tmainheader = PACKED RECORD
+    signature : ARRAY [ 0..3 ] of char;  {'PK'#5#6}
+    thisdisk,
+    centralstartdisk,
+    entries_this_disk,
+    entries_central_dir : word;
+    headsize,
+    headstart : longint;
+    comment_len : longint;
+    unknown : word;
+  END;
+  theader = PACKED RECORD
+    signature : ARRAY [ 0..3 ] of char;  {'PK'#1#2}
+    OSversion,      {Operating system version}
+    OSmadeby : byte;  {MSDOS (FAT): 0}
+    extract_ver,
+    bit_flag,
+    zip_type : word;
+    file_timedate : longint;
+    crc_32,
+    compress_size,
+    uncompress_size : longint;
+    filename_len,
+    extra_field_len,
+    file_comment_len,
+    disk_number_start,
+    internal_attr : word;
+    external_attr : ARRAY [ 0..3 ] of byte;
+    offset_local_header : longint;
+  END;
+
+{*********** Fill out tZipRec structure with next entry *************}
+
+FUNCTION filloutRec ( VAR zprec : tZipRec ) : integer;
+VAR p : pchar;
+    incr : longint;
+    header : pheader;
+    offs : word;
+    old : char;
+    f : file;
+    extra, err : nword;
+
+BEGIN
+ WITH zprec DO BEGIN
+  header := pheader ( @buf^ [ localstart ] );
+  IF ( bufsize = maxbufsize ) THEN BEGIN       {Caution: header bigger than 64k!}
+    extra := sizeof ( file );
+    IF ( ( localstart + sizeof ( theader ) ) > bufsize ) OR
+      ( localstart + header^.filename_len + header^.extra_field_len +
+      header^.file_comment_len + sizeof ( theader ) > bufsize )
+      THEN BEGIN     {Read over end of header}
+        move ( buf^ [ bufsize + 1 ], f, extra );   {Restore file}
+        move ( buf^ [ localstart ], buf^ [ 0 ], bufsize -localstart );  {Move end to beginning in buffer}
+        {$I-}
+        blockread ( f, buf^ [ bufsize -localstart ], localstart, err );  {Read in full central dir, up to maxbufsize Bytes}
+        {$I+}
+        IF ( ioresult <> 0 ) OR ( err + localstart < sizeof ( theader ) ) THEN BEGIN
+          filloutrec := unzip_nomoreitems;
+          exit
+        END;
+        move ( f, buf^ [ bufsize + 1 ], extra );  {Save changed file info!}
+        localstart := 0;
+        header := pheader ( @buf^ [ localstart ] );
+      END;
+  END;
+  IF ( localstart + 4 <= bufsize ) AND   {Here is the ONLY correct finish!}
+    ( strlcomp ( header^.signature, mainheader, 4 ) = 0 ) THEN BEGIN  {Main header}
+    filloutrec := unzip_nomoreitems;
+    exit
+  END;
+  IF ( localstart + sizeof ( header ) > bufsize ) OR
+    ( localstart + header^.filename_len + header^.extra_field_len +
+    header^.file_comment_len + sizeof ( theader ) > bufsize ) OR
+    ( strlcomp ( header^.signature, 'PK'#1#2, 4 ) <> 0 ) THEN BEGIN
+    filloutrec := unzip_nomoreitems;
+    exit
+  END;
+  size := header^.uncompress_size;
+  compressSize := header^.compress_size;
+  IF header^.osmadeby = 0 THEN
+    attr := header^.external_attr [ 0 ]
+  ELSE
+    attr := 0;
+  time := header^.file_timedate;
+  headeroffset := header^.offset_local_header; {Other header size}
+  Packmethod := header^.zip_type;
+  offs := localstart + header^.filename_len + sizeof ( header^ );
+  old := buf^ [ offs ];
+  buf^ [ offs ] := #0;  {Repair signature of next block!}
+  strlcopy ( filename, pchar ( @buf^ [ localstart + sizeof ( header^ ) ] ), sizeof ( filename ) -1 );
+  buf^ [ offs ] := old;
+{$ifndef linux}
+  REPEAT           {Convert slash to backslash!}
+    p := strscan ( filename, '/' );
+    IF p <> NIL THEN p [ 0 ] := '\';
+  UNTIL p = NIL;
+{$else}
+  REPEAT           {Convert backslash to slash!}
+    p := strscan ( filename, '\' );
+    IF p <> NIL THEN p [ 0 ] := '/';
+  UNTIL p = NIL;
+{$endif}
+  incr := header^.filename_len + header^.extra_field_len +
+        header^.file_comment_len + sizeof ( header^ );
+  IF incr <= 0 THEN BEGIN
+    filloutrec := unzip_InternalError;
+    exit
+  END;
+  localstart := localstart + incr;
+  filloutrec := unzip_ok;
+ END;
+END;
+
+{**************** Get first entry from ZIP file ********************}
+FUNCTION GetFirstInZip ( zipfilename : pchar;VAR zprec : tZipRec ) : integer;
+VAR bufstart, headerstart, start : longint;
+    err, i : integer;
+    mainh : pmainheader;
+    f : file;
+    extra : word;   {Extra bytes for saving File!}
+
+BEGIN
+ WITH zprec DO BEGIN
+  assign ( f, zipfilename );
+  filemode := 0;  {Others may read or write};
+  {$I-}
+  reset ( f, 1 );
+  {$I+}
+  IF ioresult <> 0 THEN BEGIN
+    GetFirstInZip := unzip_FileError;
+    exit
+  END;
+  size := filesize ( f );
+  IF size = 0 THEN BEGIN
+    GetFirstInZip := unzip_FileError;
+    {$I-}
+    close ( f );
+    {$I+}
+    exit
+  END;
+  bufsize := 4096;     {in 4k-blocks}
+  IF size > bufsize THEN BEGIN
+    bufstart := size -bufsize;
+  END ELSE BEGIN
+    bufstart := 0;
+    bufsize := size;
+  END;
+  getmem ( buf, bufsize + 1 );     {#0 at the end of filemname}
+
+  {Search from back of file to central directory start}
+  start := -1;    {Nothing found}
+  REPEAT
+    {$I-}
+    seek ( f, bufstart );
+    {$I+}
+    IF ioresult <> 0 THEN BEGIN
+      GetFirstInZip := unzip_FileError;
+      freeMem ( buf, bufsize + 1 );
+      buf := NIL;
+      {$I-}
+      close ( f );
+      {$I+}
+      exit
+    END;
+    {$I-}
+    blockread ( f, buf^, bufsize, err );
+    {$I+}
+    IF ( ioresult <> 0 ) OR ( err <> bufsize ) THEN BEGIN
+      GetFirstInZip := unzip_FileError;
+      freeMem ( buf, bufsize + 1 );
+      buf := NIL;
+      {$I-}
+      close ( f );
+      {$I+}
+      exit
+    END;
+
+    IF bufstart = 0 THEN start := maxlongint;{Break}
+
+    FOR i := bufsize -22 DOWNTO 0 DO BEGIN  {Search buffer backwards}
+      IF ( buf^ [ i ] = 'P' ) AND ( buf^ [ i + 1 ] = 'K' ) AND ( buf^ [ i + 2 ] = #5 ) AND ( buf^ [ i + 3 ] = #6 )
+      THEN BEGIN                         {Header found!!!}
+        start := bufstart + i;
+        break;
+      END;
+    END;
+
+    IF start = -1 THEN BEGIN               {Nothing found yet}
+      dec ( bufstart, bufsize -22 );          {Full header in buffer!}
+      IF bufstart < 0 THEN bufstart := 0;
+    END;
+  UNTIL start >= 0;
+  IF ( start = maxlongint ) THEN BEGIN       {Nothing found}
+    GetFirstInZip := unzip_FileError;
+    freeMem ( buf, bufsize + 1 );
+    buf := NIL;
+    {$I-}
+    close ( f );
+    {$I+}
+    exit
+  END;
+  mainh := pmainheader ( @buf^ [ start -bufstart ] );
+  headerstart := mainh^.headstart;
+  localstart := 0;
+  freeMem ( buf, bufsize + 1 );
+  IF ( localstart + sizeof ( theader ) > start ) THEN BEGIN
+    buf := NIL;
+    GetFirstInZip := unzip_InternalError;
+    {$I-}
+    close ( f );
+    {$I+}
+    exit
+  END;
+  bufstart := headerstart;
+  start := start -headerstart + 4; {size for central dir,Including main header signature}
+  IF start >= maxbufsize THEN BEGIN
+    bufsize := maxbufsize; {Max buffer size, limit of around 1000 items!}
+    extra := sizeof ( file ) {Save file information for later reading!}
+  END ELSE BEGIN
+    bufsize := start;
+    extra := 0
+  END;
+  getmem ( buf, bufsize + 1 + extra );
+  {$I-}
+  seek ( f, bufstart );
+  {$I+}
+  IF ioresult <> 0 THEN BEGIN
+    GetFirstInZip := unzip_FileError;
+    freeMem ( buf, bufsize + 1 + extra );
+    buf := NIL;
+    {$I-}
+    close ( f );
+    {$I+}
+    exit
+  END;
+  {$I-}
+  blockread ( f, buf^, bufsize, err );  {Read in full central dir, up to maxbufsize Bytes}
+  {$I+}
+  IF ioresult <> 0 THEN BEGIN
+    GetFirstInZip := unzip_FileError;
+    freeMem ( buf, bufsize + 1 + extra );
+    buf := NIL;
+    {$I-}
+    close ( f );
+    {$I+}
+    exit
+  END;
+  IF extra = 0 THEN
+  {$I-} close ( f ) {$I+}
+    ELSE move ( f, buf^ [ bufsize + 1 ], extra );  {Save file info!}
+  err := filloutRec ( zprec );
+  IF err <> unzip_ok THEN BEGIN
+    CloseZipFile ( zprec );
+    GetFirstInZip := err;
+    exit
+  END;
+  GetFirstInZip := err;
+ END;
+END;
+
+{**************** Get next entry from ZIP file ********************}
+FUNCTION GetNextInZip ( VAR Zprec : tZiprec ) : integer;
+VAR err : integer;
+BEGIN
+ WITH zprec DO BEGIN
+  IF ( buf <> NIL ) THEN BEGIN  {Main Header at the end}
+    err := filloutRec ( zprec );
+    IF err <> unzip_ok THEN BEGIN
+      CloseZipFile ( ZPRec );
+    END;
+    GetNextInZip := err;
+  END ELSE GetNextInZip := unzip_NoMoreItems;
+ END
+END;
+
+{**************** VERY simple test for zip file ********************}
+FUNCTION isZip ( filename : pchar ) : boolean;
+VAR
+    myname : tdirtype;
+    l, err : integer;
+    f : file;
+    buf : ARRAY [ 0..4 ] of char;
+    oldcurdir : string{$ifndef BIT32} [ 80 ]{$endif};
+
+BEGIN
+  filemode := 0;
+  {$I-}
+  getdir ( 0, oldcurdir );
+  {$I+}
+  err := ioresult;
+  isZip := FALSE;
+  IF ( strscan ( filename, '.' ) <> NIL )
+    AND ( strpos ( filename, '.exe' ) = NIL ) THEN BEGIN
+    strcopy ( myname, filename );
+    l := strlen ( myname );
+    IF myname [ l -1 ] = DirSep THEN myname [ l -1 ] := #0;
+    {$I-}
+    chdir ( Strpas ( myname ) );
+    {$I+}
+    IF ioresult <> 0 THEN BEGIN
+      assign ( f, Strpas ( myname ) );
+      filemode := 0;  {Others may read or write};
+      {$I-}
+      reset ( f, 1 );
+      {$I+}
+      IF ioresult = 0 THEN BEGIN
+        {$I-}
+        blockread ( f, buf, 4, err );
+        {$I+}
+        IF ( ioresult = 0 ) THEN BEGIN
+          IF ( err = 4 ) AND ( buf [ 0 ] = 'P' ) AND ( buf [ 1 ] = 'K' )
+            AND ( buf [ 2 ] = #3 ) AND ( buf [ 3 ] = #4 ) THEN isZip := TRUE
+        END;
+        {$I-}
+        close ( f );
+        {$I+}
+        err := ioresult;  {only clears ioresult variable}
+      END;
+    END;
+  END;
+  {$I-}
+  chdir ( oldcurdir );
+  {$I+}
+  err := ioresult;
+END;
+
+{**************** free ZIP buffers ********************}
+PROCEDURE CloseZipFile ( VAR Zprec : tZiprec );  {Only free buffer, file only open in Getfirstinzip}
+VAR
+    f : file;
+    extra : word;
+BEGIN
+ WITH zprec DO BEGIN
+  IF buf <> NIL THEN BEGIN
+    IF ( bufsize = maxbufsize ) THEN BEGIN       {Caution: header bigger than 64k!}
+      extra := sizeof ( file );
+      move ( buf^ [ bufsize + 1 ], f, extra );   {Restore file}
+      {$I-}
+      close ( f );
+      {$I+}
+      IF ioresult <> 0 THEN ;
+    END ELSE extra := 0;
+    freemem ( buf, bufsize + 1 + extra );
+    buf := NIL
+  END;
+ END
+END;
+{***************************************************************************}
+{***************************************************************************}
+{********** routines by the African Chief **********************************}
+{***************************************************************************}
+{***************************************************************************}
+{$ifndef Delphi}
+FUNCTION FileExists ( CONST fname : string ) : boolean; {simple fileexist function}
+VAR
+f : file;
+i : byte;
+BEGIN
+    i := filemode;
+    filemode := 0;
+    assign ( f, fname );
+    {$i-}
+    Reset ( f, 1 );
+    filemode := i;
+    FileExists := ioresult = 0;
+    Close ( f ); IF ioresult <> 0 THEN;
+    {$i+}
+END;
+{$endif Delphi}
+
+PROCEDURE DummyReport ( Retcode : longint;Rec : pReportRec );
+{$ifdef Windows}{$ifdef win32}STDCALL;{$else}EXPORT;{$endif}{$endif}
+{dummy report procedure}
+BEGIN
+END;
+
+FUNCTION DummyQuestion( Rec : pReportRec ) : Boolean;
+{$ifdef Windows}{$ifdef win32}STDCALL;{$else}EXPORT;{$endif}{$endif}
+{dummy question procedure}
+begin
+  DummyQuestion:=true;
+end;
+
+FUNCTION Matches ( s : String;CONST main : string ) : Boolean;
+{rudimentary matching function;
+ accepts only '', '*.*', 'XXX.*' or '*.XXX'
+}
+FUNCTION extensiononly ( CONST s : string ) : string;{return just the extension}
+VAR i : integer;
+BEGIN
+   extensiononly := '';
+   i := pos ( '.', s );
+   IF i = 0 THEN exit;
+   extensiononly := copy ( s, succ ( i ), length ( s ) );
+END;
+
+FUNCTION nameonly ( CONST s : string ) : string;{return just the name}
+VAR i : integer;
+BEGIN
+   nameonly := s;
+   i := pos ( '.', s );
+   IF i = 0 THEN exit;
+   nameonly := copy ( s, 1, pred ( i ) );
+END;
+{!!!!!}
+VAR
+b : boolean;
+i : integer;
+BEGIN
+   Matches := TRUE;
+   IF ( s = '' ) OR ( s = AllFiles ) THEN exit; {'' or '*.*' = all files match}
+   s := upper ( s );
+   b := copy ( s, 1, 2 ) = '*.';  {e.g., *.PAS}
+   IF b THEN BEGIN
+      delete ( s, 1, 2 );
+      Matches := s = extensiononly ( upper ( main ) );
+   END ELSE BEGIN
+      i := length ( s );
+      b := s [ i ] = '*'; {e.g. TEST.*}
+      IF b THEN BEGIN
+         IF s [ pred ( i ) ] = '.' THEN delete ( s, pred ( i ), 2 );
+         i := length ( s );
+         IF s [ i ] in [ '*', '?' ] THEN dec ( i );{e.g. TEST*.*}
+         Matches := Copy ( s, 1, i ) = Copy ( nameonly ( upper ( main ) ), 1, i );
+      END ELSE Matches := s = upper ( main );
+   END;
+END;  { Matches }
+{****************************************************}
+FUNCTION FileUnzip ( SourceZipFile, TargetDirectory, FileSpecs : pChar;
+ Report : UnzipReportProc;Question : UnzipQuestionProc ) : integer;
+VAR
+    rc : integer;
+    r : tziprec;
+    buf,
+    thename,
+    target : ARRAY [ 0..tFSize ] of char;
+    Count : integer;
+    rSize, cSize : longint;
+    s : string [ 255 ];
+
+BEGIN
+{$IFDEF FPC}
+  IF not assigned(Report) THEN
+   Report := @DummyReport;
+  IF not assigned(Question) THEN
+   Question := @DummyQuestion;
+{$ELSE}
+  IF @Report = nil THEN
+   Report := DummyReport;
+  IF @Question = nil THEN
+   Question := DummyQuestion;
+{$ENDIF}
+
+  Count := 0;
+  rSize := 0;
+  cSize := 0;
+  FileUnzip := unzip_MissingParameter;
+  IF ( StrPas ( SourceZipFile ) = '' ) OR ( StrPas ( TargetDirectory ) = '' ) THEN Exit;
+
+  Strcopy ( thename, SourceZipFile );
+  Strcopy ( target, TargetDirectory );
+  IF ( target [ 0 ] <> #0 ) AND ( target [ strlen ( target ) -1 ] <> DirSep )
+  THEN strcat ( target, DirSep );
+  FileUnzip := unzip_NotZipFile;
+  IF NOT iszip ( thename ) THEN exit;
+
+  FillChar ( ZipRec, Sizeof ( ZipRec ), #0 );
+
+  WITH ZipRec DO BEGIN
+       IsaDir := FALSE;
+       strcopy ( FileName, thename );
+       Size := UnZipSize ( SourceZipFile, CompressSize );
+       IF Size = 0 THEN ratio := 0 ELSE
+       Ratio := 100 -Round ( ( CompressSize / Size ) * 100 );
+       Status := unzip_starting;
+       Report ( Status, @ZipRec );
+  END; {start of ZIP file}
+
+  ZipReport := Report;
+
+  rc := getfirstinzip ( thename, r );
+  WHILE ( rc = unzip_ok )
+  DO BEGIN
+   IF ( Matches ( StrPas ( FileSpecs ), Strpas ( R.FileName ) ) )
+   THEN BEGIN
+      Inc ( rSize, r.Size );
+      Inc ( cSize, r.CompressSize );
+
+      strcopy ( buf, target );
+      IF NoRecurseDirs  { no recursion }
+      THEN BEGIN
+          s := StripPath ( Strpas ( r.filename ) ) + #0;
+          Strcat ( buf, @s [ 1 ] );
+      END ELSE strcat ( buf, r.filename );
+
+
+      WITH ZipRec DO BEGIN { report start of file }
+           s := StrPas ( Buf );
+           IsaDir := s [ length ( s ) ] = DirSep;
+           Time := r.Time;
+           Size := r.Size;
+           CompressSize := r.CompressSize;
+           strcopy ( FileName, buf );
+           PackMethod := r.PackMethod;
+           Attr := r.Attr;
+           IF Size = 0 THEN ratio := 0 ELSE
+           Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
+           Status := file_starting;
+           IF ( IsaDir ) AND ( NoRecurseDirs )
+           THEN {} ELSE
+           ZipReport ( Status, @ZipRec );
+      END;  { start of file }
+
+      IF ( FileExists ( StrPas ( buf ) ) )
+      AND ( Question ( @ZipRec ) = FALSE )
+      THEN BEGIN
+         rc := unzip_ok;              { we are okay }
+         WITH ZipRec DO BEGIN
+           Status := file_unzipping;
+           PackMethod := 9;           { skipped }
+           ZipReport ( Size, @ZipRec );  { report uncompressed size }
+         END;
+      END ELSE BEGIN
+          rc := unzipfile ( thename, buf, r.headeroffset, 0,
+          {$ifdef windows}vk_escape{$else}27{$endif} ); {Escape interrupts}
+      END;
+
+      IF rc = unzip_ok
+      THEN BEGIN
+         Inc ( Count );
+         WITH ZipRec DO BEGIN   { report end of file }
+            Status := file_completed;
+            IF ( IsaDir ) AND ( NoRecurseDirs )
+            THEN {} ELSE
+            ZipReport ( Status, @ZipRec );
+         END; { end of file }
+      END ELSE BEGIN
+           ZipRec.Status := file_failure; {error}
+           CASE rc of
+                unzip_CRCErr,
+                unzip_WriteErr,
+                unzip_Encrypted,
+                unzip_NotSupported : ZipReport ( rc, @ZipRec );
+
+                unzip_ReadErr, unzip_Userabort,
+                unzip_FileError, unzip_InternalError,
+                unzip_InUse, unzip_ZipFileErr :
+                BEGIN
+                    ZipRec.Status := unzip_SeriousError;
+                    FileUnzip := unzip_SeriousError;   {Serious error, force abort}
+                    ZipReport ( unzip_SeriousError, @ZipRec );
+                    closezipfile ( r );
+                    ZipReport := NIL;
+                    ZipQuestion := NIL;
+                    exit;
+                END;
+           END; {case rc}
+           Continue;
+           {rc:=getnextinzip(r);}
+        END; {else}
+    END; { if Matches }
+      rc := getnextinzip ( r );
+  END; {while }
+
+  closezipfile ( r );               {Free memory used for central directory info}
+
+  WITH ZipRec DO BEGIN { report end of ZIP file }
+       Time := -1;
+       Attr := -1;
+       PackMethod := 0;
+       Size := rSize;
+       CompressSize := cSize;
+       strcopy ( FileName, thename );
+       IF Size = 0 THEN ratio := 0 ELSE
+       Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
+       Status := unzip_completed;
+       ZipReport ( Status, @ZipRec );
+  END; { end of ZIP file }
+
+  ZipReport := NIL;
+  ZipQuestion := NIL;
+  FileUnzip := Count;
+END; { FileUnzip }
+{***************************************************************************}
+FUNCTION FileUnzipEx ( SourceZipFile, TargetDirectory, FileSpecs : pChar ) : integer;
+BEGIN
+  FileUnzipEx :=
+  FileUnzip ( SourceZipFile, TargetDirectory, FileSpecs, ZipReport, ZipQuestion );
+END; { FileUnzipEx }
+{***************************************************************************}
+FUNCTION Viewzip ( SourceZipFile, FileSpecs : pChar; Report : UnzipReportProc ) : integer;
+VAR
+    rc : integer;
+    r : tziprec;
+    thename : ARRAY [ 0..tFSize ] of char;
+    Count : integer;
+    rSize, cSize : longint;
+
+BEGIN
+  Count := 0;
+  rSize := 0;
+  cSize := 0;
+  Viewzip := unzip_MissingParameter;
+{$IFDEF FPC}
+  IF ( StrPas ( SourceZipFile ) = '' ) or
+     not assigned(Report) THEN
+   exit;
+{$ELSE}
+  IF ( StrPas ( SourceZipFile ) = '' ) OR ( @Report = NIL ) THEN Exit;
+{$ENDIF}
+
+  Strcopy ( thename, SourceZipFile );
+  ViewZip := unzip_NotZipFile;
+  IF NOT iszip ( thename ) THEN exit;
+  FillChar ( ZipRec, Sizeof ( ZipRec ), #0 );
+
+  rc := getfirstinzip ( thename, r );
+  WHILE ( rc = unzip_ok )
+  DO BEGIN
+   IF ( Matches ( StrPas ( FileSpecs ), Strpas ( R.FileName ) ) ) THEN BEGIN
+      Inc ( rSize, r.Size );
+      Inc ( cSize, r.CompressSize );
+      WITH ZipRec DO BEGIN
+           Time := r.Time;
+           Size := r.Size;
+           CompressSize := r.CompressSize;
+           strcopy ( FileName, r.Filename );
+           PackMethod := r.PackMethod;
+           Attr := r.Attr;
+           IF Size = 0 THEN ratio := 0 ELSE
+           Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
+      END;
+      Inc ( Count );
+      Report ( rc, @ZipRec );
+   END; {matches}
+      rc := getnextinzip ( r );
+  END; {while }
+  closezipfile ( r );
+
+  WITH ZipRec DO BEGIN
+       Time := -1;
+       Attr := -1;
+       PackMethod := 0;
+       Size := rSize;
+       CompressSize := cSize;
+       strcopy ( FileName, thename );
+       IF Size = 0 THEN ratio := 0 ELSE
+       Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
+  END;
+  Report ( Count, @ZipRec );
+  ViewZip := Count;
+END; { ViewZip }
+{***************************************************************************}
+FUNCTION UnZipSize ( SourceZipFile : pChar;VAR Compressed : Longint ) : longint;
+VAR
+    rc : integer;
+    r : tziprec;
+    thename : ARRAY [ 0..tFSize ] of char;
+    Count : longint;
+    f : file;
+
+BEGIN
+  Compressed := 0;
+  UnZipSize := 0;
+  IF ( StrPas ( SourceZipFile ) = '' ) THEN Exit;
+  System.Assign ( f, StrPas ( SourceZipFile ) );
+  count := filemode;
+  filemode := 0;
+  {$i-}
+  Reset ( f, 1 );
+  filemode := count;
+  IF ioresult <> 0 THEN exit;
+  Count := filesize ( f );
+  close ( f );
+  UnZipSize := count;
+  Compressed := count;
+  Strcopy ( thename, SourceZipFile );
+  IF NOT iszip ( thename ) THEN exit;
+  Count := 0;
+  Compressed := 0;
+  rc := getfirstinzip ( thename, r );
+  WHILE ( rc = unzip_ok )
+  DO BEGIN
+      Inc ( Count, r.Size );
+      Inc ( Compressed, r.CompressSize );
+      rc := getnextinzip ( r );
+  END; {while }
+  closezipfile ( r );
+  UnZipSize := Count;
+END; { UnZipSize }
+{***************************************************************************}
+FUNCTION  SetUnZipReportProc ( aProc : UnzipReportProc ) : Pointer;
+BEGIN
+{$IFDEF FPC}
+   SetUnZipReportProc := ZipReport; {save and return original}
+{$ELSE}
+   SetUnZipReportProc := @ZipReport; {save and return original}
+{$ENDIF}
+   ZipReport  := aProc;
+END; { SetUnZipReportProc }
+{***************************************************************************}
+FUNCTION  SetUnZipQuestionProc ( aProc : UnzipQuestionProc ) : Pointer;
+BEGIN
+{$IFDEF FPC}
+  SetUnZipQuestionProc := ZipQuestion;  {save and return original}
+{$ELSE}
+  SetUnZipQuestionProc := @ZipQuestion;  {save and return original}
+{$ENDIF}
+  ZipQuestion := aProc;
+END; { SetUnZipQuestionProc }
+{***************************************************************************}
+FUNCTION SetNoRecurseDirs ( DontRecurse : Boolean ) : Boolean;
+BEGIN
+   SetNoRecurseDirs := NoRecurseDirs;
+   NoRecurseDirs := DontRecurse;
+END; { SetNoRecurseDirs }
+{***************************************************************************}
+{***************************************************************************}
+PROCEDURE ChfUnzip_Init;
+BEGIN
+   slide := NIL;       {unused}
+  {$ifdef windows}
+   inuse := FALSE;    {Not yet in use!}
+   lastusedtime := 0; {Not yet used}
+  {$endif}
+  if inuse then; { to remove warning }
+  SetUnZipReportProc ( NIL );
+  SetUnZipQuestionProc ( NIL );
+  SetNoRecurseDirs ( FALSE );
+END;
+{***************************************************************************}
+{***************************************************************************}
+{***************************************************************************}
+BEGIN
+   ChfUnzip_Init;
+END.
+{
+  $Log$
+  Revision 1.1  2000-03-02 12:16:56  michael
+  + Initial implementation
+
+  Revision 1.5  2000/02/24 17:47:47  peter
+    * last fixes for 0.99.14a release
+
+  Revision 1.4  2000/01/26 21:49:33  peter
+    * install.pas compilable by FPC again
+    * removed some notes from unzip.pas
+    * support installer creation under linux (install has name conflict)
+
+  Revision 1.3  1999/06/10 15:00:16  peter
+    * fixed to compile for not os2
+    * update install.dat
+
+  Revision 1.2  1999/06/10 07:28:28  hajny
+    * compilable with TP again
+
+  Revision 1.1  1999/02/19 16:45:26  peter
+    * moved to fpinst/ directory
+    + makefile
+
+}
+

+ 187 - 0
packages/zip/unzipdll.pas

@@ -0,0 +1,187 @@
+{
+  $Id$
+}
+unit UnzipDLL;
+
+{$Cdecl+,AlignRec-,OrgName+}
+
+interface
+
+const
+{$IFDEF OS2}
+ AllFiles: string [1] = '*';
+{$ELSE}
+ AllFiles: string [3] = '*.*';
+{$ENDIF}
+
+type
+ TArgV = array [0..1024] of PChar;
+ PArgV = ^TArgV;
+ TCharArray = array [1..1024*1024] of char;
+ PCharArray = ^TCharArray;
+
+function FileUnzipEx (SourceZipFile, TargetDirectory,
+                                                    FileSpecs: PChar): integer;
+
+implementation
+
+uses
+{$IFDEF OS2}
+ {$IFDEF FPC}
+     DosCalls,
+ {$ELSE FPC}
+  {$IFDEF VirtualPascal}
+     OS2Base,
+  {$ELSE VirtualPascal}
+     BseDos,
+  {$ENDIF VirtualPascal}
+ {$ENDIF FPC}
+{$ENDIF OS2}
+ Dos;
+
+type
+ UzpMainFunc = function (ArgC: longint; var ArgV: TArgV): longint;
+
+const
+{$IFDEF OS2}
+ LibPath = 'LIBPATH';
+{$ELSE}
+ LibPath = 'PATH';
+{$ENDIF}
+ UzpMainOrd = 4;
+ DLLName: string [8] = 'UNZIP32'#0;
+ UzpMain: UzpMainFunc = nil;
+ QuiteOpt: array [1..4] of char = '-qq'#0;
+ OverOpt: array [1..3] of char = '-o'#0;
+ CaseInsOpt: array [1..3] of char = '-C'#0;
+ ExDirOpt: array [1..3] of char = '-d'#0;
+ OptCount = 4;
+
+var
+ DLLHandle: longint;
+ OldExit: pointer;
+
+function DLLInit: boolean;
+var
+ ErrPath: array [0..259] of char;
+ DLLPath: PathStr;
+ Dir: DirStr;
+ Name: NameStr;
+ Ext: ExtStr;
+begin
+ DLLInit := false;
+ FSplit (FExpand (ParamStr (0)), Dir, Name, Ext);
+ DLLPath := Dir + DLLName;
+ Insert ('.DLL', DLLPath, byte (DLLPath [0]));
+ if (DosLoadModule (@ErrPath, SizeOf (ErrPath), @DLLPath [1], DLLHandle) <> 0)
+ and (DosLoadModule (@ErrPath, SizeOf (ErrPath), @DLLName [1], DLLHandle) <> 0)
+                                                                           then
+ begin
+  if ErrPath [0] <> #0 then
+  begin
+   Write (#13#10'Error while loading module ');
+   WriteLn (PChar (@ErrPath));
+  end;
+ end else DLLInit := DosQueryProcAddr (DLLHandle, UzpMainOrd, nil, @UzpMain) = 0;
+end;
+
+procedure NewExit;
+begin
+ ExitProc := OldExit;
+ DosFreeModule (DLLHandle);
+end;
+
+function FileUnzipEx;
+var
+ I, FCount, ArgC: longint;
+ ArgV: TArgV;
+ P: PChar;
+ StrLen: array [Succ (OptCount)..1024] of longint;
+begin
+ ArgV [0] := @DLLName;
+ ArgV [1] := @QuiteOpt;
+ ArgV [2] := @OverOpt;
+ ArgV [3] := @CaseInsOpt;
+ ArgV [4] := SourceZipFile;
+ FCount := 0;
+ if FileSpecs^ <> #0 then
+ begin
+  P := FileSpecs;
+  I := 0;
+  repeat
+   case FileSpecs^ of
+    '"': begin
+          Inc (FileSpecs);
+          repeat Inc (I) until (FileSpecs^ = '"') or (FileSpecs^ = #0);
+          Inc (FileSpecs);
+          Inc (I);
+         end;
+    '''':  begin
+            Inc (FileSpecs);
+            repeat Inc (I) until (FileSpecs^ = '''') or (FileSpecs^ = #0);
+            Inc (FileSpecs);
+            Inc (I);
+           end;
+    #0, ' ', #9: begin
+                  Inc (I);
+                  Inc (FCount);
+                  GetMem (ArgV [OptCount + FCount], I);
+                  Move (P^, ArgV [OptCount + FCount]^, Pred (I));
+                  PCharArray (ArgV [OptCount + FCount])^ [I] := #0;
+                  StrLen [OptCount + FCount] := I;
+                  while (FileSpecs^ = #9) or (FileSpecs^ = ' ') do Inc (FileSpecs);
+                  P := FileSpecs;
+                  I := 0;
+                 end;
+    else
+    begin
+     Inc (I);
+     Inc (FileSpecs);
+    end;
+   end;
+  until (FileSpecs^ = #0) and (I = 0);
+ end else
+ begin
+  FCount := 1;
+  StrLen [OptCount + FCount] := Succ (byte (AllFiles [0]));
+  GetMem (ArgV [OptCount + FCount], StrLen [OptCount + FCount]);
+  Move (AllFiles [1], ArgV [OptCount + FCount]^, StrLen [OptCount + FCount]);
+ end;
+ ArgC := Succ (FCount + OptCount);
+ ArgV [ArgC] := @ExDirOpt;
+ Inc (ArgC);
+ ArgV [ArgC] := TargetDirectory;
+ Inc (ArgC);
+ ArgV [ArgC] := @ExDirOpt [3]; (* contains #0 *)
+ if UzpMain (ArgC, ArgV) <> 0 then FileUnzipEx := 0 else FileUnzipEx := FCount;
+ for I := 1 to FCount do FreeMem (ArgV [I + OptCount], StrLen [I + OptCount]);
+end;
+
+begin
+ if DLLInit then
+ begin
+  OldExit := ExitProc;
+  ExitProc := @NewExit;
+ end else
+ begin
+  WriteLn (#13#10'Dynamic library UNZIP32.DLL from InfoZip is needed to install.');
+  WriteLn ('This library could not be found on your system, however.');
+  WriteLn ('Please, download the library, either from the location where you found');
+  WriteLn ('this installer, or from any FTP archive carrying InfoZip programs.');
+  WriteLn ('If you have this DLL on your disk, please, check your configuration (' + LIBPATH + ').');
+  Halt (255);
+ end;
+end.
+{
+  $Log$
+  Revision 1.1  2000-03-02 12:16:57  michael
+  + Initial implementation
+
+  Revision 1.2  1999/06/10 07:28:29  hajny
+    * compilable with TP again
+
+  Revision 1.1  1999/02/19 16:45:26  peter
+    * moved to fpinst/ directory
+    + makefile
+
+}

+ 215 - 0
packages/zip/ziptypes.pas

@@ -0,0 +1,215 @@
+{
+  $Id$
+}
+UNIT ziptypes;
+{
+Type definitions for UNZIP
+  * original version by Christian Ghisler
+  * extended
+    and
+    amended for Win32 by Dr Abimbola Olowofoyeku (The African Chief)
+ Homepage: http://ourworld.compuserve.com/homepages/African_Chief
+  * extended by Tomas Hajny, [email protected] to support other 32-bit
+    compilers/platforms (OS/2, GO32, ...); search for (* TH ... *)
+}
+
+{$IFDEF FPC}
+ {$DEFINE BIT32}
+{$ENDIF}
+
+{$IFDEF OS2}
+ {$DEFINE BIT32}
+{$ENDIF}
+
+{$IFDEF WIN32}
+ {$DEFINE BIT32}
+{$ENDIF}
+
+
+INTERFACE
+
+{$ifdef BIT32}
+TYPE
+  nWord   = longint;
+  Integer = Longint; {Default Integer is 16 bit!}
+{$else BIT32}
+TYPE
+  nWord = Word;
+{$endif BIT32}
+
+CONST
+  tBufSize = {$ifdef BIT32}256{$else}63{$endif} * 1024;   {buffer size}
+  tFSize   = {$ifdef BIT32}259{$else}79{$endif};          {filename length}
+
+{$IFDEF OS2}
+  AllFiles = '*';
+{$ELSE}
+  {$ifdef linux}
+  AllFiles = '*';
+  {$else}
+  AllFiles = '*.*';
+  {$endif}
+{$ENDIF}
+
+{$ifdef linux}
+  DirSep='/';
+{$else}
+  DirSep='\';
+{$endif}
+
+TYPE
+  { Record for UNZIP }
+  buftype  = ARRAY [ 0..tBufSize ] of char;
+  TDirtype = ARRAY [ 0..tFSize ] of char;
+  TZipRec = PACKED RECORD
+       buf : ^buftype;        {please}         {buffer containing central dir}
+       bufsize,               {do not}         {size of buffer}
+       localstart : word;     {change these!}  {start pos in buffer}
+       Time,
+       Size,
+       CompressSize,
+       headeroffset : Longint;
+       FileName : tdirtype;
+       PackMethod : word;
+       Attr : Byte;
+  END; { TZipRec }
+
+  { record for callback progress Reports, etc. }
+  pReportRec = ^TReportRec;     {passed to callback functions}
+  TReportRec = PACKED RECORD
+       FileName : tdirtype;   {name of individual file}
+       Time,                  {date and time stamp of individual file}
+       Size,                  {uncompressed and time stamp of individual file}
+       CompressSize : Longint;{compressed and time stamp of individual file}
+       Attr : integer;        {file attribute of individual file}
+       PackMethod : Word;     {compression method of individual file}
+       Ratio : byte;          {compression ratio of individual file}
+       Status : longint;      {callback status code to show where we are}
+       IsaDir : Boolean;      {is this file a directory?}
+  END; {TReportRec}
+
+{ callback status codes }
+CONST
+  file_starting    = -1000;  {beginning the unzip process; file}
+  file_unzipping   = -1001;  {continuing the unzip process; file}
+  file_completed   = -1002;  {completed the unzip process; file}
+  file_Failure     = -1003;  {failure in unzipping file}
+  unzip_starting   = -1004;  {starting with a new ZIP file}
+  unzip_completed  = -1005;  {completed this ZIP file}
+
+
+{ procedural types for callbacks }
+TYPE
+  UnzipReportProc  = PROCEDURE ( Retcode : longint;Rec : pReportRec );{$ifdef Delphi32}STDCALL;{$endif}
+{ procedural type for "Report" callback: the callback function
+  (if any) is called several times during the unzip process
+
+  Error codes are sent to the callback in "Retcode". Other
+  details are sent in the record pointed to by "Rec".
+  * Note particularly Rec^.Status - this contains information about
+  the current status or stage of the unzip process. It can have
+  any of the following values;
+  (archive status)
+    unzip_starting   = starting with a new ZIP archive (rec^.filename)
+    unzip_completed  = finished with the ZIP archive (rec^.filename)
+
+  (file status)
+    file_starting    = starting to unzip (extract) a file (from archive)
+    file_unzipping   = continuing to unzip a file (from archive)
+        (when this status value is reported, the actual number of
+         bytes written to the file are reported in "Retcode"; this is
+         valuable for updating any progress bar)
+
+    file_completed   = finshed  unzip a file (from archive)
+    file_Failure     = could not extract the file (from archive)
+}
+
+UnzipQuestionProc = FUNCTION ( Rec : pReportRec ) : Boolean;
+{$ifdef Delphi32}STDCALL;{$endif}
+{ procedural type for "Question" callback:if a file already
+  exists, the callback (if any) will be called to ask whether
+  the file should be overwritten by the one in the ZIP file;
+
+  the details of the file in the ZIP archive are supplied in the
+  record pointed to by "Rec"
+
+ in your callback function, you should;
+   return TRUE  if you want the existing file to be overwritten
+   return FALSE is you want the existing file to be skipped
+}
+
+
+{Error codes returned by the main unzip functions}
+CONST
+  unzip_Ok             =  0;
+  unzip_CRCErr         = -1;
+  unzip_WriteErr       = -2;
+  unzip_ReadErr        = -3;
+  unzip_ZipFileErr     = -4;
+  unzip_UserAbort      = -5;
+  unzip_NotSupported   = -6;
+  unzip_Encrypted      = -7;
+  unzip_InUse          = -8;
+  unzip_InternalError  = -9;    {Error in zip format}
+  unzip_NoMoreItems    = -10;
+  unzip_FileError      = -11;   {Error Accessing file}
+  unzip_NotZipfile     = -12;   {not a zip file}
+  unzip_SeriousError   = -100;  {serious error}
+  unzip_MissingParameter = -500; {missing parameter}
+
+
+{ the various unzip methods }
+CONST
+Unzipmethods : ARRAY [ 0..9 ] of pchar =
+  ( 'stored', 'shrunk', 'reduced 1', 'reduced 2', 'reduced 3',
+   'reduced 4', 'imploded', 'tokenized', 'deflated', 'skipped' );
+
+{ unzip actions being undertaken }
+CONST
+UnzipActions : ARRAY [ 0..9 ] of pchar =
+  ( 'copying', 'unshrinking', 'unreducing 1', 'unreducing 2', 'unreducing 3',
+   'unreducing 4', 'exploding', 'un-tokenizing', 'inflating', 'skipping' );
+
+{ rudimentary "uppercase" function }
+FUNCTION Upper ( s : String ) : String;
+
+{ remove path and return filename only }
+FUNCTION StripPath ( CONST s : String ) : String;
+
+IMPLEMENTATION
+
+FUNCTION Upper ( s : String ) : String;
+VAR i : integer;
+BEGIN
+   FOR i := 1 TO length ( s ) DO s [ i ] := Upcase ( s [ i ] );
+   Upper := s;
+END;
+
+FUNCTION StripPath ( CONST s : String ) : String;
+VAR
+i, j : Word;
+BEGIN
+   StripPath := s;
+   j := length ( s );
+   FOR i := j DOWNTO 1 DO BEGIN
+       IF s [ i ] in [ '\', ':', '/' ] THEN BEGIN
+          StripPath := Copy ( s, succ ( i ), j -i );
+          exit;
+       END;
+   END;
+END;
+
+END.
+{
+  $Log$
+  Revision 1.1  2000-03-02 12:16:57  michael
+  + Initial implementation
+
+  Revision 1.2  1999/06/10 07:28:30  hajny
+    * compilable with TP again
+
+  Revision 1.1  1999/02/19 16:45:26  peter
+    * moved to fpinst/ directory
+    + makefile
+
+}