From 912a4526fe173981417f4b36598cf9069c9b2bf0 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Thu, 19 Apr 2018 13:41:14 -0700 Subject: [PATCH] LZ4 unpack library and sample lz4cat --- src/inc/lz4.plh | 3 + src/libsrc/lz4.pla | 91 ++++++++++++++++++++++ src/makefile | 15 ++-- src/mkrel | 5 +- src/samplesrc/lz4.pla | 161 --------------------------------------- src/samplesrc/lz4cat.pla | 107 ++++++++++++++++++++++++++ 6 files changed, 215 insertions(+), 167 deletions(-) create mode 100644 src/inc/lz4.plh create mode 100644 src/libsrc/lz4.pla delete mode 100644 src/samplesrc/lz4.pla create mode 100644 src/samplesrc/lz4cat.pla diff --git a/src/inc/lz4.plh b/src/inc/lz4.plh new file mode 100644 index 0000000..502b86e --- /dev/null +++ b/src/inc/lz4.plh @@ -0,0 +1,3 @@ +import lz4 + predef lz4Unpack(seq, seqend, buff, buffend) +end diff --git a/src/libsrc/lz4.pla b/src/libsrc/lz4.pla new file mode 100644 index 0000000..16bf29c --- /dev/null +++ b/src/libsrc/lz4.pla @@ -0,0 +1,91 @@ +include "inc/cmdsys.plh" +asm incs + !SOURCE "vmsrc/plvmzp.inc" +end +// +// Always forward copy memory - important for overlapping match sequences +// +asm bcpy(dst, src, len)#0 + INX + INX + INX + LDA ESTKL-3,X + ORA ESTKH-3,X + BEQ CPYEX + LDA ESTKL-1,X + STA DSTL + LDA ESTKH-1,X + STA DSTH + LDA ESTKL-2,X + STA SRCL + LDA ESTKH-2,X + STA SRCH + LDY ESTKL-3,X + BEQ CPYLP + INC ESTKH-3,X + LDY #$00 +CPYLP LDA (SRC),Y + STA (DST),Y + INY + BNE + + INC DSTH + INC SRCH ++ DEC ESTKL-3,X + BNE CPYLP + DEC ESTKH-3,X + BNE CPYLP +CPYEX RTS +end +// +// Unpack LZ4 sequence into buffer, return unpacked length +// +export def lz4Unpack(seq, seqend, buff, buffend) + word data, len, match, i + byte token + + data = buff + while isult(seq, seqend) + token = ^seq + seq++ + len = token >> 4 + if len + // + // Literal sequence + // + if len == 15 + while ^seq == 255 + len = len + 255 + seq++ + loop + len = len + ^seq + seq++ + fin + if isuge(data + len, buffend); return 0; fin + bcpy(data, seq, len) + data = data + len + seq = seq + len + fin + len = token & $0F + if len or isult(seq, seqend) + // + // Match sequence + // + match = data - *seq + seq = seq + 2 + len = len + 4 + if len == 19 // $0F + 4 + while ^seq == 255 + len = len + 255 + seq++ + loop + len = len + ^seq + seq++ + fin + if isuge(data + len, buffend); return 0; fin + bcpy(data, match, len) + data = data + len + fin + loop + return data - buff +end +done diff --git a/src/makefile b/src/makefile index 985ce19..b48cc6d 100755 --- a/src/makefile +++ b/src/makefile @@ -36,7 +36,8 @@ SNDSEQ = rel/apple/SNDSEQ\#FE1000 PLAYSEQ = rel/apple/PLAYSEQ\#FE1000 SANITY = rel/SANITY\#FE1000 RPNCALC = rel/RPNCALC\#FE1000 -LZ4DECOMP = rel/LZ4DECOMP\#FE1000 +LZ4 = rel/LZ4\#FE1000 +LZ4CAT = rel/LZ4CAT\#FE1000 UTHERNET2 = rel/apple/UTHERNET2\#FE1000 UTHERNET = rel/apple/UTHERNET\#FE1000 ETHERIP = rel/ETHERIP\#FE1000 @@ -82,7 +83,7 @@ TXTTYPE = .TXT #SYSTYPE = \#FF2000 #TXTTYPE = \#040000 -apple: $(PLVMZP_APL) $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVMJIT) $(PLVM802) $(PLVM03) $(CMD) $(CMDJIT) $(JIT) $(JIT16) $(JITUNE) $(SOSCMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(FIBERTEST) $(LONGJMP) $(ED) $(MON) $(SOS) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(GRAFIX) $(GFXDEMO) $(DGR) $(DGRTEST) $(FILEIO_APL) $(CONIO_APL) $(JOYBUZZ) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(LZ4DECOMP) $(RPNCALC) $(SNDSEQ) $(PLAYSEQ) +apple: $(PLVMZP_APL) $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVMJIT) $(PLVM802) $(PLVM03) $(CMD) $(CMDJIT) $(JIT) $(JIT16) $(JITUNE) $(SOSCMD) $(PLASMAPLASM) $(CODEOPT) $(ARGS) $(MEMMGR) $(MEMTEST) $(FIBER) $(FIBERTEST) $(LONGJMP) $(ED) $(MON) $(SOS) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(GRAFIX) $(GFXDEMO) $(DGR) $(DGRTEST) $(FILEIO_APL) $(CONIO_APL) $(JOYBUZZ) $(PORTIO) $(SPIPORT) $(SDFAT) $(FATCAT) $(FATGET) $(FATPUT) $(FATWDSK) $(FATRDSK) $(SANE) $(FPSTR) $(FPU) $(SANITY) $(LZ4) $(LZ4CAT) $(RPNCALC) $(SNDSEQ) $(PLAYSEQ) -rm vmsrc/plvmzp.inc c64: $(PLVMZP_C64) $(PLASM) $(PLVM) $(PLVMC64) @@ -256,9 +257,13 @@ $(SANITY): samplesrc/sanity.pla $(PLVM02) $(PLASM) ./$(PLASM) -AMOW < samplesrc/sanity.pla > samplesrc/sanity.a acme --setpc 4094 -o $(SANITY) samplesrc/sanity.a -$(LZ4DECOMP): samplesrc/lz4.pla $(PLVM02) $(PLASM) - ./$(PLASM) -AMOW < samplesrc/lz4.pla > samplesrc/lz4.a - acme --setpc 4094 -o $(LZ4DECOMP) samplesrc/lz4.a +$(LZ4): libsrc/lz4.pla $(PLVM02) $(PLASM) + ./$(PLASM) -AMOW < libsrc/lz4.pla > libsrc/lz4.a + acme --setpc 4094 -o $(LZ4) libsrc/lz4.a + +$(LZ4CAT): samplesrc/lz4cat.pla inc/lz4.plh $(PLVM02) $(PLASM) + ./$(PLASM) -AMOW < samplesrc/lz4cat.pla > samplesrc/lz4cat.a + acme --setpc 4094 -o $(LZ4CAT) samplesrc/lz4cat.a $(RPNCALC): samplesrc/rpncalc.pla libsrc/fpu.pla inc/fpu.plh libsrc/fpstr.pla inc/fpstr.plh inc/conio.plh $(PLVM02) $(PLASM) ./$(PLASM) -AMOW < samplesrc/rpncalc.pla > samplesrc/rpncalc.a diff --git a/src/mkrel b/src/mkrel index 8702feb..7b937bb 100755 --- a/src/mkrel +++ b/src/mkrel @@ -33,6 +33,7 @@ cp rel/FPU#FE1000 prodos/sys/FPU.REL cp rel/SANE#FE1000 prodos/sys/SANE.REL cp ../sysfiles/FP6502.CODE#060000 prodos/sys/FP6502.CODE.BIN cp ../sysfiles/ELEMS.CODE#060000 prodos/sys/ELEMS.CODE.BIN +cp rel/LZ4#FE1000 prodos/sys/LZ4.REL rm -rf prodos/sos mkdir prodos/sos @@ -47,7 +48,7 @@ rm -rf prodos/demos mkdir prodos/demos cp rel/apple/DGRTEST#FE1000 prodos/demos/DGRTEST.REL cp rel/RPNCALC#FE1000 prodos/demos/RPNCALC.REL -cp rel/LZ4DECOMP#FE1000 prodos/demos/LZ4DECOMP.REL +cp rel/LZ4CAT#FE1000 prodos/demos/LZ4CAT.REL cp rel/ROD#FE1000 prodos/demos/ROD.REL mkdir prodos/demos/rogue @@ -99,6 +100,7 @@ cp samplesrc/rogue.pla prodos/bld/ROGUE.PLA.TXT cp samplesrc/rogue.map.pla prodos/bld/ROGUE.MAP.PLA.TXT cp samplesrc/rogue.combat.pla prodos/bld/ROGUE.COMBAT.PLA.TXT cp samplesrc/gfxdemo.pla prodos/bld/GFXDEMO.PLA.TXT +cp samplesrc/lz4cat.pla prodos/bld/LZ4CAT.PLA.TXT mkdir prodos/bld/inc cp inc/args.plh prodos/bld/inc/ARGS.PLH.TXT @@ -120,4 +122,5 @@ cp inc/sndseq.plh prodos/bld/inc/SNDSEQ.PLH.TXT cp inc/spiport.plh prodos/bld/inc/SPIPORT.PLH.TXT cp inc/testlib.plh prodos/bld/inc/TESTLIB.PLH.TXT cp inc/grafix.plh prodos/bld/inc/GRAFIX.PLH.TXT +cp inc/lz4.plh prodos/bld/inc/LZ4.PLH.TXT cp vmsrc/apple/plvmzp.inc prodos/bld/inc/PLVMZP.INC.TXT diff --git a/src/samplesrc/lz4.pla b/src/samplesrc/lz4.pla deleted file mode 100644 index aebc459..0000000 --- a/src/samplesrc/lz4.pla +++ /dev/null @@ -1,161 +0,0 @@ -include "inc/cmdsys.plh" -include "inc/args.plh" -include "inc/fileio.plh" - -struc t_header - word magic[2] - byte FLG - byte BD -end -word arg -byte ref - -def dump(addr, len)#0 - while len - putc(^addr == $0A ?? $0D :: ^addr) - addr++ - len-- - loop -end -def lz4Decomp(seq, seqend)#2 - word buff, data, len, offset, fill - byte token - - buff = heapalloc(heapavail - 256) - data = buff - if not buff - return NULL, 0 - fin - while seq < seqend - //puts("LZ4 sequence @ $"); puth(seq); putln - token = ^seq - seq++ - len = token >> 4 - if len - // - // Literal sequence - // - if len == 15 - while ^seq == 255 - len = len + 255 - seq++ - loop - len = len + ^seq - seq++ - fin - //puts("Literals @ $"); puth(seq); puts(", len $"); puth(len); putln; getc - dump(seq, len) - memcpy(data, seq, len) - data = data + len - seq = seq + len - fin - // - // Match sequence - // - offset = *seq - seq = seq + 2 - len = (token & $0F) + 4 - if len == 19 // $0F + 4 - while ^seq == 255 - len = len + 255 - seq++ - loop - len = len + ^seq - seq++ - fin - //puts("Match offset $"); puth(offset); puts(" @ $"); puth(data - offset); puts(", len $"); puth(len); putln; getc - while len > offset - memcpy(data, data - offset, offset) - dump(data, offset) - data = data + offset - len = len - offset - loop - memcpy(data, data - offset, len) - dump(data, len) - data = data + len - loop - return buff, data - buff -end - -def lz4ReadBlock(flags)#2 - word size[2], block, data, len - - fileio:read(ref, @size, 4) - if size[1] & $7FFF - return NULL, 0 - fin - block = heapalloc(size[0]) - if block - fileio:read(ref, block, size[0]) - else - return NULL, 0 - fin - if size[1] & $8000 - // - // Uncompressed block - // - data = block - //puts("Uncompressed data @ $"); puth(data); putln - else - // - // Decompress block - // - //puts("Compressed block @ $"); puth(block); putln - data, len = lz4Decomp(block, block + size[0]) - //puts("Uncompressed data @ $"); puth(data); putln - if data - memcpy(block, data, len) - data = block - fin - heaprelease(block + len) - fin - if flags & $10 // Block Checksum - fileio:read(ref, @size, 4) - fin - return data, len -end - -def lz4ReadFrame#0 - word data, len - byte header[t_header], opt - - fileio:read(ref, @header, t_header) - if header:magic[1] <> $184D or header:magic[0] <> $2204 - puts("Not LZ4 file.\n") - return - fin - if header.FLG & $C0 <> $40 - puts("Wrong LZ4 version.\n") - return - fin - if header.BD & $70 <> $40 - puts("Not 64K block size.\n") - return - fin - opt = 1 - if header.FLG & $08 // Content Size - opt = opt + 8 - fin - if header.FLG & $01 // Dictionary ID - opt = opt + 4 - fin - fileio:read(ref, heapmark, opt) // Read rest of header and throw away - repeat - data, len = lz4ReadBlock(header.FLG) - until not data - if header.FLG & $04 // Content Checksun - fileio:read(ref, heapmark, 4) - fin -end -arg = argNext(argFirst) -if ^arg - ref = fileio:open(arg) - if ref - lz4ReadFrame - fileio:close(ref) - else - puts("File not found.\n") - fin -fin - -done diff --git a/src/samplesrc/lz4cat.pla b/src/samplesrc/lz4cat.pla new file mode 100644 index 0000000..ca5a59a --- /dev/null +++ b/src/samplesrc/lz4cat.pla @@ -0,0 +1,107 @@ +include "inc/cmdsys.plh" +include "inc/args.plh" +include "inc/fileio.plh" +include "inc/lz4.plh" + +struc t_header + word magic[2] + byte FLG + byte BD +end +word arg +byte ref + +def lz4ReadBlock(flags)#2 + word size[2], block, data, len + + len = fileio:read(ref, @size, 4) + if len <> 4 or size[0] == 0 or size[1] & $7FFF + return NULL, 0 + fin + block = heapalloc(size[0]) + if block + len = fileio:read(ref, block, size[0]) + if len <> size[0] + heaprelease(block) + return NULL, 0 + fin + else + return NULL, 0 + fin + if size[1] & $8000 + // + // Uncompressed block + // + data = block + else + // + // Decompress block + // + len = heapavail - 256 // Allocate almost entire heap to decompress into + data = heapalloc(len) + if data + len = lz4Unpack(block, block + size[0], data, data + len) + memcpy(block, data, len) + data = block + else + len = 0 + fin + heaprelease(block + len) + fin + if flags & $10 // Block Checksum + fileio:read(ref, @size, 4) + fin + return data, len +end +def lz4ReadFrame#0 + word data, len + byte header[t_header], opt + + fileio:read(ref, @header, t_header) + if header:magic[1] <> $184D or header:magic[0] <> $2204 + puts("Not LZ4 file.\n") + return + fin + if header.FLG & $C0 <> $40 + puts("Wrong LZ4 version.\n") + return + fin + if header.BD & $70 <> $40 + puts("Not 64K block size.\n") + return + fin + opt = 1 + if header.FLG & $08 // Content Size + opt = opt + 8 + fin + if header.FLG & $01 // Dictionary ID + opt = opt + 4 + fin + fileio:read(ref, heapmark, opt) // Read rest of header and throw away + repeat + data, len = lz4ReadBlock(header.FLG) + if len + while len + putc(^data <> $0A ?? ^data :: $0D) + data++ + len-- + loop + heaprelease(data) + fin + until not data + if header.FLG & $04 // Content Checksun + fileio:read(ref, heapmark, 4) + fin +end +arg = argNext(argFirst) +if ^arg + ref = fileio:open(arg) + if ref + lz4ReadFrame + fileio:close(ref) + else + puts("File not found.\n") + fin +fin + +done