Skip to content

Instantly share code, notes, and snippets.

@andwn
Created October 20, 2017 16:44
Show Gist options
  • Select an option

  • Save andwn/5a9cbcea24700eb9d6f2335a57340968 to your computer and use it in GitHub Desktop.

Select an option

Save andwn/5a9cbcea24700eb9d6f2335a57340968 to your computer and use it in GitHub Desktop.

Revisions

  1. andwn created this gist Oct 20, 2017.
    90 changes: 90 additions & 0 deletions flax.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,90 @@
    // Compile
    // gcc flax.c -o flax
    // Usage
    // ./flax <input file>
    // Outputs decompressed data to <input file>.out

    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    // Based on disassembled Glover.exe sub_4C6E40
    int flax(uint8_t *src, uint8_t *dest) {
    int outSize = 0;
    uint8_t ring[0x1000];
    uint16_t ringPos = 0;
    memset(ring, 0, 0x1000);

    uint8_t command;

    LABEL_2:
    command = *src++;
    for(int i = 0; ; ++i) {
    if(i == 8) goto LABEL_2;
    if(!(command & 0x80)) {
    uint8_t val = *src++;
    *dest++ = val;
    ++outSize;
    ring[ringPos] = val;
    ringPos = (ringPos + 1) & 0xFFF;
    command *= 2;
    continue;
    }
    uint8_t dataLen = *src;
    if(!dataLen) break;
    uint8_t *dataPtr = src + 1;
    int16_t dataRingPos = 4096 - (*dataPtr + 16 * (dataLen & 0xF0));
    src = dataPtr + 1;
    for(int j = (dataLen & 0xF) + 2; j; --j) {
    uint8_t val = ring[(ringPos + dataRingPos) & 0xFFF];
    *dest++ = val;
    ++outSize;
    ring[ringPos] = val;
    ringPos = (ringPos + 1) & 0xFFF;
    }
    command *= 2;
    }
    return outSize;
    }

    int main(int argc, char *argv[]) {
    uint8_t buffer[0x400000]; // 4MB decompression buffer

    if(argc != 2) {
    printf("Usage: flax <input file>\n");
    return EXIT_SUCCESS;
    }

    FILE *file = fopen(argv[1], "rb");
    if(!file) {
    printf("FATAL: Failed to read input file '%s'.\n", argv[1]);
    return EXIT_FAILURE;
    }
    fseek(file, 0, SEEK_END);
    int size = ftell(file);
    fseek(file, 0, SEEK_SET);
    uint8_t *fla = malloc(size);
    fread(fla, 1, size, file);
    fclose(file);
    printf("Loaded %d byte file.\n", size);

    if(fla[0]=='F' && fla[1]=='L' && fla[2]=='A' && fla[3]=='2') {
    int decSize = flax(&fla[8], buffer);
    printf("%d bytes extracted.\n", decSize);
    char fn[256];
    sprintf(fn, "%s.out", argv[1]);
    file = fopen(fn, "wb");
    if(!file) {
    printf("\nERROR: Unable to write output file '%s'.\n", fn);
    } else {
    fwrite(buffer, 1, decSize, file);
    fclose(file);
    }
    } else {
    printf("...but it's not FLA compressed.\n");
    }

    free(fla);
    return EXIT_SUCCESS;
    }