Views: 57,685,053
Main | FAQ | Uploader | IRC chat | Radio | Memberlist | Active users | Latest posts | Calendar | Stats | Online users | Search 07-12-20 11:36 PM
Guest: Register | Login

0 users currently in ROM Hacking | 1 guest | 1 bot

Main - ROM Hacking - SMA4 level card level compressor New thread | Thread closed


RANDY Ruler of Zexernet
Posted on 10-01-07 05:35 AM (rev. 2 of 10-01-07 05:36 AM) Link | Quote | ID: 66807


Shyguy
Level: 22

Posts: 10/89
EXP: 57834
Next: 516

Since: 07-17-07
From: Arizona, US

Last post: 3247 days
Last view: 209 days
I am not sure if this has been posted before, but I once saw someone say that the Super Mario Advance 4 level e-cards are encrypted (the actual level data, not the raw e-Reader card data). They are not - they are merely compressed using a dictionary compressor, after which the data & offset streams are separately compressed using range coding, then concatenated. Someone else already decompiled the decompressor, so I made a compressor.

Call compress with the size of the level, a pointer to the level data, the mode (0x00 or 0x80, use whichever gives a smaller output size), & a pointer to the destination buffer (which should be large enough - how large is left as an exercise for the reader). It writes the complete level (suitable for placing in the EEPROM save, though there might be more needed to print a level card) to the destination buffer.

Code for compressor ((poorly) written in ISO C99):

#include<stdint.h>
int range(int size,int*src,int ws,char*dst){
unsigned di=0,c[0x1000],t[0x1001],l=0,w=0xFFFFFFFF;
for(int x=0;x<ws;x++){c[x]=1;t[x]=x;}t[ws]=ws;
for(int si=0;si<size;si++){int n=src[si];
l+=t[n]*(w/=t[ws]);w*=c[n]++;for(int x=n;x<ws;t[++x]++);
if(t[ws]>0xFFFF){t[0]=0;for(int x=0;x<ws;x++)t[x+1]=t[x]+(c[x]=c[x]>>1|1);}
while((l&0xFF000000)==(l+w&0xFF000000)){dst[di++]=l>>24;l<<=8;w<<=8;}
while(w<=0xFFFF){w=(0x10000-(l&0xFFFF))<<8;dst[di++]=l>>24;l<<=8;}}
while((l&0xFF000000)==(l+w&0xFF000000)){dst[di++]=l>>24;l<<=8;w<<=8;}
dst[di++]=(l>>24);return di;}
#define MIN(x,y) ((x)<(y)?(x): (y))
int compress(uint32_t size,uint8_t*src,uint8_t mode,uint8_t*dst){
int data[0x10000],offset[0x4000],di=0,oi=0,ws=mode&0x80?0x1000:0x200,ds,os;
dst[0]='A';dst[1]='S';dst[2]='R';dst[3]='0';
dst[4]=mode;dst[5]=size>>16;dst[6]=size>>8&0xFF;dst[7]=size&0xFF;
for(int si=0;si<size; ){int bo,bc=0;
for(int off=1;off<=MIN(si,ws);off++){int c;
for(c=0;c<MIN(size-si,0x102);c++)if(src[si-off+c]!=src[si+c])break;
if(c>bc){bo=off;bc=c;}}
if(bc>2){data[di++]=bc+0xFD;offset[oi++]=bo-1;si+=bc;}
else data[di++]=src[si++];}
ds=range(di,data,0x200,dst+12);
os=range(oi,offset,ws,dst+ds+12);
dst[8]=ds+12>>24;dst[9]=ds+12>>16&0xFF;
dst[10]=ds+12>>8&0xFF;dst[11]=ds+12&0xFF;
return ds+12+os;}

purplebridge001
Posted on 10-02-07 04:34 AM (rev. 2 of 10-15-07 07:34 AM) Link | Quote | ID: 66885

Newcomer
Level: 7

Posts: 2/7
EXP: 1267
Next: 181

Since: 09-13-07
From: Somewhere in world-e

Last post: 3907 days
Last view: 3907 days
Wow, great job!
We will be able to create home made levels!
If I remember correctly, we still need to fix the checksum (or something other) in the save data to actually work in SMA4.

EDIT:
It seems that the last byte of input can't compress correctly. (For example, "Hello" becomes "Helln")

caitsith2
Posted on 08-21-09 01:14 AM Link | Quote | ID: 113910

Newcomer
Level: 7

Posts: 1/8
EXP: 1427
Next: 21

Since: 08-21-09

