Better build script

This commit is contained in:
neauoire 2023-11-15 14:46:18 -08:00
parent 88b3e33676
commit b6049f7212
4 changed files with 144 additions and 197 deletions

View File

@ -14,26 +14,32 @@ then
clang-format -i ulzcdec.c clang-format -i ulzcdec.c
fi fi
# Make c file # Building
cc lz_main.c -o main && ./main && ./main # read example.txt, write compressed.bin cc lz_main.c -o main
cc ulzdec.c -o ulzdec
$ASM ulzdec.tal ulzdec.rom
# Decoding # Make compressed file
$ASM decoder.tal decoder.rom ./main && ./main # read example.txt, write compressed.bin
uxncli decoder.rom compressed.bin decompressed.txt
# C Decoder
echo ""
echo "C Decoder"
echo ""
./ulzdec compressed.bin
# Uxn Decoding
echo ""
echo "Uxn Decoder"
echo ""
uxncli ulzdec.rom compressed.bin decompressed.txt && cat decompressed.txt
rm ./main rm ./main
rm ./ulzdec
rm ./compressed.bin rm ./compressed.bin
rm ./decompressed.txt rm ./decompressed.txt
rm ./ulzdec.rom
# Encoding
$ASM encoder.tal encoder.rom
uxncli encoder.rom example-small.txt recompressed.bin
# Redecoding
uxncli decoder.rom recompressed.bin redecoded.txt
cat redecoded.txt

View File

@ -1,180 +0,0 @@
#include "uxn_lz.h"
enum { MinMatchLength = 4 };
int
uxn_lz_compress(void *output, int output_size, const void *input, int input_size)
{
int dict_len, match_len, i, string_len, match_ctl;
unsigned char *out = output, *combine = 0;
const unsigned char *dict, *dict_best = 0, *in = input, *start = in, *end = in + input_size;
while (in != end)
{
dict_len = (int)(in - start); /* Get available dictionary size (history of original output) */
if (dict_len > 256) dict_len = 256; /* Limit history lookback to 256 bytes */
dict = in - dict_len; /* Start of dictionary */
string_len = (int)(end - in); /* Size of the string to search for */
if (string_len > 0x3FFF + MinMatchLength) string_len = 0x3FFF + MinMatchLength;
/* ^ Limit string length to what we can fit in 14 bits, plus the minimum match length */
match_len = 0; /* This will hold the length of our best match */
for (; dict_len; dict += 1, dict_len -= 1) /* Iterate through the dictionary */
{
for (i = 0;; i++) /* Find common prefix length with the string */
{
if (i == string_len) { match_len = i; dict_best = dict; goto done_search; }
/* ^ If we reach the end of the string, this is the best possible match. End. */
if (in[i] != dict[i % dict_len]) break; /* Dictionary repeats if we hit the end */
}
if (i > match_len) { match_len = i; dict_best = dict; }
}
done_search:
if (match_len >= MinMatchLength) /* Long enough? Use dictionary match */
{
if ((output_size -= 2) < 0) goto overflow;
match_ctl = match_len - MinMatchLength; /* More numeric range: treat 0 as 4, 1 as 5, etc. */
if (match_ctl > 0x3F) /* Match is long enough to use 2 bytes for the size */
{
if ((output_size -= 1) < 0) goto overflow;
*out++ = match_ctl >> 8 | 0x40 | 0x80; /* High byte of the size, with both flags set */
*out++ = match_ctl; /* Low byte of the size */
}
else /* Use 1 byte for the size */
{
*out++ = match_ctl | 0x80; /* Set the "dictionary" flag */
}
*out++ = in - dict_best - 1; /* Write offset into history. (0 is -1, 1 is -2, ...) */
in += match_len; /* Advance input by size of the match */
combine = 0; /* Disable combining previous literal, if any */
continue;
}
if (combine) /* Combine with previous literal */
{
if ((output_size -= 1) < 0) goto overflow;
if (++*combine == 127) combine = 0; /* If the literal hits its size limit, terminate it. */
}
else /* Start a new literal */
{
if ((output_size -= 2) < 0) goto overflow;
combine = out++; /* Store this address, and later use it to increment the literal size. */
*combine = 0; /* The 0 here means literal of length 1. */
}
*out++ = *in++; /* Write 1 literal byte from the input to the output. */
}
return (int)(out - (unsigned char *)output);
overflow: return -1;
}
int
uxn_lz_expand(void *output, int output_size, const void *input, int input_size)
{
int num, offset, written = 0;
unsigned char *out = output;
const unsigned char *from, *in = input;
while (input_size)
{
num = *in++;
if (num > 127) /* Dictionary */
{
if ((input_size -= 1) < 0) goto malformed;
num &= 0x7F;
if (num & 0x40)
{
if ((input_size -= 1) < 0) goto malformed;
num = *in++ | num << 8 & 0x3FFF;
}
num += MinMatchLength;
offset = *in++ + 1;
if (offset > written) goto malformed;
from = out + written - offset;
}
else /* Literal */
{
input_size -= ++num;
if (input_size < 0) goto malformed;
from = in, in += num;
}
if (written + num > output_size) goto overflow;
while (num--) out[written++] = *from++;
}
return written;
overflow: malformed: return -1;
}
int
uxn_lz_expand_stream(struct uxn_lz_expand_t *a)
{
/* Copy struct to stack variables for compiler optimizations */
unsigned char *next_in = a->next_in, *next_out = a->next_out;
int avail_in = a->avail_in, avail_out = a->avail_out;
int dict_len = a->dict_len, copy_num = a->copy_num;
unsigned char dict_read_pos = a->dict_read_pos, dict_write_pos = a->dict_write_pos, *dict = a->dict;
int result = 0;
switch (a->state)
{
case 0:
for (; avail_in;)
{
copy_num = *next_in++;
avail_in--;
if (copy_num > 127) /* Dictionary */
{
copy_num &= 0x7F;
if (copy_num & 0x40)
{
case 1:
if (!avail_in) { a->state = 1; goto need_more; }
avail_in--;
copy_num = *next_in++ | copy_num << 8 & 0x3FFF;
}
copy_num += MinMatchLength;
case 2:
if (!avail_in) { a->state = 2; goto need_more; }
avail_in--;
dict_read_pos = *next_in++ + 1;
if (dict_read_pos > dict_len) { a->state = 5; result = -1; goto flush; } /* Malformed */
dict_read_pos = dict_write_pos - dict_read_pos;
if ((dict_len += copy_num) > 256) dict_len = 256;
case 3:
do {
if (!avail_out) { a->state = 3; goto need_more; }
*next_out++ = dict[dict_write_pos++] = dict[dict_read_pos++];
avail_out--;
} while (--copy_num);
}
else /* Literal */
{
copy_num++;
if ((dict_len += copy_num) > 256) dict_len = 256;
case 4:
do {
if (!avail_in || !avail_out) { a->state = 4; goto need_more; }
*next_out++ = dict[dict_write_pos++] = *next_in++;
avail_in--, avail_out--;
} while (--copy_num);
}
}
a->state = 0;
case 5:;
}
need_more: flush:
/* Flush stack variables back to struct */
a->next_in = next_in, a->next_out = next_out;
a->avail_in = avail_in, a->avail_out = avail_out;
a->dict_len = dict_len, a->copy_num = copy_num;
a->dict_read_pos = dict_read_pos, a->dict_write_pos = dict_write_pos;
return result;
}
unsigned int
uxn_checksum(unsigned int seed, void *bytes, unsigned int bytes_size)
{
unsigned int x = seed >> 16, y = seed, c;
unsigned char *in = bytes, *end = in + bytes_size;
for (; in != end; in++) {
c = *in << 8 | *in;
x = x * 0x2443 + c;
y = y * 0x118d + c;
}
return x << 16 | (y & 0xFFFF);
}

