mirror of https://github.com/zeldaret/mm.git
git subrepo pull tools/z64compress --force
subrepo: subdir: "tools/z64compress" merged: "43035d97f" upstream: origin: "https://github.com/z64me/z64compress.git" branch: "main" commit: "43035d97f" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
parent
768094b1a8
commit
2e487b5008
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "src/enc/libdeflate"]
|
||||||
|
path = src/enc/libdeflate
|
||||||
|
url = https://github.com/ebiggers/libdeflate
|
|
@ -6,7 +6,7 @@
|
||||||
[subrepo]
|
[subrepo]
|
||||||
remote = https://github.com/z64me/z64compress.git
|
remote = https://github.com/z64me/z64compress.git
|
||||||
branch = main
|
branch = main
|
||||||
commit = 5da3132606e4fd427a8d72b8428e4f921cd6e56f
|
commit = 43035d97f2e750332d9644438bc4f687f073a4dd
|
||||||
parent = 837eb1c80687fe9b57a3c7b841547c33feeed6c7
|
parent = 768094b1a889b2253b3e905b99792efaecd3e879
|
||||||
method = merge
|
method = merge
|
||||||
cmdver = 0.4.3
|
cmdver = 0.4.3
|
||||||
|
|
|
@ -24,10 +24,12 @@ endif
|
||||||
|
|
||||||
OBJ_DIR := o/$(TARGET)
|
OBJ_DIR := o/$(TARGET)
|
||||||
|
|
||||||
$(OBJ_DIR)/src/enc/%.o: CFLAGS := -DNDEBUG -s -Ofast -flto -Wall
|
$(OBJ_DIR)/src/enc/%.o: CFLAGS := -DNDEBUG -s -Ofast -flto -Wall -Isrc/enc/libdeflate
|
||||||
|
|
||||||
SRC_DIRS := $(shell find src -type d)
|
SRC_DIRS := $(shell find src -type d)
|
||||||
C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
|
C_DIRS := $(shell find src -type d -not -path "src/enc/libdeflate/*")
|
||||||
|
C_FILES := $(foreach dir,$(C_DIRS),$(wildcard $(dir)/*.c))
|
||||||
|
C_FILES += src/enc/libdeflate/lib/deflate_compress.c src/enc/libdeflate/lib/utils.c
|
||||||
O_FILES := $(foreach f,$(C_FILES:.c=.o),$(OBJ_DIR)/$f)
|
O_FILES := $(foreach f,$(C_FILES:.c=.o),$(OBJ_DIR)/$f)
|
||||||
|
|
||||||
# Make build directories
|
# Make build directories
|
||||||
|
@ -38,7 +40,7 @@ $(shell mkdir -p $(foreach dir,$(SRC_DIRS),$(OBJ_DIR)/$(dir)))
|
||||||
all: z64compress
|
all: z64compress
|
||||||
|
|
||||||
z64compress: $(O_FILES)
|
z64compress: $(O_FILES)
|
||||||
$(CC) $(TARGET_CFLAGS) $(CFLAGS) $(O_FILES) -lm -lpthread $(TARGET_LIBS) -o z64compress
|
$(CC) $(TARGET_CFLAGS) $(CFLAGS) $(O_FILES) -lm -lpthread -lz $(TARGET_LIBS) -o z64compress
|
||||||
|
|
||||||
$(OBJ_DIR)/%.o: %.c
|
$(OBJ_DIR)/%.o: %.c
|
||||||
$(CC) -c $(TARGET_CFLAGS) $(CFLAGS) $< -o $@
|
$(CC) -c $(TARGET_CFLAGS) $(CFLAGS) $< -o $@
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
`z64compress` is a program for compressing Zelda 64 roms: be they retail, hacked traditionally, or custom-built from the [`Ocarina of Time`](https://github.com/zeldaret/oot) or [`Majora's Mask`](https://github.com/zeldaret/mm) reverse engineering projects. It is written in highly efficient C and leverages the power of multithreading to make compression as fast as possible. To reduce overhead on subsequent compressions, an optional cache directory can be specified.
|
`z64compress` is a program for compressing Zelda 64 roms: be they retail, hacked traditionally, or custom-built from the [`Ocarina of Time`](https://github.com/zeldaret/oot) or [`Majora's Mask`](https://github.com/zeldaret/mm) reverse engineering projects. It is written in highly efficient C and leverages the power of multithreading to make compression as fast as possible. To reduce overhead on subsequent compressions, an optional cache directory can be specified.
|
||||||
|
|
||||||
In addition to the default `yaz`, it supports some faster and more compact algorithms such as `lzo`, `ucl`, and `aplib`. In order to use these, grab patches or code from my [`z64enc` repository](https://github.com/z64me/z64enc).
|
In addition to the default `yaz`, it supports some faster and more compact algorithms such as `DEFLATE`, `lzo`, `ucl`, and `aplib`. In order to use these, grab patches or code from my [`z64enc` repository](https://github.com/z64me/z64enc).
|
||||||
|
|
||||||
If you add an algorithm, please make sure `valgrind` reports no memory leaks or other errors before making a pull request. Thank you!
|
If you add an algorithm, please make sure `valgrind` reports no memory leaks or other errors before making a pull request. Thank you!
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ This is a command line application. Learn from these common examples and adapt t
|
||||||
yaz
|
yaz
|
||||||
ucl
|
ucl
|
||||||
lzo
|
lzo
|
||||||
|
zlib
|
||||||
aplib
|
aplib
|
||||||
* to use non-yaz codecs, find patches
|
* to use non-yaz codecs, find patches
|
||||||
and code on my z64enc repo
|
and code on my z64enc repo
|
||||||
|
@ -89,6 +90,13 @@ This is a command line application. Learn from these common examples and adapt t
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
I have included shell scripts for building Linux and Windows binaries. Windows binaries are built using a cross compiler ([I recommend `MXE`](https://mxe.cc/)).
|
First, clone the repository and initialize its submodules:
|
||||||
|
```
|
||||||
|
git clone https://github.com/z64me/z64compress.git
|
||||||
|
cd z64compress
|
||||||
|
git submodule update --init
|
||||||
|
```
|
||||||
|
|
||||||
Alternatively, a Makefile-based build system is provided. Choose the target platform with `make TARGET=linux64|linux32|win32`, default is linux64. If building for windows with a cross compiler, specify the compiler executable with `make TARGET=win32 CC=/path/to/executable`.
|
A Makefile-based build system is provided. Choose the target platform with `make TARGET=linux64|linux32|win32`, default is linux64. If building for windows with a cross compiler, specify the compiler executable with `make TARGET=win32 CC=/path/to/executable`.
|
||||||
|
|
||||||
|
Alternatively, I have included shell scripts for building Linux and Windows binaries. Windows binaries are built using a cross compiler ([I recommend `MXE`](https://mxe.cc/)).
|
||||||
|
|
|
@ -4,7 +4,7 @@ mkdir -p o
|
||||||
mv *.o o
|
mv *.o o
|
||||||
|
|
||||||
# build everything else
|
# build everything else
|
||||||
gcc -o z64compress -DNDEBUG src/*.c o/*.o -Wall -Wextra -s -Os -flto -lpthread -march=native -mtune=native
|
gcc -o z64compress -DNDEBUG src/*.c o/*.o src/enc/libdeflate/lib/deflate_compress.c src/enc/libdeflate/lib/utils.c -Isrc/enc/libdeflate -Wall -Wextra -s -Os -flto -lpthread -lz -march=native -mtune=native
|
||||||
|
|
||||||
# move to bin directory
|
# move to bin directory
|
||||||
mkdir -p bin/linux64
|
mkdir -p bin/linux64
|
||||||
|
|
|
@ -4,7 +4,7 @@ mkdir -p o
|
||||||
mv *.o o
|
mv *.o o
|
||||||
|
|
||||||
# build everything else
|
# build everything else
|
||||||
gcc -m32 -o z64compress -DNDEBUG src/*.c o/*.o -Wall -Wextra -s -Os -flto -lpthread -march=native -mtune=native
|
gcc -m32 -o z64compress -DNDEBUG src/*.c o/*.o src/enc/libdeflate/lib/deflate_compress.c src/enc/libdeflate/lib/utils.c -Isrc/enc/libdeflate -Wall -Wextra -s -Os -flto -lpthread -lz -march=native -mtune=native
|
||||||
|
|
||||||
# move to bin directory
|
# move to bin directory
|
||||||
mkdir -p bin/linux32
|
mkdir -p bin/linux32
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
# build compression functions (slow)
|
# build compression functions (slow)
|
||||||
~/c/mxe/usr/bin/i686-w64-mingw32.static-gcc -DNDEBUG -s -Ofast -flto -lm -c -Wall src/enc/*.c src/enc/lzo/*.c src/enc/ucl/comp/*.c src/enc/apultra/*.c
|
i686-w64-mingw32.static-gcc -DNDEBUG -s -Ofast -flto -lm -c -Wall src/enc/*.c src/enc/lzo/*.c src/enc/ucl/comp/*.c src/enc/apultra/*.c
|
||||||
mkdir -p o
|
mkdir -p o
|
||||||
mv *.o o
|
mv *.o o
|
||||||
|
|
||||||
# build everything else
|
# build everything else
|
||||||
~/c/mxe/usr/bin/i686-w64-mingw32.static-gcc -o z64compress.exe -DNDEBUG src/*.c o/*.o -Wall -Wextra -s -Os -flto -lpthread -mconsole -municode
|
i686-w64-mingw32.static-gcc -o z64compress.exe -DNDEBUG src/*.c o/*.o src/enc/libdeflate/lib/deflate_compress.c src/enc/libdeflate/lib/utils.c -Isrc/enc/libdeflate -Wall -Wextra -s -Os -flto -lpthread -lz -mconsole -municode
|
||||||
|
|
||||||
# move to bin directory
|
# move to bin directory
|
||||||
mkdir -p bin/win32
|
mkdir -p bin/win32
|
||||||
|
|
|
@ -21,8 +21,8 @@ aplenc(
|
||||||
int nMaxCompressedSize = apultra_get_max_compressed_size(src_sz);
|
int nMaxCompressedSize = apultra_get_max_compressed_size(src_sz);
|
||||||
apultra_stats stats;
|
apultra_stats stats;
|
||||||
|
|
||||||
int hlen = 8; /* header length; required due to MM's archives */
|
extern int g_hlen; /* header length */
|
||||||
memset(dst, 0, hlen);
|
memset(dst, 0, g_hlen);
|
||||||
memcpy(dst, "APL0", 4);
|
memcpy(dst, "APL0", 4);
|
||||||
dst[4] = (src_sz >> 24);
|
dst[4] = (src_sz >> 24);
|
||||||
dst[5] = (src_sz >> 16);
|
dst[5] = (src_sz >> 16);
|
||||||
|
@ -31,7 +31,7 @@ aplenc(
|
||||||
|
|
||||||
*dst_sz = apultra_compress(
|
*dst_sz = apultra_compress(
|
||||||
src
|
src
|
||||||
, dst + hlen
|
, dst + g_hlen
|
||||||
, src_sz
|
, src_sz
|
||||||
, nMaxCompressedSize
|
, nMaxCompressedSize
|
||||||
, 0 /* flags */
|
, 0 /* flags */
|
||||||
|
@ -41,7 +41,7 @@ aplenc(
|
||||||
, &stats
|
, &stats
|
||||||
);
|
);
|
||||||
|
|
||||||
*dst_sz = *dst_sz + hlen;
|
*dst_sz = *dst_sz + g_hlen;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,15 @@ int zx7enc(
|
||||||
, void *_ctx
|
, void *_ctx
|
||||||
);
|
);
|
||||||
|
|
||||||
|
int
|
||||||
|
zlibenc(
|
||||||
|
void *_src
|
||||||
|
, unsigned src_sz
|
||||||
|
, void *_dst
|
||||||
|
, unsigned *dst_sz
|
||||||
|
, void *_ctx
|
||||||
|
);
|
||||||
|
|
||||||
int aplenc(
|
int aplenc(
|
||||||
void *_src
|
void *_src
|
||||||
, unsigned src_sz
|
, unsigned src_sz
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 6c095314d0c49061f41e1e40be2625dfc2253afa
|
|
@ -33,8 +33,8 @@ lzoenc(
|
||||||
unsigned char *wrkmem = _ctx;
|
unsigned char *wrkmem = _ctx;
|
||||||
lzo_uint result_sz = 0;
|
lzo_uint result_sz = 0;
|
||||||
|
|
||||||
int hlen = 8; /* header length; required due to MM's archives */
|
extern int g_hlen; /* header length */
|
||||||
memset(dst, 0, hlen);
|
memset(dst, 0, g_hlen);
|
||||||
memcpy(dst, "LZO0", 4);
|
memcpy(dst, "LZO0", 4);
|
||||||
dst[4] = (src_sz >> 24);
|
dst[4] = (src_sz >> 24);
|
||||||
dst[5] = (src_sz >> 16);
|
dst[5] = (src_sz >> 16);
|
||||||
|
@ -46,9 +46,9 @@ lzoenc(
|
||||||
|
|
||||||
memset(wrkmem, 0, LZO1X_999_MEM_COMPRESS);
|
memset(wrkmem, 0, LZO1X_999_MEM_COMPRESS);
|
||||||
|
|
||||||
lzo1x_999_compress(src, src_sz, dst + hlen, &result_sz, wrkmem);
|
lzo1x_999_compress(src, src_sz, dst + g_hlen, &result_sz, wrkmem);
|
||||||
|
|
||||||
*dst_sz = result_sz + hlen;
|
*dst_sz = result_sz + g_hlen;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ uclenc(
|
||||||
int level = 10;
|
int level = 10;
|
||||||
ucl_uint result_sz;
|
ucl_uint result_sz;
|
||||||
|
|
||||||
int hlen = 8; /* header length; required due to MM's archives */
|
extern int g_hlen; /* header length */
|
||||||
memset(dst, 0, hlen);
|
memset(dst, 0, g_hlen);
|
||||||
memcpy(dst, "UCL0", 4);
|
memcpy(dst, "UCL0", 4);
|
||||||
dst[4] = (src_sz >> 24);
|
dst[4] = (src_sz >> 24);
|
||||||
dst[5] = (src_sz >> 16);
|
dst[5] = (src_sz >> 16);
|
||||||
|
@ -29,7 +29,7 @@ uclenc(
|
||||||
r = ucl_nrv2b_99_compress(
|
r = ucl_nrv2b_99_compress(
|
||||||
src /* in */
|
src /* in */
|
||||||
, src_sz /* in size */
|
, src_sz /* in size */
|
||||||
, dst + hlen /* out */
|
, dst + g_hlen /* out */
|
||||||
, &result_sz /* out size */
|
, &result_sz /* out size */
|
||||||
, NULL /* callback */
|
, NULL /* callback */
|
||||||
, level /* level */
|
, level /* level */
|
||||||
|
@ -43,7 +43,7 @@ uclenc(
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst_sz = result_sz + hlen;
|
*dst_sz = result_sz + g_hlen;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
/* <z64.me> yar.c: decode and encode MM yaz archives */
|
/* <z64.me> yar.c: decode and encode MM yaz archives */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this file can also be compiled as a standalone program for
|
||||||
|
* decompressing the contents of a MM yaz archive like so:
|
||||||
|
* gcc -o unyar -Wall -Wextra -std=c99 -pedantic -DYAR_MAIN_TEST=1 yar.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -231,7 +238,7 @@ yar_reencode(
|
||||||
ss += 4;
|
ss += 4;
|
||||||
item += 1;
|
item += 1;
|
||||||
|
|
||||||
} while (ss - src < end);
|
} while ((unsigned)(ss - src) < end);
|
||||||
|
|
||||||
/* update progress display */
|
/* update progress display */
|
||||||
if (name)
|
if (name)
|
||||||
|
@ -277,7 +284,7 @@ yar_reencode(
|
||||||
|
|
||||||
/* yaz decoder, courtesy of spinout182 */
|
/* yaz decoder, courtesy of spinout182 */
|
||||||
static
|
static
|
||||||
int spinout_yaz_dec(void *_src, void *_dst, int dstSz)
|
int spinout_yaz_dec(void *_src, void *_dst, unsigned dstSz, unsigned *srcSz)
|
||||||
{
|
{
|
||||||
unsigned char *src = _src;
|
unsigned char *src = _src;
|
||||||
unsigned char *dst = _dst;
|
unsigned char *dst = _dst;
|
||||||
|
@ -328,7 +335,7 @@ int spinout_yaz_dec(void *_src, void *_dst, int dstSz)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*copy run*/
|
/*copy run*/
|
||||||
int i;
|
unsigned int i;
|
||||||
for(i = 0; i < numBytes; ++i)
|
for(i = 0; i < numBytes; ++i)
|
||||||
{
|
{
|
||||||
dst[dstPlace] = dst[copySource];
|
dst[dstPlace] = dst[copySource];
|
||||||
|
@ -343,12 +350,14 @@ int spinout_yaz_dec(void *_src, void *_dst, int dstSz)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
(void)srcSz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* encodes decompressed data, storing result in dst */
|
/* encodes decompressed data, storing result in dst */
|
||||||
static
|
static
|
||||||
int encode(void *src, int srcSz, void *_dst, int *dstSz, void *ctx)
|
int encode(void *src, unsigned srcSz, void *_dst, unsigned *dstSz, void *ctx)
|
||||||
{
|
{
|
||||||
unsigned char *dst = _dst;
|
unsigned char *dst = _dst;
|
||||||
|
|
||||||
|
@ -368,15 +377,22 @@ int encode(void *src, int srcSz, void *_dst, int *dstSz, void *ctx)
|
||||||
*dstSz = srcSz + 0x10;
|
*dstSz = srcSz + 0x10;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
(void)ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* checks if data has already been encoded */
|
/* checks if data has already been encoded */
|
||||||
/* if it does, dst is filled with that data and 1 is returned */
|
/* if it does, dst is filled with that data and 1 is returned */
|
||||||
/* 0 is returned otherwise */
|
/* 0 is returned otherwise */
|
||||||
static
|
static
|
||||||
int exist(void *src, int srcSz, void *dst, int *dstSz)
|
int exist(void *src, unsigned srcSz, void *dst, unsigned *dstSz)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
(void)src;
|
||||||
|
(void)srcSz;
|
||||||
|
(void)dst;
|
||||||
|
(void)dstSz;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unsafe but it's a test program so it's fine */
|
/* unsafe but it's a test program so it's fine */
|
||||||
|
@ -412,17 +428,39 @@ file_read(char *fn, unsigned *sz)
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* minimal file writer
|
||||||
|
* returns 0 on failure
|
||||||
|
* returns non-zero on success
|
||||||
|
*/
|
||||||
|
int savefile(const char *fn, const void *dat, const size_t sz)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
/* rudimentary error checking returns 0 on any error */
|
||||||
|
if (
|
||||||
|
!fn
|
||||||
|
|| !sz
|
||||||
|
|| !dat
|
||||||
|
|| !(fp = fopen(fn, "wb"))
|
||||||
|
|| fwrite(dat, 1, sz, fp) != sz
|
||||||
|
|| fclose(fp)
|
||||||
|
)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
unsigned char *raw;
|
void *raw;
|
||||||
unsigned int raw_sz;
|
unsigned int raw_sz;
|
||||||
|
|
||||||
unsigned char *out;
|
void *out;
|
||||||
unsigned char *imm;
|
void *imm;
|
||||||
unsigned int out_sz = 0;
|
unsigned int out_sz = 0;
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc != 3)
|
||||||
FERR("args: unyar in.yar > out.yar");
|
FERR("args: unyar in.yar out.yar");
|
||||||
|
|
||||||
raw = file_read(argv[1], &raw_sz);
|
raw = file_read(argv[1], &raw_sz);
|
||||||
fprintf(stderr, "input file %s:\n", argv[1]);
|
fprintf(stderr, "input file %s:\n", argv[1]);
|
||||||
|
@ -432,18 +470,21 @@ int main(int argc, char *argv[])
|
||||||
imm = malloc(1024 * 1024 * 64);
|
imm = malloc(1024 * 1024 * 64);
|
||||||
|
|
||||||
yar_reencode(
|
yar_reencode(
|
||||||
raw, raw_sz, out, &out_sz, 12, "Yaz0", imm
|
raw, raw_sz, out, &out_sz, 16, argv[1], "Yaz0", imm, 0
|
||||||
, spinout_yaz_dec
|
, spinout_yaz_dec
|
||||||
, encode
|
, encode
|
||||||
, exist
|
, exist
|
||||||
);
|
);
|
||||||
|
|
||||||
/* write output to stdout */
|
/* write output file */
|
||||||
fwrite(out, 1, out_sz, stdout);
|
if (!savefile(argv[2], out, out_sz))
|
||||||
|
FERR("failed to write output file");
|
||||||
|
|
||||||
free(raw);
|
free(raw);
|
||||||
free(out);
|
free(out);
|
||||||
free(imm);
|
free(imm);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* YAR_MAIN_TEST */
|
#endif /* YAR_MAIN_TEST */
|
||||||
|
|
|
@ -272,16 +272,24 @@ uint32_t encode(struct yazCtx *ctx, uint8_t *data, uint32_t data_size, uint8_t *
|
||||||
// block and stream differentiation
|
// block and stream differentiation
|
||||||
// Yay is block, Yaz is stream
|
// Yay is block, Yaz is stream
|
||||||
int mode_block=1, mode_stream=1; // temporary, for testing
|
int mode_block=1, mode_stream=1; // temporary, for testing
|
||||||
|
#ifdef YAZ_MAIN_TEST
|
||||||
|
int g_hlen = 8;
|
||||||
|
#else
|
||||||
|
extern int g_hlen;
|
||||||
|
#endif
|
||||||
mode_block=!strcmp(mode,"Yay0");
|
mode_block=!strcmp(mode,"Yay0");
|
||||||
if (mode_block ) {
|
if (g_hlen) {
|
||||||
uint32_t l = (sb_count(ctx->cmds) << 2) + 16;
|
|
||||||
uint32_t o = (sb_count(ctx->ctrl) << 1) + l;
|
|
||||||
memcpy(output, mode, 4);
|
memcpy(output, mode, 4);
|
||||||
U32wr(output+4, sz);
|
U32wr(output+4, sz);
|
||||||
|
} else
|
||||||
|
output -= 8; /* headerless */
|
||||||
|
if (mode_block) {
|
||||||
|
uint32_t l = (sb_count(ctx->cmds) << 2) + 16;
|
||||||
|
uint32_t o = (sb_count(ctx->ctrl) << 1) + l;
|
||||||
U32wr(output+8, l);
|
U32wr(output+8, l);
|
||||||
U32wr(output+12, o);
|
U32wr(output+12, o);
|
||||||
|
|
||||||
uint32_t output_position = 16;
|
uint32_t output_position = g_hlen + 8;
|
||||||
uint32_t x;
|
uint32_t x;
|
||||||
for (x=0; x<sb_count(ctx->cmds); x++) {
|
for (x=0; x<sb_count(ctx->cmds); x++) {
|
||||||
U32wr(output+output_position, ctx->cmds[x]);
|
U32wr(output+output_position, ctx->cmds[x]);
|
||||||
|
@ -296,8 +304,6 @@ uint32_t encode(struct yazCtx *ctx, uint8_t *data, uint32_t data_size, uint8_t *
|
||||||
}
|
}
|
||||||
return output_position;
|
return output_position;
|
||||||
} else if(mode_stream) {
|
} else if(mode_stream) {
|
||||||
memcpy(output, mode, 4);
|
|
||||||
U32wr(output+4, sz);
|
|
||||||
U32wr(output+8, 0);
|
U32wr(output+8, 0);
|
||||||
U32wr(output+12, 0);
|
U32wr(output+12, 0);
|
||||||
|
|
||||||
|
@ -315,8 +321,8 @@ uint32_t encode(struct yazCtx *ctx, uint8_t *data, uint32_t data_size, uint8_t *
|
||||||
sb_push(ctx->back, (ctx->ctrl[x]>>8)&0xFF);
|
sb_push(ctx->back, (ctx->ctrl[x]>>8)&0xFF);
|
||||||
sb_push(ctx->back, (ctx->ctrl[x])&0xFF);
|
sb_push(ctx->back, (ctx->ctrl[x])&0xFF);
|
||||||
}
|
}
|
||||||
output_position = _enc_z_from_tables(ctx, ctx->ctl, ctx->back, ctx->raws, output+16, data_size, mode);
|
output_position = _enc_z_from_tables(ctx, ctx->ctl, ctx->back, ctx->raws, output+g_hlen+8, data_size, mode);
|
||||||
return 16 + output_position;
|
return output_position + g_hlen + 8;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
#include "libdeflate/libdeflate.h"
|
||||||
|
|
||||||
|
#define CAPACITY (1024 * 1024 * 4) /* output buffer max (4 mb) */
|
||||||
|
|
||||||
|
int
|
||||||
|
zlibenc(
|
||||||
|
void *_src
|
||||||
|
, unsigned src_sz
|
||||||
|
, void *_dst
|
||||||
|
, unsigned *dst_sz
|
||||||
|
, void *_ctx
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned char *src = _src;
|
||||||
|
unsigned char *dst = _dst;
|
||||||
|
unsigned result_sz;
|
||||||
|
|
||||||
|
extern int g_hlen; /* header length */
|
||||||
|
memset(dst, 0, g_hlen);
|
||||||
|
memcpy(dst, "ZLIB", 4);
|
||||||
|
dst[4] = (src_sz >> 24);
|
||||||
|
dst[5] = (src_sz >> 16);
|
||||||
|
dst[6] = (src_sz >> 8);
|
||||||
|
dst[7] = (src_sz >> 0);
|
||||||
|
|
||||||
|
/* zlib and gzip have different header lengths
|
||||||
|
* https://stackoverflow.com/a/68538037
|
||||||
|
*/
|
||||||
|
#if 1
|
||||||
|
|
||||||
|
#if 0 /* zlib */
|
||||||
|
z_stream stream = {0};
|
||||||
|
int r;
|
||||||
|
stream.avail_in = src_sz;
|
||||||
|
stream.next_in = src;
|
||||||
|
stream.avail_out = CAPACITY;
|
||||||
|
stream.next_out = dst + g_hlen;
|
||||||
|
#define HEADER_LEN 2
|
||||||
|
if ((r = deflateInit(&stream, Z_BEST_COMPRESSION)) != Z_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[!] fatal compression error %d\n", r);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if ((r = deflate(&stream, Z_FINISH)) == Z_STREAM_ERROR)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[!] Z_STREAM_ERROR\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
deflateEnd(&stream);
|
||||||
|
|
||||||
|
result_sz = CAPACITY - stream.avail_out;
|
||||||
|
#else /* libdeflate */
|
||||||
|
#define HEADER_LEN 0
|
||||||
|
int level = 12;
|
||||||
|
struct libdeflate_compressor *compressor;
|
||||||
|
compressor = libdeflate_alloc_compressor(level);
|
||||||
|
result_sz = libdeflate_deflate_compress(
|
||||||
|
compressor
|
||||||
|
, src, src_sz
|
||||||
|
, dst + g_hlen
|
||||||
|
, CAPACITY
|
||||||
|
);
|
||||||
|
libdeflate_free_compressor(compressor);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* this gzip code was left in for testing purposes; it may
|
||||||
|
* be useful if matching ique recompression is ever revisited;
|
||||||
|
* ique matches (except for one byte...) when compressed using
|
||||||
|
* gzip 1.2.4 or 1.2.4a (they produce identical results),
|
||||||
|
* available here: https://ftp.gnu.org/gnu/gzip/
|
||||||
|
* this is not a compression error, because decompressing the
|
||||||
|
* recompressed rom produces a rom identical to the original
|
||||||
|
* decompressed ique rom;
|
||||||
|
* TODO: find out why that byte doesn't match on recompression;
|
||||||
|
* TODO: once that's working, add --codec ique for those wanting
|
||||||
|
* matching ique recompression; otherwise, modern zlib works great!
|
||||||
|
*/
|
||||||
|
#define HEADER_LEN 10
|
||||||
|
FILE *fp = fopen("tmp.bin", "wb");
|
||||||
|
fwrite(src, 1, src_sz, fp);
|
||||||
|
fclose(fp);
|
||||||
|
system("./gzip -c -9 -n tmp.bin > tmp.bin.gzip");
|
||||||
|
fp = fopen("tmp.bin.gzip", "rb");
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
result_sz = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
fread(dst, 1, result_sz, fp);
|
||||||
|
fclose(fp);
|
||||||
|
#endif
|
||||||
|
*dst_sz = result_sz + g_hlen;
|
||||||
|
|
||||||
|
/* trim zlib/gzip header */
|
||||||
|
memmove(dst + g_hlen, dst + g_hlen + HEADER_LEN, result_sz);
|
||||||
|
*dst_sz -= HEADER_LEN;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
(void)_ctx; /* -Wunused-parameter */
|
||||||
|
}
|
||||||
|
|
|
@ -16,20 +16,20 @@ zx7enc(
|
||||||
unsigned char *src = _src;
|
unsigned char *src = _src;
|
||||||
unsigned char *dst = _dst;
|
unsigned char *dst = _dst;
|
||||||
|
|
||||||
int hlen = 8; /* header length; required due to MM's archives */
|
extern int g_hlen; /* header length */
|
||||||
memset(dst, 0, hlen);
|
memset(dst, 0, g_hlen);
|
||||||
memcpy(dst, "ZX70", 4);
|
memcpy(dst, "ZX70", 4);
|
||||||
dst[4] = (src_sz >> 24);
|
dst[4] = (src_sz >> 24);
|
||||||
dst[5] = (src_sz >> 16);
|
dst[5] = (src_sz >> 16);
|
||||||
dst[6] = (src_sz >> 8);
|
dst[6] = (src_sz >> 8);
|
||||||
dst[7] = (src_sz >> 0);
|
dst[7] = (src_sz >> 0);
|
||||||
|
|
||||||
*dst_sz = ZX7Compress(src, src_sz, dst + hlen);
|
*dst_sz = ZX7Compress(src, src_sz, dst + g_hlen);
|
||||||
|
|
||||||
if (!*dst_sz)
|
if (!*dst_sz)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
*dst_sz += hlen;
|
*dst_sz += g_hlen;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "rom.h"
|
#include "rom.h"
|
||||||
|
|
||||||
FILE* printer;
|
FILE* printer;
|
||||||
|
int g_hlen = 8;
|
||||||
|
|
||||||
static void compress(struct rom *rom, int start, int end)
|
static void compress(struct rom *rom, int start, int end)
|
||||||
{
|
{
|
||||||
|
@ -167,6 +168,7 @@ static void usage(void)
|
||||||
fprintf(printer, " yaz\n");
|
fprintf(printer, " yaz\n");
|
||||||
fprintf(printer, " ucl\n");
|
fprintf(printer, " ucl\n");
|
||||||
fprintf(printer, " lzo\n");
|
fprintf(printer, " lzo\n");
|
||||||
|
fprintf(printer, " zlib\n");
|
||||||
fprintf(printer, " aplib\n");
|
fprintf(printer, " aplib\n");
|
||||||
fprintf(printer, " * to use non-yaz codecs, find patches\n");
|
fprintf(printer, " * to use non-yaz codecs, find patches\n");
|
||||||
fprintf(printer, " and code on my z64enc repo\n");
|
fprintf(printer, " and code on my z64enc repo\n");
|
||||||
|
@ -184,6 +186,8 @@ static void usage(void)
|
||||||
fprintf(printer, "\n");
|
fprintf(printer, "\n");
|
||||||
fprintf(printer, " --skip disable compression on specified files\n");
|
fprintf(printer, " --skip disable compression on specified files\n");
|
||||||
fprintf(printer, "\n");
|
fprintf(printer, "\n");
|
||||||
|
fprintf(printer, " --headerless don't write file headers (for iQue)\n");
|
||||||
|
fprintf(printer, "\n");
|
||||||
fprintf(printer, " --repack handles Majora's Mask archives\n");
|
fprintf(printer, " --repack handles Majora's Mask archives\n");
|
||||||
fprintf(printer, "\n");
|
fprintf(printer, "\n");
|
||||||
fprintf(printer, " --threads optional multithreading;\n");
|
fprintf(printer, " --threads optional multithreading;\n");
|
||||||
|
@ -209,6 +213,7 @@ wow_main
|
||||||
int Athreads = 0;
|
int Athreads = 0;
|
||||||
bool Amatching = false;
|
bool Amatching = false;
|
||||||
bool Aonly_stdout = false;
|
bool Aonly_stdout = false;
|
||||||
|
bool Aheaderless = false;
|
||||||
wow_main_argv;
|
wow_main_argv;
|
||||||
|
|
||||||
printer = stderr;
|
printer = stderr;
|
||||||
|
@ -253,6 +258,15 @@ wow_main
|
||||||
i--;
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(arg, "--headerless"))
|
||||||
|
{
|
||||||
|
if (Aheaderless)
|
||||||
|
die("--headerless arg provided more than once");
|
||||||
|
Aheaderless = true;
|
||||||
|
g_hlen = 0;
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* arguments with additional parameters */
|
/* arguments with additional parameters */
|
||||||
|
|
||||||
|
|
|
@ -462,6 +462,14 @@ static const struct encoder *encoder(const char *name)
|
||||||
|
|
||||||
return &zx7;
|
return &zx7;
|
||||||
}*/
|
}*/
|
||||||
|
else if (!strcmp(name, "zlib"))
|
||||||
|
{
|
||||||
|
static const struct encoder zlib = {
|
||||||
|
.encfunc = zlibenc
|
||||||
|
};
|
||||||
|
|
||||||
|
return &zlib;
|
||||||
|
}
|
||||||
else if (!strcmp(name, "aplib"))
|
else if (!strcmp(name, "aplib"))
|
||||||
{
|
{
|
||||||
static const struct encoder aplib = {
|
static const struct encoder aplib = {
|
||||||
|
@ -1112,7 +1120,7 @@ void rom_compress(struct rom *rom, int mb, int numThreads, bool matching)
|
||||||
comp_total += sz16;
|
comp_total += sz16;
|
||||||
|
|
||||||
if (mb != 0 && dma->Pend > compsz)
|
if (mb != 0 && dma->Pend > compsz)
|
||||||
die("ran out of compressed rom space");
|
die("ran out of compressed rom space (try increasing --mb)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adaptive final size */
|
/* adaptive final size */
|
||||||
|
@ -1660,6 +1668,14 @@ struct rom *rom_new(const char *fn)
|
||||||
/* propagate rom file */
|
/* propagate rom file */
|
||||||
dst->data = file_load(fn, &dst->data_sz);
|
dst->data = file_load(fn, &dst->data_sz);
|
||||||
|
|
||||||
|
/* double its bounds just in case compressed rom is larger
|
||||||
|
* (this can happen if, say, a 23mb rom is provided,
|
||||||
|
* gets compressed to 17mb, and is rounded up to 24mb)
|
||||||
|
* (retail rom sizes always use increments of 8)
|
||||||
|
*/
|
||||||
|
dst->data_sz *= 2;
|
||||||
|
dst->data = realloc(dst->data, dst->data_sz);
|
||||||
|
|
||||||
/* back up load file name */
|
/* back up load file name */
|
||||||
dst->fn = strdup_safe(fn);
|
dst->fn = strdup_safe(fn);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue