Created
September 2, 2019 09:02
-
-
Save danielkucera/6ed4266d8095795adf3e225b266f3b75 to your computer and use it in GitHub Desktop.
smaz-orig.c
This file contains 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
#if ITX_BOOT_TYPE == ITX_HOST_BOOT | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <arpa/inet.h> | |
/* magic file header for compressed files */ | |
static const unsigned char magic[4] = { 'S', 'M', 'A', 'Z' }; | |
#if !defined(__OR32__) | |
#define DATA_SWAP32(n) \ | |
( (((n) >> 24) & 0x000000FF) | \ | |
(((n) >> 8) & 0x0000FF00) | \ | |
(((n) << 8) & 0x00FF0000) | \ | |
(((n) << 24) & 0xFF000000) ) | |
#else | |
#define DATA_SWAP32(n) (n) | |
#endif | |
#define SAFE | |
#if defined(SAFE) | |
# if defined(__DEBUG__) | |
# define fail(x,r) if (x) { printf("%s #%d\n", __FILE__, __LINE__); *dst_len = olen; return r; } | |
# else | |
# define fail(x,r) if (x) { *dst_len = olen; return r; } | |
# endif // __DEBUG__ | |
#else | |
# define fail(x,r) | |
#endif // SAFE | |
/* Thinned out version of the UCL 2e decompression sourcecode | |
* Original (C) Markus F.X.J Oberhumer under GNU GPL license */ | |
#define GETBYTE(src) (src[ilen++]) | |
# define GETBIT(bb, src) \ | |
(((bb = ((bb & 0x7f) ? (bb*2) : ((unsigned)GETBYTE(src)*2+1))) >> 8) & 1) | |
enum status { | |
UCL_E_OK = 0, | |
UCL_E_INPUT_OVERRUN = -0x1, | |
UCL_E_OUTPUT_OVERRUN = -0x2, | |
UCL_E_LOOKBEHIND_OVERRUN= -0x3, | |
UCL_E_OVERLAP_OVERRUN = -0x4, | |
UCL_E_INPUT_NOT_CONSUMED= -0x5 | |
}; | |
#define SMAZ 0x534d415a | |
#define OUTLEN 0x50000 * 20 | |
typedef struct { | |
uint32_t magic; | |
uint32_t unknown; | |
uint32_t unknown1; | |
uint32_t size; | |
} smaz_hdr_t; | |
int main(){ | |
/* read header */ | |
void *start = malloc(0xb80); | |
fread(start, 1, 0xb80, stdin); | |
smaz_hdr_t header; | |
if (fread(&header, 1, sizeof(header), stdin) != sizeof(header)) { | |
perror("fread"); | |
return 1; | |
} | |
fprintf(stderr, "header read\n"); | |
/* check magic */ | |
fprintf(stderr, "magic %x %x\n", header.magic, htonl(SMAZ)); | |
if (header.magic != htonl(SMAZ)) { | |
fprintf(stderr, "error: wrong magic: '%x'\n", header.magic); | |
return 1; | |
} | |
/* read rest of file to buffer */ | |
fprintf(stderr, "malloc %d\n", header.size); | |
void *buffer = malloc(header.size); | |
fprintf(stderr, "malloc OK\n"); | |
size_t compressed_size = ntohl(header.size); | |
compressed_size -= sizeof(header); | |
size_t to_read = compressed_size; | |
size_t done = 0; | |
fprintf(stderr, "info: I am about to read %d bytes\n", to_read); | |
while (to_read > 0) { | |
done = fread(buffer, 1, to_read, stdin); | |
fprintf(stderr, "info: done %d bytes\n", done); | |
if (done == 0) { | |
perror("fread"); | |
return 1; | |
} | |
to_read -= done; | |
fprintf(stderr, "info: %d yet to be read\n", to_read); | |
} | |
/* decompress */ | |
unsigned int outlen = compressed_size + (compressed_size / 8) + 256; | |
uint8_t *output = (uint8_t*) calloc(outlen, 1); | |
int status = decompress(buffer, compressed_size, output, &outlen); | |
if (status != 0) { | |
fprintf(stderr, "error: decompression failed with %x\n", status); | |
} | |
fprintf(stderr, "info: done\n", status); | |
if (fwrite(output, 1, outlen, stdout) != outlen) { | |
perror("fwrite"); | |
return 1; | |
} | |
/* clean up */ | |
free(buffer); | |
return 0; | |
} | |
int decompress( const unsigned char* src, unsigned int src_len, | |
unsigned char* dst, unsigned int* dst_len) | |
{ | |
unsigned int bb = 0; | |
unsigned int ilen = 0, olen = 0, last_m_off = 1; | |
#if defined(SAFE) | |
const unsigned int oend = *dst_len; | |
#endif | |
for (;;) { | |
unsigned int m_off, m_len; | |
while (GETBIT(bb,src)) { | |
fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | |
fail(olen >= oend, UCL_E_OUTPUT_OVERRUN); | |
dst[olen++] = GETBYTE(src); | |
} | |
m_off = 1; | |
for (;;) { | |
m_off = m_off*2 + GETBIT(bb,src); | |
fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | |
fail(m_off > 0xfffffful + 3, UCL_E_LOOKBEHIND_OVERRUN); | |
if (GETBIT(bb,src)) { | |
break; | |
} | |
m_off = (m_off-1)*2 + GETBIT(bb,src); | |
} | |
if (m_off == 2) { | |
m_off = last_m_off; | |
m_len = GETBIT(bb,src); | |
} else { | |
fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | |
m_off = (m_off-3)*256 + GETBYTE(src); | |
if (m_off == 0xfffffffful) { | |
break; | |
} | |
m_len = (m_off ^ 0xfffffffful) & 1; | |
m_off >>= 1; | |
last_m_off = ++m_off; | |
} | |
if (m_len) { | |
m_len = 1 + GETBIT(bb,src); | |
} else if (GETBIT(bb,src)) { | |
m_len = 3 + GETBIT(bb,src); | |
} else { | |
m_len++; | |
do { | |
m_len = m_len*2 + GETBIT(bb,src); | |
fail(ilen >= src_len, UCL_E_INPUT_OVERRUN); | |
fail(m_len >= oend, UCL_E_OUTPUT_OVERRUN); | |
} while (!GETBIT(bb,src)); | |
m_len += 3; | |
} | |
m_len += (m_off > 0x500); | |
fail(olen + m_len > oend, UCL_E_OUTPUT_OVERRUN); | |
fail(m_off > olen, UCL_E_LOOKBEHIND_OVERRUN); | |
{ | |
const unsigned char* m_pos; | |
m_pos = dst + olen - m_off; | |
dst[olen++] = *m_pos++; | |
do { | |
dst[olen++] = *m_pos++; | |
} while (--m_len > 0); | |
} | |
} | |
*dst_len = olen; | |
return (ilen == src_len) ? UCL_E_OK | |
: (ilen < src_len ? UCL_E_INPUT_NOT_CONSUMED | |
: UCL_E_INPUT_OVERRUN); | |
} | |
int do_decompress(unsigned char *InBuf, unsigned char *outBuf) | |
{ | |
int r = 0; | |
unsigned char *buf = NULL; | |
unsigned char *pOutBuf; | |
unsigned int buf_len; | |
unsigned int block_size; | |
unsigned int overhead = 0; | |
unsigned int icon_header; | |
//unsigned int OutSize; | |
/* | |
* Step 1: check magic header, read flags & block size, init checksum | |
*/ | |
//memcpy(&icon_header, InBuf, sizeof(unsigned char) * sizeof(int)); | |
//InBuf += sizeof(int); | |
//icon_header = DATA_SWAP32(icon_header); | |
//OutSize = icon_header; | |
//pOutBuf = OutBuf = (unsigned char *) calloc(OutSize, sizeof(unsigned char)); | |
pOutBuf = outBuf; | |
memcpy(&block_size, InBuf, sizeof(int) * 1); | |
InBuf += sizeof(int); | |
block_size = DATA_SWAP32(block_size); | |
overhead = block_size / 8 + 256; | |
if (overhead == 0) | |
{ | |
printf("header error - invalid header\n"); | |
r = 2; | |
goto err; | |
} | |
if (block_size < 1024 || block_size > 8*1024*1024L) | |
{ | |
printf("header error - invalid block size %ld\n", | |
(long) block_size); | |
r = 3; | |
goto err; | |
} | |
printf("block-size is %ld bytes\n", (long)block_size); | |
/* | |
* Step 2: allocate buffer for in-place decompression | |
*/ | |
buf_len = (block_size + overhead + 3) & (~3l); | |
buf = (unsigned char*) malloc(buf_len); | |
if (buf == NULL) | |
{ | |
printf("out of memory\n"); | |
r = 5; | |
goto err; | |
} | |
/* | |
* Step 3: process blocks | |
*/ | |
for (;;) | |
{ | |
unsigned char* in; | |
unsigned char* out; | |
unsigned int in_len; | |
unsigned int out_len; | |
/* read uncompressed size */ | |
memcpy(&out_len, InBuf, sizeof(int) * 1); | |
InBuf += sizeof(int); | |
out_len = DATA_SWAP32(out_len); | |
/* exit if last block (EOF marker) */ | |
if (out_len == 0) | |
break; | |
/* read compressed size */ | |
memcpy(&in_len, InBuf, sizeof(int) * 1); | |
InBuf += sizeof(int); | |
in_len = DATA_SWAP32(in_len); | |
/* sanity check of the size values */ | |
if (out_len > block_size || in_len == 0) | |
{ | |
printf("in: %u, out: %u, bk: %u\n", in_len, out_len, block_size); | |
printf("block size error - data corrupted\n"); | |
r = 6; | |
goto err; | |
} | |
/* place compressed block at the top of the buffer */ | |
in = buf + buf_len - ((in_len+3)&~3l); | |
out = buf; | |
/* read compressed block data */ | |
memcpy(in, InBuf, sizeof(char) * in_len); | |
InBuf += (sizeof(char) * in_len); | |
if (in_len < out_len) | |
{ | |
/* decompress - use safe decompressor as data might be corrupted */ | |
unsigned int new_len = out_len; | |
r = decompress(in,in_len,out,&new_len); | |
if (r != UCL_E_OK || new_len != out_len) | |
{ | |
printf("r: %d, out: %u, bk: %u\n", r, new_len, out_len); | |
printf("compressed data violation: error %d (%ld/%ld/%ld)\n", r, (long) in_len, (long) out_len, (long) new_len); | |
//r = 8; | |
//goto err; | |
} | |
/* write decompressed block */ | |
memcpy(pOutBuf, out, out_len * sizeof(char)); | |
pOutBuf += (out_len * sizeof(char)); | |
} | |
#if 1 //for Jedi FW compress bug, tmp solution | |
else | |
{ | |
/* decompress - use safe decompressor as data might be corrupted */ | |
unsigned int new_len = out_len; | |
r = decompress(in,in_len,out,&new_len); | |
if (r != UCL_E_OK || new_len != out_len) | |
{ | |
printf("compressed data violation: error %d (%ld/%ld/%ld)\n", r, (long) in_len, (long) out_len, (long) new_len); | |
r = 8; | |
goto err; | |
} | |
/* write decompressed block */ | |
memcpy(pOutBuf, out, out_len * sizeof(char)); | |
pOutBuf += (out_len * sizeof(char)); | |
} | |
#else | |
else | |
{ | |
/* write original (incompressible) block */ | |
memcpy(pOutBuf, in, in_len * sizeof(char)); | |
pOutBuf += (in_len * sizeof(char)); | |
} | |
#endif | |
} | |
err: | |
free(buf); | |
//PalFree(OutBuf); | |
return r; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment