Skip to content
Permalink
Browse files

Support backward decompression

  • Loading branch information
emmanuel-marty committed Jul 24, 2019
1 parent 0c4dbf2 commit 4835e4c26c4429c80932d204f03b6cc6c9ee8389
@@ -7,6 +7,18 @@
;
; out:
; * LZSA_DST_LO and LZSA_DST_HI contain the last decompressed byte address, +1
;
; -----------------------------------------------------------------------------
; Backward decompression is also supported, use lzsa -r -b <original_file> <compressed_file>
; To use it, also define BACKWARD_DECOMPRESS=1 before including this code!
;
; in:
; * LZSA_SRC_LO/LZSA_SRC_HI must contain the address of the last byte of compressed data
; * LZSA_DST_LO/LZSA_DST_HI must contain the address of the last byte of the destination buffer
;
; out:
; * LZSA_DST_LO/LZSA_DST_HI contain the last decompressed byte address, -1
;
; -----------------------------------------------------------------------------
;
; Copyright (C) 2019 Emmanuel Marty
@@ -96,11 +108,29 @@ PREPARE_COPY_MATCH_Y

COPY_MATCH_LOOP
LDA $AAAA ; get one byte of backreference
JSR PUTDST ; copy to destination

ifdef BACKWARD_DECOMPRESS

; Backward decompression -- put backreference bytes backward

LDA COPY_MATCH_LOOP+1
BNE GETMATCH_DONE
DEC COPY_MATCH_LOOP+2
GETMATCH_DONE
DEC COPY_MATCH_LOOP+1

else

; Forward decompression -- put backreference bytes forward

INC COPY_MATCH_LOOP+1
BNE GETMATCH_DONE
INC COPY_MATCH_LOOP+2
GETMATCH_DONE
JSR PUTDST ; copy to destination

endif

DEX
BNE COPY_MATCH_LOOP
DEY
@@ -111,6 +141,29 @@ GET_LONG_OFFSET ; handle 16 bit offset:
JSR GETLARGESRC ; grab low 8 bits in X, high 8 bits in A

GOT_OFFSET

ifdef BACKWARD_DECOMPRESS

; Backward decompression - substract match offset

STA OFFSHI ; store high 8 bits of offset
STX OFFSLO

SEC ; substract dest - match offset
LDA PUTDST+1
OFFSLO = *+1
SBC #$AA ; low 8 bits
STA COPY_MATCH_LOOP+1 ; store back reference address
LDA PUTDST+2
OFFSHI = *+1
SBC #$AA ; high 8 bits
STA COPY_MATCH_LOOP+2 ; store high 8 bits of address
SEC

else

; Forward decompression - add match offset

STA OFFSHI ; store high 8 bits of offset
TXA

@@ -123,6 +176,8 @@ OFFSHI = *+1
ADC PUTDST+2
STA COPY_MATCH_LOOP+2 ; store high 8 bits of address
endif

PLA ; retrieve token from stack again
AND #$0F ; isolate match len (MMMM)
ADC #$02 ; plus carry which is always set by the high ADC
@@ -145,6 +200,45 @@ OFFSHI = *+1
DECOMPRESSION_DONE
RTS

ifdef BACKWARD_DECOMPRESS

; Backward decompression -- get and put bytes backward

GETPUT
JSR GETSRC
PUTDST
LZSA_DST_LO = *+1
LZSA_DST_HI = *+2
STA $AAAA
LDA PUTDST+1
BNE PUTDST_DONE
DEC PUTDST+2
PUTDST_DONE
DEC PUTDST+1
RTS

GETLARGESRC
JSR GETSRC ; grab low 8 bits
TAX ; move to X
; fall through grab high 8 bits

GETSRC
LZSA_SRC_LO = *+1
LZSA_SRC_HI = *+2
LDA $AAAA
PHA
LDA GETSRC+1
BNE GETSRC_DONE
DEC GETSRC+2
GETSRC_DONE
DEC GETSRC+1
PLA
RTS

else

; Forward decompression -- get and put bytes forward

GETPUT
JSR GETSRC
PUTDST
@@ -171,3 +265,5 @@ LZSA_SRC_HI = *+2
INC GETSRC+2
GETSRC_DONE
RTS