Last post: 1917 days
Last view: 1629 days
I fixed a bug in the code, that was causing the last byte to not be compressed correctly. Smaller compression doesn't do any good, if it does not decompress correctly. Turns out more than just 1 byte of l, at the end of the range stream was actually required to correctly decompress the last byte.

Also dealt with some input validation while I was at it, and final output, in case of e-reader levels.

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

int range(int size,int*src,int ws,char*dst)
{
unsigned di=0,c[0x1000],t[0x1001],l=0,w=0xFFFFFFFF;
for(int x=0;x<ws;x++)
{
c[x]=1;
t[x]=x;
}
t[ws]=ws;
for(int si=0;si<size;si++)
{
int n=src[si];
l+=t[n]*(w/=t[ws]);w*=c[n]++;
for(int x=n;x<ws;t[++x]++);
if(t[ws]>0xFFFF)
{
t[0]=0;
for(int x=0;x<ws;x++)
t[x+1]=t[x]+(c[x]=c[x]>>1|1);
}
while((l&0xFF000000)==(l+w&0xFF000000))
{
dst[di++]=l>>24;
l<<=8;
w<<=8;
}
while(w<=0xFFFF)
{
w=(0x10000-(l&0xFFFF))<<8;
dst[di++]=l>>24;
l<<=8;
}
}
while((l&0xFF000000)==(l+w&0xFF000000))
{
dst[di++]=l>>24;
l<<=8;
w<<=8;
}
while(l&0xFF000000)
{
dst[di++]=(l>>24);
l<<=8;
}
return di;
}

#define MIN(x,y) ((x)<(y)?(x): (y))

int data[0x10000];
int offset[0x4000];

int compress(uint32_t size,uint8_t*src,uint8_t mode,uint8_t*dst)
{
int di=0,oi=0,ws=mode&0x80?0x1000:0x200,ds,os;
dst[0]='A';
dst[1]='S';
dst[2]='R';
dst[3]='0';

dst[4]=mode;
dst[5]=size>>16;
dst[6]=size>>8&0xFF;
dst[7]=size&0xFF;

for(int si=0;si<size; )
{
int bo,bc=0;
for(int off=1;off<=MIN(si,ws);off++)
{
int c;
for(c=0;c<MIN(size-si,0x102);c++)
if(src[si-off+c]!=src[si+c])
break;
if(c>bc)
{
bo=off;
bc=c;
}
}
if(bc>2)
{
data[di++]=bc+0xFD;
offset[oi++]=bo-1;
si+=bc;
}
else
data[di++]=src[si++];
}
//di+=4;
ds=range(di,data,0x200,(char*)dst+12);
os=range(oi,offset,ws,(char*)dst+ds+12);
dst[8]=ds+12>>24;
dst[9]=ds+12>>16&0xFF;
dst[10]=ds+12>>8&0xFF;
dst[11]=ds+12&0xFF;
return ds+12+os;
}


// [insert the code in the post here]
int main(int argc, char* argv[])
{
if(argc<3)
{
printf("Usage: compress <in_file> <out_file>\n");
return -1; // too few arguments
}
FILE *flin=fopen(argv[1],"rb");
FILE *flout=fopen(argv[2],"wb");
if((flin==NULL)||(flout==NULL))
{
printf("Error opening in/out file\n");
return -1;
}
char buf1[409600],buf2[409600]; //400KB each
int size=fread(buf1,1,409600,flin);
size=compress(size,(uint8_t*)buf1,0,(uint8_t*)buf2);
fwrite(buf2,1,size,flout);
if(size>0x7C6)
printf("This level will not work on an e-reader.\n");
fclose(flin);fclose(flout);
return 0;
}



KP9000
Posted on 08-21-09 03:54 AM Link | Quote | ID: 113922


Boomboom

Level: 86

Posts: 927/1975
EXP: 6139316
Next: 2791

Since: 02-19-07

Last post: 2196 days
Last view: 1820 days


I would like to refer you to this thread regarding anything SMA4-related. Lots of stuff has been going on in there and is a great place for you guys to put your data and ask questions.

Since that thread exists, there's no point in having this one since the other one covers this. I'll close it.

____________________

Main - ROM Hacking - SMA4 level card level compressor New thread | Thread closed

Acmlmboard 2.1+3δ (2016-01-08)
© 2005-2016 Acmlm, blackhole89, Xkeeper et al.

Page rendered in 0.033 seconds. (342KB of memory used)
MySQL - queries: 51, rows: 75/0, time: 0.023 seconds.