diff options
author | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-07-20 19:30:57 +0100 |
---|---|---|
committer | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-07-20 19:30:57 +0100 |
commit | 04664087ad66f5614f82a2cfba3ae4eda15e792b (patch) | |
tree | 332090b15fd2db1b93abf40dccf06211d9aba297 /human68k | |
download | zip-04664087ad66f5614f82a2cfba3ae4eda15e792b.tar.gz |
Tarball conversion
Diffstat (limited to 'human68k')
-rw-r--r-- | human68k/Makefile | 95 | ||||
-rw-r--r-- | human68k/Makefile.gcc | 78 | ||||
-rw-r--r-- | human68k/crc_68.s | 144 | ||||
-rw-r--r-- | human68k/deflate.s | 1076 | ||||
-rw-r--r-- | human68k/human68k.c | 371 | ||||
-rw-r--r-- | human68k/match.s | 163 | ||||
-rw-r--r-- | human68k/osdep.h | 28 | ||||
-rw-r--r-- | human68k/zipup.h | 16 |
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 |