Created
March 7, 2020 00:12
-
-
Save bnnm/1d771a406cc2900320fe8df2aa981d12 to your computer and use it in GitHub Desktop.
LZX from XNB decompressor
This file contains hidden or 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
| // 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