View File

@ -18,4 +18,3 @@ int uxn_lz_expand_stream(struct uxn_lz_expand_t *a);
#define UXN_CHECKSUM_SEED 0x1234ABCD #define UXN_CHECKSUM_SEED 0x1234ABCD
unsigned int uxn_checksum(unsigned int seed, void *bytes, unsigned int bytes_size); unsigned int uxn_checksum(unsigned int seed, void *bytes, unsigned int bytes_size);

122
cli/lz/ulzdec.tal Normal file
View File

@ -0,0 +1,122 @@
( decompressor )
|10 @Console &vector $2 &read $1 &pad $5 &write $1 &err $1
|a0 @File &vector $2 &success $2 &stat $2 &delete $1 &append $1 &name $2 &length $2 &read $2 &write $2
|0000
@input-size $2
@src $30
@dst $30
@ptr $1
|0100
(
@|vectors )
@ready-src ( -> ) ;&await .Console/vector DEO2 BRK
&await ( -> ) .Console/read DEI .src skey ?ready-dst BRK
@ready-dst ( -> ) ;&await .Console/vector DEO2 BRK
&await ( -> ) .Console/read DEI .dst skey ?on-ready BRK
@on-ready ( -> )
;src decompress
( ;mem pstr #0a18 DEO )
( debug #800e DEO )
( write )
;dst .File/name DEO2
;mem .ptr LDZ2 SUB2 .File/length DEO2
;mem .File/write DEO2
( halt ) #800f DEO
BRK
@decompress ( str* -- )
;mem .ptr STZ2
.File/name DEO2
#0001 .input-size STZ2
&stream
.input-size LDZ2 .File/length DEO2
;&b
DUP2 .File/read DEO2
.File/success DEI2 #0000 EQU2 ?&eof
LDA decompress/run
.File/success DEI2 ORA ?&stream
JMP2r
&eof POP2 JMP2r
&b $1
&run ( byte -- )
DUP #80 AND ?&dict
( literal )
#00 SWP INC2 !do-literal
&dict ( byte -- )
#7f AND
DUP #40 AND ?&dict3
( 1 byte )
#00 SWP #0004 ADD2
( offset )
;&b .File/read DEO2
;&b LDA INC
!do-copy
&dict3 ( byte -- )
( hb )
#3f AND
( lb )
#0001 .File/length DEO2
;&b .File/read DEO2
;&b LDA #0004 ADD2
( offset )
;&b .File/read DEO2
;&b LDA INC
!do-copy
@do-copy ( length* offset -- )
#00 SWP #0000 SWP2 SUB2 .ptr LDZ2 ADD2 STH2
#0000
&l
DUP2 STH2kr ADD2 LDA do-append
INC2 GTH2k ?&l
POP2 POP2
POP2r
JMP2r
@do-append ( byte -- )
.ptr LDZ2 STH2k STA
STH2r INC2 .ptr STZ2
JMP2r
@do-literal ( length* -- )
DUP2 .File/length DEO2
.ptr LDZ2
DUP2 .File/read DEO2
ADD2 .ptr STZ2
JMP2r
(
@|stdlib )
@pstr ( str* -- ) LDAk ?&w POP2 JMP2r &w LDAk #18 DEO INC2 LDAk ?&w POP2 JMP2r
@skey ( key buf -- proc ) OVR #21 LTH ?&eval #00 SWP sput #00 JMP2r &eval POP2 #01 JMP2r
@scap ( str* -- end* ) LDAk ?&w JMP2r &w INC2 LDAk ?&w JMP2r
@sput ( chr str* -- ) scap INC2k #00 ROT ROT STA STA JMP2r
@mem