endif
@@ -8,6 +8,18 @@
;
; out:
; * LZSA_DST_LO and LZSA_DST_HI contain the last decompressed byte address, +1
;
; -----------------------------------------------------------------------------
; Backward decompression is also supported, use lzsa -r -b -f2 <original_file> <compressed_file>
; To use it, also define BACKWARD_DECOMPRESS=1 before including this code!
;
; in:
; * LZSA_SRC_LO/LZSA_SRC_HI must contain the address of the last byte of compressed data
; * LZSA_DST_LO/LZSA_DST_HI must contain the address of the last byte of the destination buffer
;
; out:
; * LZSA_DST_LO/LZSA_DST_HI contain the last decompressed byte address, -1
;
; -----------------------------------------------------------------------------
;
; Copyright (C) 2019 Emmanuel Marty
@@ -130,6 +142,25 @@ GOT_OFFSET_LO
STX OFFSHI ; store high byte of match offset

REP_MATCH
ifdef BACKWARD_DECOMPRESS

; Backward decompression - substract match offset

SEC ; add dest + match offset
LDA PUTDST+1 ; low 8 bits
OFFSLO = *+1
SBC #$AA
STA COPY_MATCH_LOOP+1 ; store back reference address
LDA PUTDST+2
OFFSHI = *+1
SBC #$AA ; high 8 bits
STA COPY_MATCH_LOOP+2 ; store high 8 bits of address
SEC

else

; Forward decompression - add match offset

CLC ; add dest + match offset
LDA PUTDST+1 ; low 8 bits
OFFSLO = *+1
@@ -140,6 +171,8 @@ OFFSHI = *+1
ADC PUTDST+2
STA COPY_MATCH_LOOP+2 ; store high 8 bits of address
endif
PLA ; retrieve token from stack again
AND #$07 ; isolate match len (MMM)
ADC #$01 ; add MIN_MATCH_SIZE_V2 and carry
@@ -173,11 +206,29 @@ PREPARE_COPY_MATCH_Y

COPY_MATCH_LOOP
LDA $AAAA ; get one byte of backreference
JSR PUTDST ; copy to destination

ifdef BACKWARD_DECOMPRESS

; Backward decompression -- put backreference bytes backward

LDA COPY_MATCH_LOOP+1
BNE GETMATCH_DONE
DEC COPY_MATCH_LOOP+2
GETMATCH_DONE
DEC COPY_MATCH_LOOP+1

else

; Forward decompression -- put backreference bytes forward

INC COPY_MATCH_LOOP+1
BNE GETMATCH_DONE
INC COPY_MATCH_LOOP+2
GETMATCH_DONE
JSR PUTDST ; copy to destination

endif

DEX
BNE COPY_MATCH_LOOP
DEY
@@ -215,6 +266,45 @@ HAS_NIBBLES
AND #$0F ; isolate low 4 bits of nibble
RTS

ifdef BACKWARD_DECOMPRESS

; Backward decompression -- get and put bytes backward

GETPUT
JSR GETSRC
PUTDST
LZSA_DST_LO = *+1
LZSA_DST_HI = *+2
STA $AAAA
LDA PUTDST+1
BNE PUTDST_DONE
DEC PUTDST+2
PUTDST_DONE
DEC PUTDST+1
RTS

GETLARGESRC
JSR GETSRC ; grab low 8 bits
TAX ; move to X
; fall through grab high 8 bits

GETSRC
LZSA_SRC_LO = *+1
LZSA_SRC_HI = *+2
LDA $AAAA
PHA
LDA GETSRC+1
BNE GETSRC_DONE
DEC GETSRC+2
GETSRC_DONE
DEC GETSRC+1
PLA
RTS

else

; Forward decompression -- get and put bytes forward

GETPUT
JSR GETSRC
PUTDST
@@ -241,3 +331,5 @@ LZSA_SRC_HI = *+2
INC GETSRC+2
GETSRC_DONE
RTS

endif
@@ -35,6 +35,7 @@
#include "expand_context.h"
#include "expand_block_v1.h"
#include "expand_block_v2.h"
#include "lib.h"

