Created
January 7, 2020 17:46
-
-
Save odzhan/fb0602b66325b01b85585d8691fa2781 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/stat.h> | |
#include <inttypes.h> | |
#include <fcntl.h> | |
#ifdef TEST | |
#if defined(_WIN32) || defined(_WIN64) | |
#define WINDOWS | |
#include <windows.h> | |
#include "mmap.h" | |
#if defined(_MSC_VER) | |
#pragma comment(lib, "advapi32.lib") | |
#pragma comment(lib, "user32.lib") | |
#endif | |
#else | |
#define LINUX | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/mman.h> | |
#endif | |
#define PS *p++!=*s++ /* Body of inner unrolled matching loop. */ | |
#define ITEMMAX 16 /* Maximum number of bytes in an expanded item. */ | |
uint32_t lzrw1_compress(uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) { | |
uint8_t *in=inbuf,*out=outbuf; | |
uint8_t *p_src_post=inbuf+inlen,*p_dst_post=outbuf+inlen; | |
uint8_t *p_src_max1=p_src_post-ITEMMAX,*p_src_max16=p_src_post-16*ITEMMAX; | |
uint8_t *hash[4096]={0},*p_control; uint16_t ctrl=0,bits=0; | |
p_control=out; out+=2; | |
for(;;) { | |
uint8_t *p,*s; uint16_t unroll=16,len,index; uint32_t ofs; | |
if (out>p_dst_post) return 0; | |
if (in>p_src_max16) | |
{unroll=1; | |
if (in>p_src_max1) | |
{if (in==p_src_post) break; goto literal;}} | |
begin_unrolled_loop: | |
index=((40543*((((in[0]<<4)^in[1])<<4)^in[2]))>>4) & 0xFFF; | |
p=hash[index]; hash[index]=s=in; ofs=s-p; | |
if (ofs>4095 || p<inbuf || ofs==0 || PS || PS || PS) { | |
literal: | |
*out++=*in++; ctrl>>=1; bits++; | |
} else { | |
PS || PS || PS || PS || PS || PS || PS || | |
PS || PS || PS || PS || PS || PS || s++; | |
len=s-in-1; | |
*out++=((ofs&0xF00)>>4)+(len-1); | |
*out++=ofs&0xFF; | |
in+=len; | |
ctrl=(ctrl>>1)|0x8000; | |
bits++; | |
} | |
end_unrolled_loop: if (--unroll) goto begin_unrolled_loop; | |
if (bits==16) | |
{*p_control=ctrl&0xFF; *(p_control+1)=ctrl>>8; | |
p_control=out; out+=2; ctrl=bits=0;} | |
} | |
ctrl>>=16-bits; | |
*p_control++=ctrl&0xFF; *p_control++=ctrl>>8; | |
if (p_control==out) out-=2; | |
return (out - outbuf); | |
} | |
#endif | |
uint32_t lzrw1_decompress(void *inbuf, uint32_t inlen, void *outbuf) { | |
uint32_t bits=0, ctrl, ofs, len; | |
uint8_t *in=(uint8_t*)inbuf; | |
uint8_t *out=(uint8_t*)outbuf; | |
uint8_t *end=(uint8_t*)inbuf + inlen; | |
uint8_t *ptr, c; | |
while(in != end) { | |
// read the length | |
if(bits == 0) { | |
ctrl = (*(uint16_t*)in); | |
in += 2; | |
bits = 16; | |
} | |
// compressed block? | |
if(ctrl & 1) { | |
c = *in++; | |
// read the 4-bit length | |
len = (c & 0x0F) + 1; | |
// read the 12-bit offset | |
ofs = (c & 0xF0) << 4; | |
ofs |= *in++ & 0xFF; | |
// calculate offset | |
ptr = out - ofs; | |
// store bytes | |
while(len--) *out++ = *ptr++; | |
} else { | |
*out++ = *in++; | |
} | |
ctrl >>= 1; bits--; | |
} | |
return (out - (uint8_t*)outbuf); | |
} | |
/** | |
; LZRW1 decompressor in 64 bytes of x86 assembly | |
; odzhan | |
bits 32 | |
%ifndef BIN | |
global lzrw1_decompressx | |
global _lzrw1_decompressx | |
%endif | |
lzrw1_decompressx: | |
_lzrw1_decompressx: | |
pushad | |
lea esi, [esp+32+4] | |
lodsd | |
xchg eax, ecx ; ecx = inlen | |
lodsd | |
xchg edi, eax ; edi = outbuf | |
lodsd | |
xchg esi, eax ; esi = inbuf | |
lea ebp, [esi+ecx] ; ebp = inbuf + inlen | |
L0: | |
push 16 + 1 ; bits = 16 | |
pop edx | |
lodsw ; ctrl = *in++, ctrl |= (*in++) << 8 | |
xchg ebx, eax | |
L1: | |
; while(in != end) { | |
cmp esi, ebp | |
je L4 | |
; if(--bits == 0) goto L0 | |
dec edx | |
jz L0 | |
L2: | |
; if(ctrl & 1) { | |
shr ebx, 1 | |
jnc L3 | |
xor eax, eax | |
lodsb ; ofs = (*in & 0xF0) << 4 | |
aam 16 | |
movzx ecx, al | |
inc ecx | |
lodsb ; ofs |= *in++ & 0xFF; | |
push esi ; save pointer to in | |
mov esi, edi ; ptr = out - ofs; | |
sub esi, eax | |
rep movsb ; while(len--) *out++ = *ptr++; | |
pop esi ; restore pointer to in | |
jmp L1 | |
L3: | |
; } else { | |
movsb ; *out++ = *in++; | |
jmp L1 | |
; } | |
L4: | |
sub edi, [esp+32+8] ; edi = out - outbuf | |
mov [esp+28], edi ; esp+_eax = edi | |
popad | |
ret | |
*/ | |
uint32_t lzrw1_decompressx(uint32_t, void*, void*); | |
#ifdef TEST | |
int main(int argc, char *argv[]) { | |
struct stat fs; | |
int fd; | |
uint32_t inlen, outlen, diff, unpcklen; | |
void *inbuf, *outbuf, *unpacked; | |
char *infile, *outfile; | |
if(argc != 2) { | |
printf("usage: lzrw1 <infile>\n"); | |
return 0; | |
} | |
infile = argv[1]; | |
if(stat(infile, &fs) != 0) { | |
printf("unable to access %s\n", infile); | |
return -1; | |
} | |
// open | |
fd = open(infile, O_RDONLY); | |
if(fd < 0) { | |
printf("unable to open %s.\n", infile); | |
return -1; | |
} | |
// map input file | |
inlen = fs.st_size; | |
inbuf = mmap(NULL, inlen, PROT_READ, MAP_PRIVATE, fd, 0); | |
if(inbuf != NULL) { | |
// allocate buffer for output | |
outbuf = malloc(inlen); | |
if(outbuf != NULL) { | |
// compress data | |
outlen = lzrw1_compress(inbuf, inlen, outbuf); | |
if(outlen == 0) { | |
printf("compression failed.\n"); | |
} else { | |
// show the ratio | |
diff = ((float)(inlen - outlen) / (float)inlen) * 100; | |
printf("oiginal size: %"PRId32"\n" | |
"packed size: %"PRId32"\n" | |
"reduced by %"PRId32"%%\n", inlen, outlen, diff); | |
// decompress | |
unpacked = malloc(inlen); | |
unpcklen = lzrw1_decompressx(outlen, unpacked, outbuf); | |
// show the ratio | |
diff = ((float)(unpcklen - outlen) / (float)unpcklen) * 100; | |
printf("\npacked size: %"PRId32"\n" | |
"unpacked size: %"PRId32"\n" | |
"increased by %"PRId32"%%\n", outlen, unpcklen, diff); | |
free(unpacked); | |
} | |
free(outbuf); | |
} else { | |
printf("malloc() failed.\n", infile); | |
} | |
munmap(inbuf, inlen); | |
} else { | |
printf("mmap() failed.\n"); | |
} | |
close(fd); | |
return 0; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment