Browse Source

Initial commit

master
mid-kid 5 years ago
commit
f952a0ab5b
  1. 47
      Makefile
  2. 149
      source/main.c

47
Makefile

@ -0,0 +1,47 @@
name := ovldec
dir_source := source
dir_build := build
CFLAGS := -O0 -g -Wall -Wextra -std=c17 $(CFLAGS)
CFLAGS += #$(shell pkg-config --cflags ...)
LDLIBS += #$(shell pkg-config --libs ...)
SANIT := -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=leak -fsanitize=undefined
OPTIM := -Os -fdata-sections -ffunction-sections -flto -fuse-linker-plugin -fipa-pta -Wl,--gc-sections -Wl,--print-gc-sections -fgraphite-identity -floop-nest-optimize
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
objects := $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, $(call rwildcard, $(dir_source)/, *.c))
.SECONDEXPANSION:
.PHONY: all
all: $(name)
.PHONY: clean
clean:
rm -rf $(dir_build) $(name)
.PHONY: sanit
sanit: CFLAGS += $(SANIT)
sanit: LDFLAGS += $(SANIT)
sanit: $(name)
.PHONY: optim
optim: CFLAGS += $(OPTIM)
optim: LDFLAGS += $(OPTIM)
optim: $(name)
strip --strip-all --strip-unneeded $(name)
$(name): $(objects)
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
$(dir_build)/%.o: $(dir_source)/%.c | $$(dir $$@)
$(COMPILE.c) -MMD -MF $(@:.o=.d) $(OUTPUT_OPTION) $<
.PRECIOUS: %/
%/:
mkdir -p $@
-include $(patsubst %.o, %.d, $(objects))

149
source/main.c

@ -0,0 +1,149 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// This is a LZ77-esque compression algorithm.
// However, unlike LZ77, it decompresses itself in-place.
// This is done by storing and reading the compressed data _backwards_,
// and writing the decompressed data far beyond the end of the compressed blob.
// Of course, that's not a *requirement* of any sort.
void nitro_decompress(void *header)
{
if (!header) return;
unsigned dest_offset = *((uint32_t *)header - 1);
unsigned data_offset = *((uint32_t *)header - 2) >> 24;
unsigned end_offset = *((uint32_t *)header - 2) & 0xFFFFFF;
// Compressed size: end_offset
// Header + padding size: data_offset
// Decompressed size: dest_offset + end_offset + 1
uint8_t *dest = (uint8_t *)header + dest_offset;
uint8_t *data = (uint8_t *)header - data_offset;
uint8_t *end = (uint8_t *)header - end_offset;
while (data > end) {
uint8_t flags = *--data;
for (int i = 8; i > 0; i--) {
if (flags & 0x80) {
unsigned length = ((*(data - 1) & 0xF0) >> 4) + 3;
unsigned offset = (((*(data - 1) & 0x0F) << 8) | *(data - 2)) + 2;
data -= 2;
for (unsigned x = length; x > 0; x--) {
char d = *(dest + offset);
*--dest = d;
}
} else {
*--dest = *--data;
}
flags <<= 1;
if (data <= end) break;
}
}
return;
}
void usage(const char *prgname)
{
fprintf(stderr, "Usage: %s [-o offset] [--] <in> <out>\n", prgname);
exit(1);
}
int main(int argc, char *argv[])
{
FILE *f;
int argi = 1;
int offset = 0;
for (;;) {
if (argc <= argi) usage(argv[0]);
if (argv[argi][0] != '-') break;
if (strcmp(argv[argi], "--") == 0) {
argi++;
break;
} else if (strcmp(argv[argi], "-o") == 0) {
if (argc <= argi + 1) {
fprintf(stderr, "-o: Missing offset\n");
usage(argv[0]);
}
offset = strtol(argv[argi + 1], NULL, 0);
argi += 2;
} else {
fprintf(stderr, "Unrecognized option: '%s'\n", argv[argi]);
usage(argv[0]);
}
}
if (argc < argi + 2) {
fprintf(stderr, "Missing parameters\n");
usage(argv[0]);
}
f = fopen(argv[argi + 0], "r");
if (!f) {
perror("fopen");
return 1;
}
// Find the "header" in the file
if (!offset) {
fseek(f, 0, SEEK_END);
} else if (offset < 0) {
fseek(f, offset, SEEK_END);
} else if (offset > 0) {
fseek(f, offset, SEEK_SET);
}
// Figure out the length and decompressed length of the file
uint32_t f_len;
uint32_t f_declen;
fseek(f, -(sizeof(f_declen) + sizeof(f_len)), SEEK_CUR);
if (fread(&f_len, sizeof(f_len), 1, f) != 1) {
perror("fread");
return 1;
}
if (fread(&f_declen, sizeof(f_declen), 1, f) != 1) {
perror("fread");
return 1;
}
f_len = f_len & 0xFFFFFF;
if (f_len % 4 != 0) f_len += 4 - (f_len % 4);
f_declen += f_len;
if (fseek(f, -(size_t)f_len, SEEK_CUR)) {
perror("fseek");
return 1;
}
// Read the file
void *file = malloc(f_declen);
if (!file) {
perror("malloc");
return 1;
}
if (fread(file, 1, f_len, f) != f_len) {
perror("fread");
return 1;
}
fclose(f);
nitro_decompress((char *)file + f_len);
// Save the output
f = fopen(argv[argi + 1], "w");
if (!f) {
perror("fopen");
return 1;
}
fwrite(file, f_declen, 1, f);
fclose(f);
free(file);
return 0;
}
Loading…
Cancel
Save