-
-
Save simontime/0521158a4bca0cba0d1f24ed71cceb60 to your computer and use it in GitHub Desktop.
decompression code from My Pokemon Ranch, seems similar to the ash used by the Wii Menu
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
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
uint16_t left9[0x400]; | |
uint16_t right9[0x400]; | |
uint16_t left12[0x10000]; | |
uint16_t right12[0x10000]; | |
uint32_t stack[0x100]; | |
int bitlen[2]; | |
int ccnt[2]; | |
int wptr[2]; | |
uint32_t bitcode[2]; | |
int getbitsc(uint8_t* input, int size, int type) | |
{ | |
int k, m; | |
uint32_t i, j, g; | |
k = wptr[type]; | |
m = bitlen[type]; | |
g = bitcode[type]; | |
if (m + size > 32) | |
{ | |
j = (input[k] << 24) | (input[k + 1] << 16) | (input[k + 2] << 8) | input[k + 3]; | |
wptr[type] = k + 4; | |
bitlen[type] = m + size - 32; | |
bitcode[type] = j << bitlen[type]; | |
i = (g >> (32 - size)) | (j >> (64 - size - m)); | |
} | |
else if (m + size == 32) | |
{ | |
wptr[type] = k + 4; | |
bitlen[type] = 0; | |
bitcode[type] = (input[k] << 24) | (input[k + 1] << 16) | (input[k + 2] << 8) | input[k + 3]; | |
i = g >> (32 - size); | |
} | |
else | |
{ | |
bitlen[type] = m + size; | |
bitcode[type] = g << size; | |
i = g >> (32 - size); | |
} | |
return i; | |
} | |
int readtree9(uint8_t* input) | |
{ | |
int f, m, j, z, sp; | |
for (j = m = ccnt[0], sp = 0; ;) | |
{ | |
if (getbitsc(input, 1, 0)) | |
{ | |
stack[sp] = j | 0x80000000; | |
stack[sp + 1] = j | 0x40000000; | |
j++; | |
m++; | |
sp += 2; | |
} | |
else | |
{ | |
z = getbitsc(input, 9, 0); | |
while (1) | |
{ | |
f = stack[--sp]; | |
if (!(f & 0x80000000)) | |
{ | |
left9[f & 0x3FFFFFFF] = z; | |
j = m; | |
break; | |
} | |
else | |
{ | |
right9[f & 0x3FFFFFFF] = z; | |
z = f & 0x3FFFFFFF; | |
if (sp == 0) | |
return z; | |
} | |
} | |
} | |
} | |
} | |
int readtree12(uint8_t* input) | |
{ | |
int f, m, j, z, sp; | |
for (j = m = ccnt[1], sp = 0; ;) | |
{ | |
if (getbitsc(input, 1, 1)) | |
{ | |
stack[sp] = j | 0x80000000; | |
stack[sp + 1] = j | 0x40000000; | |
j++; | |
m++; | |
sp += 2; | |
} | |
else | |
{ | |
z = getbitsc(input, 15, 1); | |
while (1) | |
{ | |
f = stack[--sp]; | |
if (!(f & 0x80000000)) | |
{ | |
left12[f & 0x3FFFFFFF] = z; | |
j = m; | |
break; | |
} | |
else | |
{ | |
right12[f & 0x3FFFFFFF] = z; | |
z = f & 0x3FFFFFFF; | |
if (sp == 0) | |
return z; | |
} | |
} | |
} | |
} | |
} | |
int decode_ash(uint8_t* input, uint8_t* output) | |
{ | |
int i, j, k, q, t, root9, root12; | |
t = (input[4] << 24) | (input[5] << 16) | (input[6] << 8) | input[7]; | |
k = (input[8] << 24) | (input[9] << 16) | (input[10] << 8) | input[11]; | |
wptr[0] = 12; | |
wptr[1] = k; | |
bitlen[0] = 0; | |
bitlen[1] = 0; | |
ccnt[0] = 0x200; | |
ccnt[1] = 0x8000; | |
getbitsc(input, 32, 0); | |
getbitsc(input, 32, 1); | |
root9 = readtree9(input); | |
root12 = readtree12(input); | |
for (q = 0; q < t;) | |
{ | |
j = root9; | |
while (j >= 0x200) | |
{ | |
if (getbitsc(input, 1, 0)) | |
j = right9[j]; | |
else | |
j = left9[j]; | |
} | |
if (j < 0x100) | |
{ | |
output[q++] = j; | |
} | |
else | |
{ | |
i = root12; | |
while (i >= 0x8000) | |
{ | |
if (getbitsc(input, 1, 1)) | |
i = right12[i]; | |
else | |
i = left12[i]; | |
} | |
j -= 253; | |
i = q - i - 1; | |
for (; j > 0; j--, q++, i++) | |
output[q] = output[i]; | |
} | |
} | |
return q; | |
} | |
int main(int argc, char **argv) | |
{ | |
char *fname; | |
FILE *fin, *fout; | |
int lengthin, lengthout; | |
uint8_t *bufin, *bufout; | |
// Ensure correct number of arguments | |
if (argc < 2) | |
{ | |
printf("Usage: %s input.ash\n", argv[0]); | |
return 0; | |
} | |
// Try to open input file | |
if ((fin = fopen(argv[1], "rb")) == NULL) | |
{ | |
perror("Error opening input file"); | |
return 1; | |
} | |
// Duplicate output file name | |
fname = strdup(argv[1]); | |
// Remove '.ash' from output name | |
for (int i = strlen(fname) - 1; i >= 0; i--) | |
{ | |
// Look for '.' | |
if (fname[i] == '.') | |
{ | |
// Replace it with a null terminator | |
fname[i] = 0; | |
break; | |
} | |
} | |
// Try to open output file | |
if ((fout = fopen(fname, "wb")) == NULL) | |
{ | |
perror("Error opening output file"); | |
return 1; | |
} | |
// De-allocate output file name | |
free(fname); | |
// Get input file size | |
fseek(fin, 0, SEEK_END); | |
lengthin = ftell(fin); | |
rewind(fin); | |
// Allocate input buffer | |
bufin = malloc(lengthin); | |
// Read input file into input buffer and close | |
fread(bufin, 1, lengthin, fin); | |
fclose(fin); | |
// Allocate output buffer, assuming a compression ratio no greater than 8:1 | |
bufout = malloc(lengthin * 8); | |
// Decompress ASH from input buffer to output buffer | |
lengthout = decode_ash(bufin, bufout); | |
// Write output buffer to output file and close | |
fwrite(bufout, 1, lengthout, fout); | |
fclose(fout); | |
// De-allocate buffers | |
free(bufin); | |
free(bufout); | |
puts("Done!"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment