summaryrefslogtreecommitdiff
path: root/human68k
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 19:30:57 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 19:30:57 +0100
commit04664087ad66f5614f82a2cfba3ae4eda15e792b (patch)
tree332090b15fd2db1b93abf40dccf06211d9aba297 /human68k
downloadzip-04664087ad66f5614f82a2cfba3ae4eda15e792b.tar.gz
Tarball conversion
Diffstat (limited to 'human68k')
-rw-r--r--human68k/Makefile95
-rw-r--r--human68k/Makefile.gcc78
-rw-r--r--human68k/crc_68.s144
-rw-r--r--human68k/deflate.s1076
-rw-r--r--human68k/human68k.c371
-rw-r--r--human68k/match.s163
-rw-r--r--human68k/osdep.h28
-rw-r--r--human68k/zipup.h16
8 files changed, 1971 insertions, 0 deletions
diff --git a/human68k/Makefile b/human68k/Makefile
new file mode 100644
index 0000000..be1a8b7
--- /dev/null
+++ b/human68k/Makefile
@@ -0,0 +1,95 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for human68k
+# Written by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+#
+# 1999/09/23: Modified by Shimazaki Ryo.
+
+ifeq "$(TARGET)" "X68030"
+COPT = -m68020-40
+AOPT = -m68020 -sCPU020
+LDFLAGS = -L/usr/local/lib/lib060
+endif
+
+VPATH = human68k
+
+CC = gcc2
+CFLAGS = $(COPT) -I. -Wall -O2 -fomit-frame-pointer -fstrength-reduce \
+ -DASM_CRC -D__DOS_INLINE__
+#LDFLAGS = -Wl,-x
+LIBS = -lhmem -lttyi -lsignal
+
+AS = g2as
+ASFLAGS = $(AOPT) -1 -c4 -y -w2
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o globals.o crypt.o ttyio.o \
+ crc32.o human68k.o crc_68.o
+OBJI = deflate.o trees.o
+OBJA =
+OBJU = zipfile_.o fileio_.o util_.o globals.o human68k_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h human68k/osdep.h
+
+all: zips
+
+.SUFFIXES: _.o .o .c
+.c_.o:
+ $(CC) $(CFLAGS) -DUTIL -c $< -o $@
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $@
+
+ZIPS = zip.x zipnote.x zipsplit.x zipcloak.x
+
+zips: $(ZIPS)
+
+zip.x: $(OBJZ) $(OBJI) $(OBJA)
+ $(CC) $(LDFLAGS) -o $@ $(OBJZ) $(OBJI) $(OBJA) $(LIBS)
+zipnote.x: $(OBJN)
+ $(CC) $(LDFLAGS) -o $@ $(OBJN) $(LIBS)
+zipcloak.x: $(OBJC)
+ $(CC) $(LDFLAGS) -o $@ $(OBJC) $(LIBS)
+zipsplit.x: $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+
+human68k.o: human68k/human68k.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+human68k_.o: human68k/human68k.c
+ $(CC) $(CFLAGS) -c -o $@ $< -DUTIL
+
+#match.o: human68k/match.s
+# $(AS) $(ASFLAGS) -o $@ $<
+
+deflate.o: human68k/deflate.s
+ $(AS) $(ASFLAGS) -o $@ $<
+
+crc_68.o: human68k/crc_68.s
+ $(AS) $(ASFLAGS) -o $@ $<
+
+
+clean:
+ rm -f *.o $(ZIPS)
+
+zip.bfd: $(ZIPS)
+ rm -f $@
+ for file in $(ZIPS); do \
+ bdif -A -R uploaded/$$file $$file $@; \
+ done
+
+# rules for zip, zipnote, zipcloak, zipsplit.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: human68k/zipup.h
+
+# EOF
diff --git a/human68k/Makefile.gcc b/human68k/Makefile.gcc
new file mode 100644
index 0000000..edf2989
--- /dev/null
+++ b/human68k/Makefile.gcc
@@ -0,0 +1,78 @@
+# Makefile for Zip, ZipCloak, ZipNote and ZipSplit for human68k
+# Written by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+
+VPATH = human68k
+
+CC = gcc
+AS = as
+
+# if you are using mc68030 (or higher) based X68000,
+# uncomment following defines
+#CC = gcc -DUNALIGNED_OK
+#AS = as -s UNALIGNED_OK
+
+CFLAGS = -Wall -O -fomit-frame-pointer -fstrength-reduce -DASMV
+LDFLAGS = -s
+LIBS = -lsignal -lmb -ldos
+
+# object file lists
+OBJZ = zip.o zipfile.o zipup.o fileio.o util.o crc32.o globals.o \
+ crypt.o ttyio.o
+
+OBJI = deflate.o trees.o
+OBJA = match.o human68k.o
+OBJU = zipfile_.o fileio_.o util_.o globals.o human68_.o
+OBJN = zipnote.o $(OBJU)
+OBJC = zipcloak.o $(OBJU) crc32_.o crypt_.o ttyio.o
+OBJS = zipsplit.o $(OBJU)
+
+ZIP_H = zip.h ziperr.h tailor.h human68k/osdep.h
+
+all: zips
+
+.SUFFIXES: _.o .o .c
+.c_.o:
+ $(CC) $(CFLAGS) -DUTIL -c $< -o $@
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $@
+
+ZIPS = zip.x zipnote.x zipsplit.x zipcloak.x
+
+zips: $(ZIPS)
+
+zip.x: $(OBJZ) $(OBJI) $(OBJA)
+ $(CC) -o zip.x $(LDFLAGS) $(OBJZ) $(OBJI) $(OBJA) $(LIBS)
+zipnote.x: $(OBJN)
+ $(CC) -o zipnote.x $(LDFLAGS) $(OBJN) $(LIBS)
+zipcloak.x: $(OBJC)
+ $(CC) -o zipcloak.x $(LDFLAGS) $(OBJC) $(LIBS)
+zipsplit.x: $(OBJS)
+ $(CC) -o zipsplit.x $(LDFLAGS) $(OBJS) $(LIBS)
+
+match.o: human68k/match.s
+ $(AS) -o $@ $<
+
+human68_.o: human68k/human68k.c
+ $(CC) $(CFLAGS) -DUTIL -c -o $@ $<
+
+clean:
+ rm -f *.o $(ZIPS)
+
+zip.bfd: $(ZIPS)
+ rm -f $@
+ for file in $(ZIPS); do \
+ bdif -A -R uploaded/$$file $$file $@; \
+ done
+
+# rules for zip, zipnote, zipcloak, zipsplit.
+$(OBJZ): $(ZIP_H)
+$(OBJI): $(ZIP_H)
+$(OBJN): $(ZIP_H)
+$(OBJS): $(ZIP_H)
+$(OBJC): $(ZIP_H)
+zip.o crc32.o crypt.o fileio.o zipfile.o zipup.o: crc32.h
+zipcloak.o crc32_.o crypt_.o fileio_.o zipfile_.o: crc32.h
+zip.o zipup.o crypt.o ttyio.o zipcloak.o crypt_.o: crypt.h
+zip.o zipup.o zipnote.o zipcloak.o zipsplit.o: revision.h
+zip.o crypt.o ttyio.o zipcloak.o crypt_.o: ttyio.h
+zipup.o: human68k/zipup.h
diff --git a/human68k/crc_68.s b/human68k/crc_68.s
new file mode 100644
index 0000000..9ce78d8
--- /dev/null
+++ b/human68k/crc_68.s
@@ -0,0 +1,144 @@
+;===========================================================================
+; Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 2000-Apr-09 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, all these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+;===========================================================================
+; crc_68 created by Paul Kienitz, last modified 04 Jan 96.
+;
+; Return an updated 32 bit CRC value, given the old value and a block of data.
+; The CRC table used to compute the value is gotten by calling get_crc_table().
+; This replaces the older updcrc() function used in Zip and fUnZip. The
+; prototype of the function is:
+;
+; ulg crc32(ulg crcval, uch *text, extent textlen);
+;
+; On the Amiga, type extent is always unsigned long, not unsigned int, because
+; int can be short or long at whim, but size_t is long.
+;
+; If using this source on a non-Amiga 680x0 system, note that we treat
+; a0/a1/d0/d1 as scratch registers not preserved across function calls.
+; We do not bother to support registerized arguments for crc32() -- the
+; textlen parm is usually large enough so that savings outside the loop
+; are pointless.
+;
+; Define NO_UNROLLED_LOOPS to use a simple short loop which might be more
+; efficient on certain machines with dinky instruction caches ('020?), or for
+; processing short strings. If loops are unrolled, the textlen parm must be
+; less than 512K; if not unrolled, it must be less than 64K.
+;
+; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
+
+ xdef _crc32 ; (ulg val, uch *buf, extent bufsize)
+
+DO_CRC0 MACRO
+ moveq #0,ltemp
+ move.b (textbuf)+,ltemp
+ eor.b crcval,ltemp
+ lsl.w #2,ltemp
+ move.l (crc_table,ltemp.w),ltemp
+ lsr.l #8,crcval
+ eor.l ltemp,crcval
+ ENDM
+
+
+DO_CRC2 MACRO
+ move.b (textbuf)+,btemp
+ eor.b crcval,btemp
+ lsr.l #8,crcval
+ move.l (crc_table,btemp.w*4),ltemp
+ eor.l ltemp,crcval
+ ENDM
+
+crc_table reg a0 array of unsigned long
+crcval reg d0 unsigned long initial value
+textbuf reg a1 array of unsigned char
+textbufsize reg d1 unsigned long (count of bytes in textbuf)
+btemp reg d2
+ltemp reg d3
+
+
+ xref _get_crc_table ; ulg *get_crc_table(void)
+
+
+
+ quad
+_crc32:
+ move.l 8(sp),d0
+ bne.s valid
+;;;;; moveq #0,d0
+ rts
+valid: movem.l btemp/ltemp,-(sp)
+ jsr _get_crc_table
+ movea.l d0,crc_table
+ move.l 12(sp),crcval
+ move.l 16(sp),textbuf
+ move.l 20(sp),textbufsize
+ not.l crcval
+
+ ifdef NO_UNROLLED_LOOPS
+
+ if CPU==68000
+ bra.s decr
+loop: DO_CRC0
+decr: dbra textbufsize,loop
+ bra.s done
+
+ else
+twenty: moveq #0,btemp
+ bra.s decr2
+loop2: DO_CRC2
+decr2: dbra textbufsize,loop2
+ endif
+
+ ELSE ; !NO_UNROLLED_LOOPS
+
+ if CPU==68000
+ moveq #7,btemp
+ and textbufsize,btemp
+ lsr.l #3,textbufsize
+ bra decr8
+loop8: DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+ DO_CRC0
+decr8: dbra textbufsize,loop8
+ bra.s decr1
+loop1: DO_CRC0
+decr1: dbra btemp,loop1
+ bra done
+
+ else
+twenty: moveq #0,btemp
+ move.l textbufsize,-(sp)
+ lsr.l #3,textbufsize
+ bra decr82
+ quad
+loop82: DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+ DO_CRC2
+decr82: dbra textbufsize,loop82
+ moveq #7,textbufsize
+ and.l (sp)+,textbufsize
+ bra.s decr12
+loop12: DO_CRC2
+decr12: dbra textbufsize,loop12
+ endif
+
+ ENDC ; ?NO_UNROLLED_LOOPS
+
+done: movem.l (sp)+,btemp/ltemp
+ not.l crcval
+;;;;; move.l crcval,d0 ; crcval already is d0
+ rts
diff --git a/human68k/deflate.s b/human68k/deflate.s
new file mode 100644
index 0000000..246962c
--- /dev/null
+++ b/human68k/deflate.s
@@ -0,0 +1,1076 @@
+;===========================================================================
+; Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+;
+; See the accompanying file LICENSE, version 1999-Oct-05 or later
+; (the contents of which are also included in zip.h) for terms of use.
+; If, for some reason, both of these files are missing, the Info-ZIP license
+; also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+;===========================================================================
+; This is a 680x0 assembly language translation of the Info-ZIP source file
+; deflate.c, by Paul Kienitz. No rights reserved. The function longest_match
+; is based in part on match.a by Carsten Steger, which in turn is partly based
+; on match.s for 386 by Jean-loup Gailly and Kai Uwe Rommel. Mostly, however,
+; this material is based on deflate.c, by Gailly, Rommel, and Igor Mandrichenko.
+; This code is not commented very much; see deflate.c for comments that explain
+; what the functions are doing.
+;
+; The symbols that can be used to select different versions are as follows:
+;
+; CPU020 if defined, use 68020 instructions always.
+;
+; CPUTEST if defined, check at runtime for CPU type. Another symbol
+; specifying the platform-specific test must be used with this.
+; If neither of these is defined, use 68000 instructions only.
+; Runtime test is nonportable; it is different for each OS.
+;
+; AMIGA use Amiga-specific test for 68020, if CPUTEST defined. Also
+; tells it that registers d0/a0/d1/a1 are not preserved by
+; function calls. At present, if AMIGA is not defined, it
+; causes functions to preserve all registers. ALL OF THIS CODE
+; CURRENTLY ASSUMES THAT REGISTERS D2-D7/A2-A6 WILL BE PRESERVED
+; BY ANY FUNCTIONS THAT IT CALLS.
+;
+; DYN_ALLOC should be defined here if it is defined for C source; tells us
+; that big arrays are allocated instead of static.
+;
+; WSIZE must be defined as the same number used for WSIZE in the C
+; source, and must be a power of two <= 32768. As elsewhere,
+; the default value is 32768.
+;
+; INT16 define this if ints are 16 bits; otherwise 32 bit ints assumed.
+;
+; SMALL_MEM define this if it is defined in the C source; otherwise it uses
+; the MEDIUM_MEM model. BIG_MEM and MMAP are *not* supported.
+; The FULL_SEARCH option in deflate.c is also not supported.
+;
+; DEBUG activates some tracing output, as in the C source.
+;
+; QUADLONG this selects a different version of the innermost longest_match
+; loop code for 68020 operations, comparing bytes four at a time
+; instead of two at a time. It seems to be a tiny bit faster on
+; average, but it's slower often enough that one can't generalize.
+;
+; This code currently assumes that function results are returned in D0 for
+; all platforms. It assumes that args to functions are pushed onto the stack,
+; last arg first. It also currently assumes that all C symbols have an
+; underscore prepended when referenced from assembly.
+;
+; 1999/09/23: for Human68k: Modified by Shimazaki Ryo.
+
+ IFNDEF CPU020
+ IFNDEF CPUTEST
+CPU000 equ 1
+ ENDC
+ ENDC
+
+; Use these macros for accessing variables of type int:
+ IFDEF INT16
+MOVINT MACRO _1,_2
+ move.w _1,_2
+ ENDM
+CLRINT MACRO _1
+ clr.w _1
+ ENDM
+INTSIZE equ 2
+ ELSE ; !INT16
+MOVINT MACRO _1,_2
+ move.l _1,_2
+ ENDM
+CLRINT MACRO _1
+ clr.l _1
+ ENDM
+INTSIZE equ 4
+ ENDC
+
+ IFDEF DYN_ALLOC
+BASEPTR MACRO _1,_2
+ move.l _1,_2
+ ENDM
+ ELSE
+BASEPTR MACRO _1,_2
+ lea _1,_2
+ ENDM
+ ENDC
+
+; constants we use, many of them adjustable:
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+TOO_FAR equ 4096
+ IFNDEF WSIZE
+WSIZE equ 32768
+ ENDC
+WMASK equ WSIZE-1
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+MIN_LOOKAHEAD equ MAX_MATCH+MIN_MATCH+1
+; IFD BIG_MEM ; NOT supported -- type Pos needs to be 32 bits
+;HASH_BITS equ 15
+; ELSE
+ IFDEF SMALL_MEM
+HASH_BITS equ 13
+ ELSE
+HASH_BITS equ 14 ; default -- MEDIUM_MEM
+ ENDC
+; ENDC ; BIG_MEM
+HASH_SIZE equ 1<<HASH_BITS
+HASH_MASK equ HASH_SIZE-1
+H_SHIFT equ (HASH_BITS+MIN_MATCH-1)/MIN_MATCH
+B_SLOW equ 1
+B_FAST equ 2
+ZE_MEM equ 4
+EOF equ -1
+
+; struct config is defined by these offsets:
+Good_length equ 0
+Max_lazy equ 2
+Nice_length equ 4
+Max_chain equ 6
+Sizeof_config equ 8
+
+
+; external functions we call:
+ xref _ct_tally ; int ct_tally(int, int)
+ xref _flush_block ; unsigned long F(char *, unsigned long, int)
+ xref _ziperr ; void ziperr(int, char *)
+ xref _error ; void error(char *)
+ xref _calloc ; stdlib function: void *calloc(size_t, size_t)
+ xref _free ; stdlib function: void free(void *)
+ IFDEF DEBUG
+ xref _fputc ; stdio function: int fputc(int, FILE *)
+ xref _stderr ; pointer to FILE, which we pass to fputc
+ ENDC
+
+; our entry points:
+ xdef _lm_init ; void lm_init(int level, unsigned short *flags)
+ xdef _lm_free ; void lm_free(void)
+ xdef _deflate ; void deflate(void) ...the big one
+ xdef _fill_window ; this line is just for debugging
+
+
+; ============================================================================
+; Here is where we have our global variables.
+
+;;; section deflatevars,data
+
+; external global variables we reference:
+ xref _verbose ; signed int
+ xref _level ; signed int
+ xref _read_buf ; int (*read_buf)(char *, unsigned int)
+
+; global variables we make available:
+
+ xdef _window
+ xdef _prev
+ xdef _head
+ xdef _window_size
+ xdef _block_start
+ xdef _strstart
+
+ bss
+ quad
+
+ IFDEF DYN_ALLOC
+_prev: ds.l 1 ; pointer to calloc()'d unsigned short array
+_head: ds.l 1 ; pointer to calloc()'d unsigned short array
+_window: ds.l 1 ; pointer to calloc()'d unsigned char array
+ ELSE ; !DYN_ALLOC
+_prev: ds.w WSIZE ; array of unsigned short
+_head: ds.w HASH_SIZE ; array of unsigned short
+_window: ds.b 2*WSIZE ; array of unsigned char
+ ENDC ; ?DYN_ALLOC
+
+ text
+ quad
+_window_size: ds.l 1 ; unsigned long
+_block_start: ds.l 1 ; unsigned long
+_strstart: ds.w INTSIZE/2 ; unsigned int
+
+; Now here are our private variables:
+
+ IFDEF CPUTEST
+is020: ds.w 1 ; bool: CPU type is '020 or higher
+ ENDC
+ins_h: ds.w 1 ; unsigned short
+sliding: ds.w 1 ; bool: the file is read a piece at a time
+eofile: ds.w 1 ; bool: we have read in the end of the file
+max_lazy_match: ds.w 1 ; unsigned short
+lookahead: ds.w 1 ; unsigned short
+
+; These are NOT DECLARED AS STATIC in deflate.c, but currently could be:
+max_chain_len: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+prev_length: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+good_match: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+nice_match: ds.w 1 ; unsigned short (signed int in deflate.c)
+match_start: ds.w 1 ; unsigned short (unsigned int in deflate.c)
+
+; This array of struct config is a constant and could be in the code section:
+config_table: dc.w 0,0,0,0 ; level 0: store uncompressed
+ dc.w 4,4,8,4 ; level 1: fastest, loosest compression
+ dc.w 4,5,16,8 ; level 2
+ dc.w 4,6,32,32 ; level 3: highest to use deflate_fast
+ dc.w 4,4,16,16 ; level 4: lowest to use lazy matches
+ dc.w 8,16,32,32 ; level 5
+ dc.w 8,16,128,128 ; level 6: the default level
+ dc.w 8,32,128,256 ; level 7
+ dc.w 32,128,258,1024 ; level 8
+ dc.w 32,258,258,4096 ; level 9: maximum compression, slow
+
+
+;;CAL_SH MACRO ; macro for calling zcalloc()
+;; IFD INT16
+;; move.w #2,-(sp)
+;; move.w #\1,-(sp)
+;; jsr _zcalloc
+;; addq #4,sp
+;; ELSE
+;; pea 2
+;; pea \1
+;; jsr _zcalloc
+;; addq #8,sp
+;; ENDC
+;; ENDM
+
+CAL_SH MACRO _1 ; Okay, we're back to using regular calloc()...
+ movem.l d2/a2,-(sp)
+ pea 2
+ pea _1
+ jsr _calloc
+ addq #8,sp
+ movem.l (sp)+,d2/a2
+ ENDM
+
+; ============================================================================
+; And here we begin our functions. match_init is for internal use only:
+
+;; section deflate,code
+
+match_init:
+ IFDEF CPUTEST ; now check for platform type
+ IFDEF AMIGA ; Amiga specific test for '020 CPU:
+ xref _SysBase
+ NOLIST
+ INCLUDE 'exec/execbase.i'
+ LIST
+
+ clr.w is020 ; default value is 68000
+ move.l _SysBase,a0
+ btst #AFB_68020,AttnFlags+1(a0)
+ beq.s cheap
+ move.w #1,is020
+cheap:
+ ELSE ; !AMIGA
+
+ FAIL Write an '020-detector for your system here!
+; On the Macintosh, I believe GetEnvironment() provides the information.
+
+ ENDC ; AMIGA
+ ENDC ; CPUTEST
+ rts ; match_init consists only of rts if CPUTEST unset
+
+
+; ============================================================================
+; Here is longest_match(), the function that the rest of this was built up
+; from, the hottest hot spot in the program and therefore the most heavily
+; optimized. It has two different versions, one for '020 and higher CPUs, and
+; one for 68000/68010. It can test at runtime which version to use if you
+; create a test function in match_init for your platform. Currently such a
+; test is implemented for the Amiga. It can also be assembled to use '000 or
+; '020 code only.
+
+Cur_Match reg d0 ; unsigned int, kept valid as long
+Best_Len reg d1 ; unsigned int, kept valid as long
+Scan_Start reg d3 ; pair of bytes
+Scan_End reg d4 ; pair of bytes
+Limit reg d5 ; unsigned int
+Chain_Length reg d6 ; unsigned int
+Scan_Test reg d7 ; counter, pair of bytes sometimes
+Scan reg a0 ; pointer to unsigned char
+Match reg a1 ; pointer to unsigned char
+Prev_Address reg a2 ; pointer to unsigned short
+Scan_Ini reg a3 ; pointer to unsigned char
+Match_Ini reg a5 ; pointer to unsigned char
+; Note: "pair of bytes" means the two low order bytes of the register in
+; 68020 code, but means the lowest and third lowest bytes on the 68000.
+SAVEREGS reg d3-d7/a2/a3/a5 ; don't protect d0/d1/a0/a1
+; d2, a4, a6 not used... on Amiga, a4 is used by small-data memory model
+
+
+longest_match:
+ movem.l SAVEREGS,-(sp)
+
+; setup steps common to byte and word versions:
+ IFDEF INT16
+ and.l #$0000FFFF,Cur_Match ; upper half must be zero!
+; we use an and.l down here for the sake of ATSIGN/REGARGS.
+ moveq #0,Limit ; so adding to Scan_Ini works
+ ENDC
+ move.w (max_chain_len,pc),Chain_Length
+ move.w (prev_length,pc),Best_Len
+ MOVINT (_strstart,pc),Limit
+ BASEPTR _prev,Prev_Address
+ BASEPTR _window,Match_Ini
+ move.l Match_Ini,Scan_Ini
+ addq #MIN_MATCH,Match_Ini ; optimizes inner loop
+ add.l Limit,Scan_Ini
+ sub.w #MAX_DIST,Limit
+ bhi.s limit_ok
+ moveq #0,Limit
+limit_ok:
+ cmp.w (good_match,pc),Best_Len
+ blo.s length_ok
+ lsr.w #2,Chain_Length
+length_ok:
+ subq.w #1,Chain_Length
+
+ IFDEF CPUTEST
+ tst.w is020 ; can we use '020 stuff today?
+ bne WORD_match
+ ENDC
+
+ IFNDEF CPU020
+
+; for 68000 or 68010, use byte operations:
+ moveq #0,Scan_Start ; clear 2nd & 4th bytes, use 1st & 3rd
+ moveq #0,Scan_End ; likewise
+ moveq #0,Scan_Test ; likewise
+ move.b (Scan_Ini),Scan_Start
+ swap Scan_Start ; swap is faster than 8 bit shift
+ move.b 1(Scan_Ini),Scan_Start
+ move.b -1(Scan_Ini,Best_Len.w),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len.w),Scan_End
+ bra.s bdo_scan
+
+blong_loop:
+ move.b -1(Scan_Ini,Best_Len.w),Scan_End
+ swap Scan_End
+ move.b 0(Scan_Ini,Best_Len.w),Scan_End
+
+bshort_loop:
+ add.w Cur_Match,Cur_Match ; assert value before doubling < 32K
+ IFNE 32768-WSIZE
+ and.w #(WMASK*2),Cur_Match
+ ENDC
+ move.w (Prev_Address,Cur_Match.l),Cur_Match
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,bdo_scan
+ bra return
+
+bdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ move.b -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH(Match,Best_Len.w),Scan_Test
+ cmp.l Scan_Test,Scan_End
+ bne.s bshort_loop
+ move.b -MIN_MATCH(Match),Scan_Test
+ swap Scan_Test
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.l Scan_Test,Scan_Start
+ bne.s bshort_loop
+ move.w #(MAX_MATCH-3),Scan_Test
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+bscan_loop:
+ cmp.b (Match)+,(Scan)+
+ dbne Scan_Test,bscan_loop
+ subq #1,Scan
+
+ sub.l Scan_Ini,Scan ; assert difference is 16 bits
+ cmp.w Best_Len,Scan
+ bls.s bshort_loop
+ MOVINT Scan,Best_Len
+ move.w Cur_Match,match_start
+ cmp.w (nice_match,pc),Best_Len
+ blo.s blong_loop
+ IFDEF CPUTEST
+ bra return
+ ENDC
+
+ ENDC ; !CPU020
+
+ IFNDEF CPU000
+;;; MACHINE MC68020
+
+; for 68020 or higher, use word operations even on odd addresses:
+WORD_match:
+ move.w (Scan_Ini),Scan_Start
+ move.w -1(Scan_Ini,Best_Len.w),Scan_End
+ bra.s wdo_scan
+
+wlong_loop:
+ move.w -1(Scan_Ini,Best_Len.w),Scan_End
+
+wshort_loop:
+ and.w #WMASK,Cur_Match
+ move.w (Prev_Address,Cur_Match.w*2),Cur_Match ; '020 addressing mode
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,wdo_scan
+ bra.s return
+
+wdo_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+ cmp.w -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+ bne.s wshort_loop
+ cmp.w -MIN_MATCH(Match),Scan_Start
+ bne.s wshort_loop
+ IFDEF QUADLONG
+; By some measurements, this version of the code is a little tiny bit faster.
+; But on some files it's slower. It probably pays off only when there are
+; long match strings, and costs in the most common case of three-byte matches.
+ moveq #((MAX_MATCH-MIN_MATCH)/16),Scan_Test ; value = 15
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+wscan_loop:
+ cmp.l (Match)+,(Scan)+ ; test four bytes at a time
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ bne.s odd
+ cmp.l (Match)+,(Scan)+
+ dbne Scan_Test,wscan_loop ; '020 can cache a bigger loop
+odd:
+ subq #4,Scan
+ subq #4,Match
+ cmp.b (Match)+,(Scan)+ ; find good bytes in bad longword
+ bne.s even
+ cmp.b (Match)+,(Scan)+
+ bne.s even
+ cmp.b (Match)+,(Scan)+
+ beq.s steven
+even: subq #1,Scan
+ ELSE ; !QUADLONG
+ moveq #((MAX_MATCH-MIN_MATCH)/2),Scan_Test ; value = 127
+ lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loop
+
+wscan_loop:
+ cmp.w (Match)+,(Scan)+
+ dbne Scan_Test,wscan_loop
+ subq #2,Scan
+ move.b -2(Match),Scan_Test
+ cmp.b (Scan),Scan_Test
+ bne.s steven
+ addq #1,Scan
+ ENDC ; ?QUADLONG
+steven:
+ sub.l Scan_Ini,Scan ; assert: difference is 16 bits
+ cmp.w Best_Len,Scan
+ bls.s wshort_loop
+ MOVINT Scan,Best_Len
+ move.w Cur_Match,match_start
+ cmp.w (nice_match,pc),Best_Len
+ blo.s wlong_loop
+
+;;; MACHINE MC68000
+ ENDC ; !CPU000
+
+return:
+ MOVINT Best_Len,d0 ; return value (upper half should be clear)
+ movem.l (sp)+,SAVEREGS
+ rts
+
+
+; =============================================================================
+; This is the deflate() function itself, our main entry point. It calls
+; longest_match, above, and some outside functions. It is a hot spot, but not
+; as hot as longest_match. It uses no special '020 code.
+
+; ================== Several macros used in deflate() and later functions:
+
+; Arg 1 is D-reg that new ins_h value is to be left in,
+; arg 2 is the byte value to be hashed into it, which must not be the same reg
+UP_HASH MACRO _1,_2
+ move.w (ins_h,pc),_1
+ asl.w #H_SHIFT,_1
+ eor.b _2,_1
+ and.w #HASH_MASK,_1 ; ((ins_h << H_SHIFT) ^ c) & HASH_MASK
+ move.w _1,ins_h ; ins_h = that
+ ENDM
+
+; Arg 1 is scratch A, arg 2 is scratch D
+IN_STR MACRO _1,_2
+ move.l Strst,_2
+ addq.w #MIN_MATCH-1,_2
+ move.b (Window,_2.l),_2 ; window[strstart + MIN_MATCH - 1]
+ UP_HASH Head,_2
+ add.l Head,Head ; assert upper word is zero before add
+ BASEPTR _head,_1
+ add.l Head,_1
+ move.w (_1),Head ; hash_head = head[ins_h]
+ move.w Strst,(_1) ; head[ins_h] = strstart
+ move.l Strst,_2
+ IFNE WSIZE-32768
+ and.w #WMASK,_2
+ ENDC
+ add.w _2,_2 ; masks implicitly when WSIZE == 32768
+ move.w Head,(Prev,_2.l) ; prev[str_start & WMASK] = hash_head
+ ENDM
+
+; Arg 1 is bool (int) EOF flag, flush_block result is in d0, trashes d1/a0/a1
+FLUSH_B MACRO _1
+ local nenu,nun
+ movem.l d2/a2,-(sp)
+ IF _1==0
+ CLRINT -(sp)
+ ELSEIF (INTSIZE==4).and.(_1<$8000)
+ pea (_1).w
+ ELSE
+ MOVINT #_1,-(sp)
+ ENDC
+ move.l (_block_start,pc),d0
+ blt.s nenu
+ move.l Window,a0
+ add.l d0,a0
+ bra.s nun
+nenu: sub.l a0,a0 ; if block_start < 0, push NULL
+nun: sub.l Strst,d0
+ neg.l d0
+ move.l d0,-(sp)
+ move.l a0,-(sp)
+ jsr _flush_block
+ lea 8+INTSIZE(sp),sp
+ movem.l (sp)+,d2/a2
+ ENDM
+
+; This expands to nothing unless DEBUG is defined.
+; Arg 1 is a byte to be trace-outputted -- if it is d0 it must be a valid int
+TRACE_C MACRO _1
+ local qui
+ IFDEF DEBUG
+ cmp.w #1,_verbose+INTSIZE-2 ; test lower word only
+ ble.s qui
+ moveq #0,d0
+ move.b ea,d0
+ movem.l d2/a2,-(sp)
+ move.l _stderr,-(sp)
+ MOVINT d0,-(sp)
+ jsr _fputc
+ addq.l #4+INTSIZE,sp
+ movem.l (sp)+,d2/a2
+qui:
+ ENDC ; DEBUG
+ ENDM
+
+; ================== Here are the register vars we use, and deflate() itself:
+
+Window reg a2 ; cached address of window[]
+Prev reg a3 ; cached address of prev[]
+Strst reg d7 ; strstart cached as a longword
+Look reg d6 ; lookahead cached as short
+Head reg d5 ; local variable hash_head, short
+PrevL reg d4 ; prev_length cached as short
+MatchL reg d3 ; local variable match_length, unsigned short
+Avail reg d2 ; local variable available_match, bool
+PrevM reg a5 ; local variable prev_match, int in an A-reg
+
+DEFREGS reg d3-d7/a3/a5
+
+
+_deflate: ; first, setup steps common to deflate and deflate_fast:
+ movem.l DEFREGS,-(sp)
+ IFDEF INT16
+ moveq #0,Strst ; make sure strstart is valid as a long
+ ENDC
+ moveq #0,Head ; ditto for hash_head
+ MOVINT (_strstart,pc),Strst
+ move.w (lookahead,pc),Look
+ move.w (prev_length,pc),PrevL
+ BASEPTR _window,Window
+ BASEPTR _prev,Prev
+ MOVINT _level,d0
+ cmp.w #3,d0
+ ble deflate_fast
+ moveq #MIN_MATCH-1,MatchL
+ moveq #0,Avail
+
+look_loop:
+ tst.w Look
+ beq last_tally
+ IN_STR a0,d0
+ move.w MatchL,PrevL
+ move.w (match_start,pc),PrevM
+ move.w #MIN_MATCH-1,MatchL
+
+ tst.w Head
+ beq.s no_new_match
+ cmp.w (max_lazy_match,pc),PrevL
+ bhs.s no_new_match
+ move.w Strst,d0
+ sub.w Head,d0
+ cmp.w #MAX_DIST,d0
+ bhi.s no_new_match
+ move.w PrevL,prev_length ; longest_match reads these variables
+ MOVINT Strst,_strstart
+ MOVINT Head,d0 ; parm for longest_match
+ bsr longest_match ; sets match_start
+ cmp.w Look,d0 ; does length exceed valid data?
+ bls.s stml
+ move.w Look,d0
+stml: move.w d0,MatchL ; valid length of match
+ cmp.w #MIN_MATCH,MatchL ; is the match only three bytes?
+ bne.s no_new_match
+ move.w (match_start,pc),d0
+ sub.w Strst,d0
+ cmp.w #-TOO_FAR,d0
+ bge.s no_new_match
+ moveq #MIN_MATCH-1,MatchL ; mark the current match as no good
+
+no_new_match:
+ cmp.w #MIN_MATCH,PrevL
+ blo literal
+ cmp.w MatchL,PrevL
+ blo literal
+ ; CHECK_MATCH Strst-1,PrevM,PrevL
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ move.l PrevL,d0
+ subq.w #MIN_MATCH,d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ move.l Strst,d0
+ sub.w PrevM,d0
+ subq.w #1,d0
+ MOVINT d0,-(sp)
+ jsr _ct_tally ; sets d0 true if we have to flush
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ subq.w #3,PrevL ; convert for dbra (prev_length - 2)
+ sub.w PrevL,Look
+ subq.w #2,Look
+insertmatch:
+ addq.w #1,Strst
+ IN_STR a0,d1 ; don't clobber d0
+ dbra PrevL,insertmatch
+ moveq #0,Avail
+ moveq #0,PrevL ; not needed?
+ moveq #MIN_MATCH-1,MatchL
+ addq.w #1,Strst
+ tst.w d0
+ beq refill
+ FLUSH_B 0
+ move.l Strst,_block_start
+ bra.s refill
+
+literal:
+ tst.w Avail
+ bne.s yeslit
+ moveq #1,Avail
+ bra.s skipliteral
+yeslit: TRACE_C <-1(Window,Strst.l)>
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b -1(Window,Strst.l),d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ tst.w d0
+ beq.s skipliteral
+ FLUSH_B 0
+ move.l Strst,_block_start
+skipliteral:
+ addq.w #1,Strst
+ subq.w #1,Look
+
+refill:
+ cmp.w #MIN_LOOKAHEAD,Look
+ bhs look_loop
+ bsr fill_window
+ bra look_loop
+
+last_tally:
+ tst.w Avail
+ beq last_flush
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b -1(Window,Strst.l),d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+last_flush:
+ FLUSH_B 1
+ bra deflate_exit
+
+; ================== This is another version used for low compression levels:
+
+deflate_fast:
+ moveq #0,MatchL
+ moveq #MIN_MATCH-1,PrevL
+flook_loop:
+ tst.w Look
+ beq flast_flush
+
+ IN_STR a0,d0
+ tst.w Head
+ beq.s fno_new_match
+ move.w Strst,d0
+ sub.w Head,d0
+ cmp.w #MAX_DIST,d0
+ bhi.s fno_new_match
+ move.w PrevL,prev_length ; longest_match reads these variables
+ MOVINT Strst,_strstart
+ MOVINT Head,d0 ; parm for longest_match
+ bsr longest_match ; sets match_start
+ cmp.w Look,d0 ; does length exceed valid data?
+ bls.s fstml
+ move.w Look,d0
+fstml: move.w d0,MatchL ; valid length of match
+
+fno_new_match:
+ cmp.w #MIN_MATCH,MatchL
+ blo fliteral
+ ; CHECK_MATCH Strst,match_start,MatchL
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ move.l MatchL,d0
+ subq.w #MIN_MATCH,d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ move.l Strst,d0
+ sub.w (match_start,pc),d0
+ MOVINT d0,-(sp)
+ jsr _ct_tally ; sets d0 true if we have to flush
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ sub.w MatchL,Look
+ cmp.w (max_lazy_match,pc),MatchL
+ bhi ftoolong
+ subq.w #2,MatchL
+finsertmatch:
+ addq.w #1,Strst
+ IN_STR a0,d1 ; preserve d0
+ dbra MatchL,finsertmatch
+ moveq #0,MatchL ; not needed?
+ addq.w #1,Strst
+ bra.s flushfill
+
+ftoolong:
+ add.w MatchL,Strst
+ moveq #0,MatchL
+ moveq #0,d1 ; preserve d0
+ move.b (Window,Strst.l),d1
+ move.w d1,ins_h
+; My assembler objects to passing <1(Window,Strst.l)> directly to UP_HASH...
+ move.b 1(Window,Strst.l),Avail ; Avail is not used in deflate_fast
+ UP_HASH d1,Avail ; preserve d0
+ IFNE MIN_MATCH-3
+ FAIL needs to UP_HASH another MIN_MATCH-3 times, but with what arg?
+ ENDC
+ bra.s flushfill
+
+fliteral:
+ TRACE_C <(Window,Strst.l)>
+ MOVINT Strst,_strstart ; ct_tally reads this variable
+ moveq #0,d0
+ move.b (Window,Strst.l),d0
+ movem.l d2/a2,-(sp)
+ MOVINT d0,-(sp)
+ CLRINT -(sp)
+ jsr _ct_tally ; d0 set if we need to flush
+ addq #2*INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ addq.w #1,Strst
+ subq.w #1,Look
+
+flushfill:
+ tst.w d0
+ beq.s frefill
+ FLUSH_B 0
+ move.l Strst,_block_start
+frefill:
+ cmp.w #MIN_LOOKAHEAD,Look
+ bhs flook_loop
+ bsr fill_window
+ bra flook_loop
+
+flast_flush:
+ FLUSH_B 1 ; sets our return value
+
+deflate_exit:
+ MOVINT Strst,_strstart ; save back cached values
+ move.w PrevL,prev_length
+ move.w Look,lookahead
+ movem.l (sp)+,DEFREGS
+ rts
+
+
+; =========================================================================
+; void fill_window(void) calls the input function to refill the sliding
+; window that we use to find substring matches in.
+
+More reg Head ; local variable in fill_window
+WindTop reg Prev ; local variable used for sliding
+SlidIx reg PrevL ; local variable used for sliding
+
+FWREGS reg d2-d5/a2-a6 ; does NOT include Look and Strst
+; all registers available to be clobbered by the sliding operation:
+; we exclude More, WindTop, SlidIx, Look, Strst, Window, a4 and a7.
+SPAREGS reg d0-d3/a0-a1/a5-a6
+SPCOUNT equ 8 ; number of registers in SPAREGS
+
+
+_fill_window: ; C-callable entry point
+ movem.l Look/Strst,-(sp)
+ IFDEF INT16
+ moveq #0,Strst ; Strst must be valid as a long
+ ENDC
+ MOVINT (_strstart,pc),Strst
+ move.w (lookahead,pc),Look
+ BASEPTR _window,Window
+ bsr.s fill_window
+ MOVINT Strst,_strstart
+ move.w Look,lookahead
+ movem.l (sp)+,Look/Strst
+ rts
+
+; strstart, lookahead, and window must be cached in Strst, Look, and Window:
+fill_window: ; asm-callable entry point
+ movem.l FWREGS,-(sp)
+ move.w (eofile,pc),d0 ; we put this up here for speed
+ bne fwdone
+ and.l #$FFFF,Look ; make sure Look is valid as long
+fw_refill:
+ move.l (_window_size,pc),More ; <= 64K
+ sub.l Look,More
+ sub.l Strst,More ; Strst is already valid as long
+ cmp.w #EOF,More
+ bne.s notboundary
+ subq.w #1,More
+ bra checkend
+
+notboundary:
+ move.w (sliding,pc),d0
+ beq checkend
+ cmp.w #WSIZE+MAX_DIST,Strst
+ blo checkend
+ IF (32768-WSIZE)>0
+ lea WSIZE(Window),WindTop ; WindTop is aligned when Window is
+ ELSE
+ move.l Window,WindTop
+ add.l #WSIZE,WindTop
+ ENDC
+ move.l Window,d0
+ and.w #3,d0
+ beq.s isaligned
+ subq.w #1,d0
+align: move.b (WindTop)+,(Window)+ ; copy up to a longword boundary
+ dbra d0,align
+isaligned:
+; This is faster than a simple move.l (WindTop)+,(Window)+ / dbra loop:
+ move.w #(WSIZE-1)/(4*SPCOUNT),SlidIx
+slide: movem.l (WindTop)+,SPAREGS ; copy, 32 bytes at a time!
+ movem.l SPAREGS,(Window) ; a slight overshoot doesn't matter.
+ lea 4*SPCOUNT(Window),Window ; can't use (aN)+ as movem.l dest
+ dbra SlidIx,slide
+ BASEPTR _window,Window ; restore cached value
+ sub.w #WSIZE,match_start
+ sub.w #WSIZE,Strst
+ sub.l #WSIZE,_block_start
+ add.w #WSIZE,More
+ BASEPTR _head,a0
+ move.w #HASH_SIZE-1,d0
+fixhead:
+ move.w (a0),d1
+ sub.w #WSIZE,d1
+ bpl.s headok
+ moveq #0,d1
+headok: move.w d1,(a0)+
+ dbra d0,fixhead
+ BASEPTR _prev,a0
+ move.w #WSIZE-1,d0
+fixprev:
+ move.w (a0),d1
+ sub.w #WSIZE,d1
+ bpl.s prevok
+ moveq #0,d1
+prevok: move.w d1,(a0)+
+ dbra d0,fixprev
+ TRACE_C #'.'
+
+ move _verbose+INTSIZE-2,d0
+ beq checkend
+ movem.l d2/a2,-(sp)
+ xref _print_period
+ jsr _print_period
+ movem.l (sp)+,d2/a2
+
+checkend: ; assert eofile is false
+ movem.l d2/a2,-(sp)
+ MOVINT More,-(sp) ; assert More's upper word is zero
+ move.l Strst,d0
+ add.w Look,d0
+ add.l Window,d0
+ move.l d0,-(sp)
+ move.l _read_buf,a0
+ jsr (a0) ; refill the upper part of the window
+ addq #4+INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ tst.w d0
+ beq.s iseof
+ cmp.w #EOF,d0
+ beq.s iseof
+ add.w d0,Look
+ cmp.w #MIN_LOOKAHEAD,Look
+ blo fw_refill ; eofile is still false
+
+ bra.s fwdone
+iseof: move.w #1,eofile
+fwdone: movem.l (sp)+,FWREGS
+ rts
+
+
+; =========================================================================
+; void lm_free(void) frees dynamic arrays in the DYN_ALLOC version.
+
+;;; xdef _lm_free ; the entry point
+
+_lm_free:
+ IFDEF DYN_ALLOC
+ move.l _window,d0
+ beq.s lf_no_window
+ movem.l d2/a2,-(sp)
+ move.l d0,-(sp)
+ jsr _free
+ addq #4,sp
+ movem.l (sp)+,d2/a2
+ clr.l _window
+lf_no_window:
+ move.l _prev,d0
+ beq.s lf_no_prev
+ movem.l d2/a2,-(sp)
+ move.l d0,-(sp)
+ jsr _free
+ move.l _head,(sp) ; reuse the same stack arg slot
+ jsr _free
+ addq #4,sp
+ movem.l (sp)+,d2/a2
+ clr.l _prev
+ clr.l _head
+lf_no_prev:
+ ENDC
+ rts
+
+; ============================================================================
+; void lm_init(int pack_level, unsigned short *flags) allocates dynamic arrays
+; if any, and initializes all variables so that deflate() is ready to go.
+
+;;; xdef _lm_init ; the entry point
+
+Level reg d2
+;Window reg a2 ; as in deflate()
+
+_lm_init:
+ MOVINT 4(sp),d0
+ move.l 4+INTSIZE(sp),a0
+ move.w d0,Level
+ cmp.w #1,Level
+ blt.s levelerr
+ bgt.s try9
+ bset.b #B_FAST,1(a0)
+try9: cmp.w #9,Level
+ bgt.s levelerr
+ blt.s levelok
+ bset.b #B_SLOW,1(a0)
+ bra.s levelok
+levelerr:
+ pea (level_message,pc)
+ jsr _error ; never returns
+levelok:
+ clr.w sliding
+ move.l (_window_size,pc),d0
+ bne.s gotawindowsize
+ move.w #1,sliding
+ move.l #2*WSIZE,_window_size
+gotawindowsize:
+
+ BASEPTR _window,Window
+ IFDEF DYN_ALLOC
+ move.l Window,d0 ; fake tst.l
+ bne.s gotsomewind
+ CAL_SH WSIZE
+ move.l d0,Window
+ move.l d0,_window
+ bne.s gotsomewind
+ pea (window_message,pc)
+ bra error
+gotsomewind:
+ tst.l _prev
+ bne.s gotsomehead
+ CAL_SH WSIZE
+ move.l d0,_prev
+ beq.s nohead
+ CAL_SH HASH_SIZE
+ move.l d0,_head
+ bne.s gotfreshhead ; newly calloc'd memory is zeroed
+nohead: pea (hash_message,pc)
+error: MOVINT #ZE_MEM,-(sp)
+ jsr _ziperr ; never returns
+gotsomehead:
+ ENDC ; DYN_ALLOC
+
+ move.w #(HASH_SIZE/2)-1,d0 ; two shortwords per loop
+ BASEPTR _head,a0
+wipeh: clr.l (a0)+
+ dbra d0,wipeh
+gotfreshhead:
+ move.l Level,d0
+ IFEQ Sizeof_config-8
+ asl.l #3,d0
+ ELSE
+ mulu #Sizeof_config,d0
+ ENDC
+ lea (config_table,pc),a0
+ add.l d0,a0
+ move.w Max_lazy(a0),max_lazy_match
+ move.w Good_length(a0),good_match
+ move.w Nice_length(a0),nice_match
+ move.w Max_chain(a0),max_chain_len
+ CLRINT _strstart
+ clr.l _block_start
+ bsr match_init
+
+ clr.w eofile
+ movem.l d2/a2,-(sp)
+ MOVINT #WSIZE,-(sp) ; We read only 32K because lookahead is short
+ move.l Window,-(sp) ; even when int size is long, as if deflate.c
+ move.l _read_buf,a0 ; were compiled with MAXSEG_64K defined.
+ jsr (a0)
+ addq #4+INTSIZE,sp
+ movem.l (sp)+,d2/a2
+ move.w d0,lookahead
+ beq.s noread
+ cmp.w #EOF,d0
+ bne.s irefill
+noread: move.w #1,eofile
+ clr.w lookahead
+ bra.s init_done
+
+irefill:
+ move.w (lookahead,pc),d0
+ cmp.w #MIN_LOOKAHEAD,d0
+ bhs.s hashify
+ bsr _fill_window ; use the C-callable version
+hashify:
+ clr.w ins_h
+ moveq #MIN_MATCH-2,d0
+hash1: move.b (Window)+,d1
+ UP_HASH Level,d1
+ dbra d0,hash1
+
+init_done:
+ rts
+
+; strings for error messages:
+ IFDEF DYN_ALLOC
+hash_message dc.b 'hash table allocation',0
+window_message dc.b 'window allocation',0
+ ENDC
+level_message dc.b 'bad pack level',0
+
+ end
diff --git a/human68k/human68k.c b/human68k/human68k.c
new file mode 100644
index 0000000..be47b57
--- /dev/null
+++ b/human68k/human68k.c
@@ -0,0 +1,371 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include "zip.h"
+
+#include <time.h>
+#include <stdio.h>
+#include <dirent.h>
+#ifndef UTIL
+#include <sys/dos.h>
+#endif
+
+#define MATCH shmatch
+
+#define PAD 0
+
+
+#ifndef UTIL
+
+/* Library functions not in (most) header files */
+
+int utime OF((char *, ztimbuf *));
+
+/* Local functions */
+local char *readd OF((DIR *));
+
+local char *readd(DIR* d)
+{
+ struct dirent* e = readdir(d);
+
+ return e == NULL ? NULL : e->d_name;
+}
+
+int wild(char* w)
+{
+ struct _filbuf inf;
+ /* convert FNAMX to malloc - 11/08/04 EG */
+ char *name;
+ char *p;
+
+ if (strcmp(w, "-") == 0) /* if compressing stdin */
+ return newname(w, 0, 0);
+ if ((name = malloc(strlen(w) + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "wild");
+ }
+ strcpy(name, w);
+ _toslash(name);
+
+ if ((p = strrchr(name, '/')) == NULL && (p = strrchr(name, ':')) == NULL)
+ p = name;
+ else
+ p++;
+ if (_dos_lfiles (&inf, w, 0xff) < 0) {
+ free(name);
+ return ZE_MISS;
+ }
+ do {
+ int r;
+
+ strcpy(p, inf.name);
+ r = procname(name, 0);
+ if (r != ZE_OK) {
+ free(name);
+ return r;
+ }
+ } while (_dos_nfiles(&inf) >= 0);
+ free(name);
+
+ return ZE_OK;
+}
+
+int procname(n, caseflag)
+char *n; /* name to process */
+int caseflag; /* true to force case-sensitive match */
+/* Process a name or sh expression to operate on (or exclude). Return
+ an error code in the ZE_ class. */
+{
+ char *a; /* path and name for recursion */
+ DIR *d; /* directory stream from opendir() */
+ char *e; /* pointer to name from readd() */
+ int m; /* matched flag */
+ char *p; /* path for recursion */
+ struct stat s; /* result of stat() */
+ struct zlist far *z; /* steps through zfiles list */
+
+ if (strcmp(n, "-") == 0) /* if compressing stdin */
+ return newname(n, 0, caseflag);
+ else if (LSSTAT(n, &s))
+ {
+ /* Not a file or directory--search for shell expression in zip file */
+ p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
+ m = 1;
+ for (z = zfiles; z != NULL; z = z->nxt) {
+ if (MATCH(p, z->iname, caseflag))
+ {
+ z->mark = pcount ? filter(z->zname, caseflag) : 1;
+ if (verbose)
+ fprintf(mesg, "zip diagnostic: %scluding %s\n",
+ z->mark ? "in" : "ex", z->name);
+ m = 0;
+ }
+ }
+ free((zvoid *)p);
+ return m ? ZE_MISS : ZE_OK;
+ }
+
+ /* Live name--use if file, recurse if directory */
+ _toslash(n);
+ if ((s.st_mode & S_IFDIR) == 0)
+ {
+ /* add or remove name of file */
+ if ((m = newname(n, 0, caseflag)) != ZE_OK)
+ return m;
+ } else {
+ /* Add trailing / to the directory name */
+ if ((p = malloc(strlen(n)+2)) == NULL)
+ return ZE_MEM;
+ if (strcmp(n, ".") == 0) {
+ *p = '\0'; /* avoid "./" prefix and do not create zip entry */
+ } else {
+ strcpy(p, n);
+ a = p + strlen(p);
+ if (a[-1] != '/')
+ strcpy(a, "/");
+ if (dirnames && (m = newname(p, 1, caseflag)) != ZE_OK) {
+ free((zvoid *)p);
+ return m;
+ }
+ }
+ /* recurse into directory */
+ if (recurse && (d = opendir(n)) != NULL)
+ {
+ while ((e = readd(d)) != NULL) {
+ if (strcmp(e, ".") && strcmp(e, ".."))
+ {
+ if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
+ {
+ closedir(d);
+ free((zvoid *)p);
+ return ZE_MEM;
+ }
+ strcat(strcpy(a, p), e);
+ if ((m = procname(a, caseflag)) != ZE_OK) /* recurse on name */
+ {
+ if (m == ZE_MISS)
+ zipwarn("name not matched: ", a);
+ else
+ ziperr(m, a);
+ }
+ free((zvoid *)a);
+ }
+ }
+ closedir(d);
+ }
+ free((zvoid *)p);
+ } /* (s.st_mode & S_IFDIR) == 0) */
+ return ZE_OK;
+}
+
+char *ex2in(x, isdir, pdosflag)
+char *x; /* external file name */
+int isdir; /* input: x is a directory */
+int *pdosflag; /* output: force MSDOS file attributes? */
+/* Convert the external file name to a zip file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *n; /* internal file name (malloc'ed) */
+ char *t; /* shortened name */
+
+ /* Find starting point in name before doing malloc */
+ t = (x[0] && x[1] == (char)':') ? x + 2 : x;
+ while (*t == (char)'/')
+ t++;
+
+ /* Make changes, if any, to the copied name (leave original intact) */
+ _toslash(t);
+
+ if (!pathput)
+ t = last(t, '/');
+
+ /* Malloc space for internal name and copy it */
+ if ((n = malloc(strlen(t) + 1)) == NULL)
+ return NULL;
+ strcpy(n, t);
+
+ if (dosify)
+ msname(n);
+ /* Returned malloc'ed name */
+ if (pdosflag)
+ *pdosflag = dosify;
+ return n;
+}
+
+
+char *in2ex(n)
+char *n; /* internal file name */
+/* Convert the zip file name to an external file name, returning the malloc'ed
+ string or NULL if not enough memory. */
+{
+ char *x; /* external file name */
+ if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
+ return NULL;
+ return strcpy(x, n);
+}
+
+void stamp(f, d)
+char *f; /* name of file to change */
+ulg d; /* dos-style time to change it to */
+/* Set last updated and accessed time of file f to the DOS time d. */
+{
+ ztimbuf u; /* argument for utime() */
+
+ /* Convert DOS time to time_t format in u */
+ u.actime = u.modtime = dos2unixtime(d);
+
+ /* Set updated and accessed times of f */
+ utime(f, &u);
+}
+
+ulg filetime(f, a, n, t)
+char *f; /* name of file to get info on */
+ulg *a; /* return value: file attributes */
+long *n; /* return value: file size */
+iztimes *t; /* return value: access, modific. and creation times */
+/* If file *f does not exist, return 0. Else, return the file's last
+ modified date and time as an MSDOS date and time. The date and
+ time is returned in a long with the date most significant to allow
+ unsigned integer comparison of absolute times. Also, if a is not
+ a NULL pointer, store the file attributes there, with the high two
+ bytes being the Unix attributes, and the low byte being a mapping
+ of that to DOS attributes. If n is not NULL, store the file size
+ there. If t is not NULL, the file's access, modification and creation
+ times are stored there as UNIX time_t values.
+ If f is "-", use standard input as the file. If f is a device, return
+ a file size of -1 */
+{
+ struct stat s; /* results of stat() */
+ /* convert FNMAX to malloc - 11/8/04 EG */
+ char *name;
+ int len = strlen(f);
+ isstdin = !strcmp(f, "-");
+
+ if ((name = malloc(len + 1)) == NULL) {
+ ZIPERR(ZE_MEM, "filetime");
+ }
+ strcpy(name, f);
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+
+ if (isstdin) {
+ if (fstat(fileno(stdin), &s) != 0) {
+ free(name);
+ error("fstat(stdin)");
+ }
+ } else if (LSSTAT(name, &s) != 0) {
+ /* Accept about any file kind including directories
+ * (stored with trailing / with -r option)
+ */
+ free(name);
+ return 0;
+ }
+
+ if (a != NULL) {
+ int atr = _dos_chmod(name, -1);
+
+ if (atr < 0)
+ atr = 0x20;
+ *a = ((ulg)s.st_mode << 16) | (isstdin ? 0L : (ulg)atr);
+ }
+ free(name);
+ if (n != NULL)
+ *n = S_ISVOL(s.st_mode) ? -2L : S_ISREG(s.st_mode) ? s.st_size : -1L;
+ if (t != NULL) {
+ t->atime = s.st_atime;
+ t->mtime = s.st_mtime;
+ t->ctime = s.st_ctime;
+ }
+
+ return unix2dostime(&s.st_mtime);
+}
+
+int set_extra_field(z, z_utim)
+ struct zlist far *z;
+ iztimes *z_utim;
+ /* create extra field and change z->att if desired */
+{
+#ifdef USE_EF_UT_TIME
+ if ((z->extra = (char *)malloc(EB_HEADSIZE+EB_UT_LEN(1))) == NULL)
+ return ZE_MEM;
+
+ z->extra[0] = 'U';
+ z->extra[1] = 'T';
+ z->extra[2] = EB_UT_LEN(1); /* length of data part of e.f. */
+ z->extra[3] = 0;
+ z->extra[4] = EB_UT_FL_MTIME;
+ z->extra[5] = (char)(z_utim->mtime);
+ z->extra[6] = (char)(z_utim->mtime >> 8);
+ z->extra[7] = (char)(z_utim->mtime >> 16);
+ z->extra[8] = (char)(z_utim->mtime >> 24);
+
+ z->cext = z->ext = (EB_HEADSIZE+EB_UT_LEN(1));
+ z->cextra = z->extra;
+
+ return ZE_OK;
+#else /* !USE_EF_UT_TIME */
+ return (int)(z-z);
+#endif /* ?USE_EF_UT_TIME */
+}
+
+int deletedir(d)
+char *d; /* directory to delete */
+/* Delete the directory *d if it is empty, do nothing otherwise.
+ Return the result of rmdir(), delete(), or system().
+ For VMS, d must be in format [x.y]z.dir;1 (not [x.y.z]).
+ */
+{
+ return rmdir(d);
+}
+
+void print_period(void)
+{
+ fputc('.', stderr);
+}
+
+#endif /* !UTIL */
+
+
+/******************************/
+/* Function version_local() */
+/******************************/
+
+void version_local()
+{
+ static ZCONST char CompiledWith[] = "Compiled with %s%s for %s%s%s%s.\n\n";
+#if 0
+ char buf[40];
+#endif
+
+ printf(CompiledWith,
+
+#ifdef __GNUC__
+ "gcc ", __VERSION__,
+#else
+# if 0
+ "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
+# else
+ "unknown compiler", "",
+# endif
+#endif
+
+ "Human68k",
+#ifdef __MC68020__
+ " (X68030)",
+#else
+ " (X680x0)",
+#endif
+
+#ifdef __DATE__
+ " on ", __DATE__
+#else
+ "", ""
+#endif
+ );
+
+} /* end function version_local() */
diff --git a/human68k/match.s b/human68k/match.s
new file mode 100644
index 0000000..4e6bc1c
--- /dev/null
+++ b/human68k/match.s
@@ -0,0 +1,163 @@
+*===========================================================================
+* Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+*
+* See the accompanying file LICENSE, version 1999-Oct-05 or later
+* (the contents of which are also included in zip.h) for terms of use.
+* If, for some reason, both of these files are missing, the Info-ZIP license
+* also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*===========================================================================
+*
+* match.s -- optional optimized asm version of longest match in deflate.c
+* Written by Jean-loup Gailly
+*
+* Adapted for X68000 by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
+* Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
+* using the code in match.S.
+* The major change in this code consists of removing all unaligned
+* word accesses, because they cause 68000-based machines to crash.
+* For maximum speed, UNALIGNED_OK can be defined.
+* The program will then only run on 68020-based machines, though.
+
+
+Cur_Match reg d0 ; Must be in d0!
+Best_Len reg d1
+Loop_Counter reg d2
+Scan_Start reg d3
+Scan_End reg d4
+Limit reg d5
+Chain_Length reg d6
+Scan_Test reg d7
+Scan reg a0
+Match reg a1
+Prev_Address reg a2
+Scan_Ini reg a3
+Match_Ini reg a4
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+WSIZE equ 32768
+MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
+
+
+ .xref _max_chain_length
+ .xref _prev_length
+ .xref _prev
+ .xref _window
+ .xref _strstart
+ .xref _good_match
+ .xref _match_start
+ .xref _nice_match
+
+
+ .xdef _match_init
+ .xdef _longest_match
+
+ .text
+ .even
+
+
+_match_init:
+ rts
+
+
+_longest_match:
+ move.l 4(sp),Cur_Match
+.ifdef UNALIGNED_OK
+ movem.l d2-d6/a2-a4,-(sp)
+.else
+ movem.l d2-d7/a2-a4,-(sp)
+.endif
+ move.l _max_chain_length,Chain_Length
+ move.l _prev_length,Best_Len
+ lea _prev,Prev_Address
+ lea _window+MIN_MATCH,Match_Ini
+ move.l _strstart,Limit
+ move.l Match_Ini,Scan_Ini
+ add.l Limit,Scan_Ini
+ subi.w #MAX_DIST,Limit
+ bhi.b limit_ok
+ moveq #0,Limit
+limit_ok:
+ cmp.l _good_match,Best_Len
+ bcs.b length_ok
+ lsr.l #2,Chain_Length
+length_ok:
+ subq.l #1,Chain_Length
+
+.ifdef UNALIGNED_OK
+ move.w -MIN_MATCH(Scan_Ini),Scan_Start
+ move.w -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+.else
+ move.b -MIN_MATCH(Scan_Ini),Scan_Start
+ lsl.w #8,Scan_Start
+ move.b -MIN_MATCH+1(Scan_Ini),Scan_Start
+ move.b -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+ lsl.w #8,Scan_End
+ move.b -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
+.endif
+
+ bra.b do_scan
+
+long_loop:
+
+.ifdef UNALIGNED_OK
+ move.w -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+.else
+ move.b -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
+ lsl.w #8,Scan_End
+ move.b -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
+.endif
+
+short_loop:
+ lsl.w #1,Cur_Match
+ move.w 0(Prev_Address,Cur_Match.l),Cur_Match
+ cmp.w Limit,Cur_Match
+ dbls Chain_Length,do_scan
+ bra.b return
+
+do_scan:
+ move.l Match_Ini,Match
+ add.l Cur_Match,Match
+
+.ifdef UNALIGNED_OK
+ cmp.w -MIN_MATCH-1(Match,Best_Len.w),Scan_End
+ bne.b short_loop
+ cmp.w -MIN_MATCH(Match),Scan_Start
+ bne.b short_loop
+.else
+ move.b -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
+ lsl.w #8,Scan_Test
+ move.b -MIN_MATCH(Match,Best_Len.w),Scan_Test
+ cmp.w Scan_Test,Scan_End
+ bne.b short_loop
+ move.b -MIN_MATCH(Match),Scan_Test
+ lsl.w #8,Scan_Test
+ move.b -MIN_MATCH+1(Match),Scan_Test
+ cmp.w Scan_Test,Scan_Start
+ bne.b short_loop
+.endif
+
+ move.w #(MAX_MATCH-MIN_MATCH),Loop_Counter
+ move.l Scan_Ini,Scan
+scan_loop:
+ cmpm.b (Match)+,(Scan)+
+ dbne Loop_Counter,scan_loop
+
+ sub.l Scan_Ini,Scan
+ addq.l #(MIN_MATCH-1),Scan
+ cmp.l Best_Len,Scan
+ bls.b short_loop
+ move.l Scan,Best_Len
+ move.l Cur_Match,_match_start
+ cmp.l _nice_match,Best_Len
+ bcs.b long_loop
+return:
+ move.l Best_Len,d0
+.ifdef UNALIGNED_OK
+ movem.l (sp)+,d2-d6/a2-a4
+.else
+ movem.l (sp)+,d2-d7/a2-a4
+.endif
+ rts
+
+ end
diff --git a/human68k/osdep.h b/human68k/osdep.h
new file mode 100644
index 0000000..088a9ac
--- /dev/null
+++ b/human68k/osdep.h
@@ -0,0 +1,28 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/xglob.h>
+
+#ifdef ZCRYPT_INTERNAL
+# include <process.h> /* getpid() declaration for srand seed */
+#endif
+
+#define USE_CASE_MAP
+
+#define ROUNDED_TIME(time) (((time) + 1) & (~1))
+
+#define PROCNAME(n) (action == ADD || action == UPDATE ? wild(n) : \
+ procname(n, 1))
+
+#ifdef HAVE_MBCTYPE_H
+# include <mbctype.h>
+#else
+# define ismbblead(c) (0x80 <= (c) && ((c) < 0xa0 || 0xe0 <= (c)))
+#endif
diff --git a/human68k/zipup.h b/human68k/zipup.h
new file mode 100644
index 0000000..592cff8
--- /dev/null
+++ b/human68k/zipup.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 1990-1999 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 1999-Oct-05 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, both of these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.cdrom.com/pub/infozip/license.html
+*/
+#define fhow (O_RDONLY|O_BINARY)
+#define fbad (-1)
+typedef int ftype;
+#define zopen(n,p) open(n,p)
+#define zread(f,b,n) read(f,b,n)
+#define zclose(f) close(f)
+#define zerr(f) (k == (extent)(-1L))
+#define zstdin 0