Skip to content

Instantly share code, notes, and snippets.

@simontime
Forked from NWPlayer123/decode_ash.c
Last active February 11, 2023 01:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simontime/0521158a4bca0cba0d1f24ed71cceb60 to your computer and use it in GitHub Desktop.
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
#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