Skip to content

Instantly share code, notes, and snippets.

@bnnm
Created March 7, 2020 00:12
Show Gist options
  • Select an option

  • Save bnnm/1d771a406cc2900320fe8df2aa981d12 to your computer and use it in GitHub Desktop.

Select an option

Save bnnm/1d771a406cc2900320fe8df2aa981d12 to your computer and use it in GitHub Desktop.
LZX from XNB decompressor
// Decompresses LZX found in XNB (just a test tool for vgmstream, may be of use for XMemCompress testing).
// Needs lzx.c/h, see below
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
/* lib from https://github.com/sumatrapdfreader/chmlib
* which is a cleaned-up version of https://github.com/jedwing/CHMLib */
#include "lzx.h"
/* Decompresses LZX used in XNB. Has 16b window and headered blocks (with input size and
* optionally output size) and standard LZX inside, probably what's known as XMemCompress.
* Info: https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Utilities/LzxStream/LzxDecoderStream.cs */
uint32_t read_u32le(uint8_t* buf) {
return (buf[0] << 0) | (buf[1] << 8u) | (buf[2] << 16u) | (buf[3] << 24u);
}
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("LZ4 decoder by bnnm\nUsage: %s infile\n", argv[0]);
return 1;
}
FILE* f_out = NULL;
FILE* f_in = NULL;
f_in = fopen(argv[1], "rb");
if (f_in == NULL) {
printf("cannot open infile %s", argv[1]);
goto end;
}
char s_out[32768];
strcpy(s_out, argv[1]);
strcat(s_out, ".dec");
f_out = fopen(s_out, "wb");
if (f_out == NULL) {
printf("cannot open outfile %s", s_out);
goto end;
}
fseek(f_in, 0, SEEK_END);
int src_size = ftell(f_in);
fseek(f_in, 0, SEEK_SET);
uint8_t header[0x0e];
fread(header, 1, sizeof(header), f_in);
int dec_size = read_u32le(header + 0x0a);
uint8_t dst[0x8000];
uint8_t src[0x8000];
struct lzx_state* strm = lzx_init(16);
if (!strm) {
printf("bad lzx init\n");
goto end;
}
int bytes = 0;
while (bytes < dec_size) {
int src_size, dst_size, hi, lo;
hi = fgetc(f_in);
if (hi == 0xFF) {
hi = fgetc(f_in);
lo = fgetc(f_in);
dst_size = (hi << 8) | lo;
hi = fgetc(f_in);
lo = fgetc(f_in);
src_size = (hi << 8) | lo;
}
else {
dst_size = 0x8000;
lo = fgetc(f_in);
src_size = (hi << 8) | lo;
}
if (src_size == 0 || dst_size == 0) {
printf("EOF\n");
break;
}
fread(src, sizeof(uint8_t), src_size, f_in);
int ret = lzx_decompress(strm, src, dst, src_size, dst_size);
if (ret != DECR_OK) {
printf("ret=%i\n", ret);
break;
}
fwrite(dst, sizeof(uint8_t), dst_size, f_out);
bytes += dst_size;
}
lzx_teardown(strm);
end:
fclose(f_in);
fclose(f_out);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment