Views: 55,887,021
Main | FAQ | Uploader | IRC chat | Radio | Memberlist | Active users | Latest posts | Calendar | Stats | Online users | Search 02-26-20 04:07 AM
Guest: Register | Login

0 users currently in ROM Hacking | 4 guests

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: 56988
Next: 1362

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

Last post: 3109 days
Last view: 72 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: 1249
Next: 199

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

Last post: 3769 days
Last view: 3769 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: 1402
Next: 46

Since: 08-21-09

Last post: 1779 days
Last view: 1491 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: 6052260
Next: 89847

Since: 02-19-07

Last post: 2059 days
Last view: 1683 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.095 seconds. (341KB of memory used)
MySQL - queries: 51, rows: 74/0, time: 0.052 seconds.