/**
* Decompress one data block
@@ -45,14 +46,31 @@
* @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes)
* @param nBlockMaxSize total size of output decompression buffer, in bytes
* @param nFormatVersion version of format to use (1-2)
* @param nFlags compression flags (LZSA_FLAG_xxx)
*
* @return size of decompressed data in bytes, or -1 for error
*/
int lzsa_decompressor_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion) {
int lzsa_decompressor_expand_block(unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion, const int nFlags) {
int nDecompressedSize;

if (nFlags & LZSA_FLAG_RAW_BACKWARD) {
lzsa_reverse_buffer(pInBlock, nBlockSize);
}

if (nFormatVersion == 1)
return lzsa_decompressor_expand_block_v1(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize);
nDecompressedSize = lzsa_decompressor_expand_block_v1(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize);
else if (nFormatVersion == 2)
return lzsa_decompressor_expand_block_v2(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize);
nDecompressedSize = lzsa_decompressor_expand_block_v2(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize);
else
return -1;
nDecompressedSize = -1;

if (nDecompressedSize != -1 && (nFlags & LZSA_FLAG_RAW_BACKWARD)) {
lzsa_reverse_buffer(pOutData + nOutDataOffset, nDecompressedSize);
}

if (nFlags & LZSA_FLAG_RAW_BACKWARD) {
lzsa_reverse_buffer(pInBlock, nBlockSize);
}

return nDecompressedSize;
}
@@ -48,10 +48,11 @@ extern "C" {
* @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes)
* @param nBlockMaxSize total size of output decompression buffer, in bytes
* @param nFormatVersion version of format to use (1-2)
* @param nFlags compression flags (LZSA_FLAG_xxx)
*
* @return size of decompressed data in bytes, or -1 for error
*/
int lzsa_decompressor_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion);
int lzsa_decompressor_expand_block(unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion, const int nFlags);

#ifdef __cplusplus
}
@@ -98,16 +98,16 @@ size_t lzsa_get_max_decompressed_size_inmem(const unsigned char *pFileData, size
*
* @return actual decompressed size, or -1 for error
*/
size_t lzsa_decompress_inmem(const unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion) {
const unsigned char *pCurFileData = pFileData;
size_t lzsa_decompress_inmem(unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion) {
unsigned char *pCurFileData = pFileData;
const unsigned char *pEndFileData = pCurFileData + nFileSize;
unsigned char *pCurOutBuffer = pOutBuffer;
const unsigned char *pEndOutBuffer = pCurOutBuffer + nMaxOutBufferSize;
int nPreviousBlockSize;
const int nHeaderSize = lzsa_get_header_size();

if (nFlags & LZSA_FLAG_RAW_BLOCK) {
return (size_t)lzsa_decompressor_expand_block(pFileData, (int)nFileSize, pOutBuffer, 0, (int)nMaxOutBufferSize, *pFormatVersion);
return (size_t)lzsa_decompressor_expand_block(pFileData, (int)nFileSize, pOutBuffer, 0, (int)nMaxOutBufferSize, *pFormatVersion, nFlags);
}

/* Check header */
@@ -139,7 +139,7 @@ size_t lzsa_decompress_inmem(const unsigned char *pFileData, unsigned char *pOut
if ((pCurFileData + nBlockDataSize) > pEndFileData)
return -1;

nDecompressedSize = lzsa_decompressor_expand_block(pCurFileData, nBlockDataSize, pCurOutBuffer - nPreviousBlockSize, nPreviousBlockSize, (int)(pEndOutBuffer - pCurOutBuffer + nPreviousBlockSize), *pFormatVersion);
nDecompressedSize = lzsa_decompressor_expand_block(pCurFileData, nBlockDataSize, pCurOutBuffer - nPreviousBlockSize, nPreviousBlockSize, (int)(pEndOutBuffer - pCurOutBuffer + nPreviousBlockSize), *pFormatVersion, nFlags);
if (nDecompressedSize < 0)
return -1;

@@ -61,7 +61,7 @@ size_t lzsa_get_max_decompressed_size_inmem(const unsigned char *pFileData, size
*
* @return actual decompressed size, or -1 for error
*/
size_t lzsa_decompress_inmem(const unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion);
size_t lzsa_decompress_inmem(unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion);

#ifdef __cplusplus
}
@@ -196,7 +196,7 @@ lzsa_status_t lzsa_decompress_stream(lzsa_stream_t *pInStream, lzsa_stream_t *pO
nDecompressedSize = nBlockSize;
}
else {
nDecompressedSize = lzsa_decompressor_expand_block(pInBlock, nBlockSize, pOutData, BLOCK_SIZE, BLOCK_SIZE, nFormatVersion);
nDecompressedSize = lzsa_decompressor_expand_block(pInBlock, nBlockSize, pOutData, BLOCK_SIZE, BLOCK_SIZE, nFormatVersion, nFlags);
if (nDecompressedSize < 0) {
nDecompressionError = LZSA_ERROR_DECOMPRESSION;
break;

0 comments on commit 4835e4c

Please sign in to comment.
You can’t perform that action at this time.