Points of Required Attention™
Smaghetti, a new Super Mario Advance 4 editor, is currently in development! Check out the thread HERE!

Please chime in on a proposed restructuring of the ROM hacking sections.
Views: 88,313,417
Main | FAQ | Uploader | IRC chat | Radio | Memberlist | Active users | Latest posts | Calendar | Stats | Online users | Search 03-28-24 03:39 PM
Guest: Register | Login

0 users currently in ROM Hacking | 1 guest | 2 bots

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: 23

Posts: 10/89
EXP: 65573
Next: 2150

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

Last post: 4601 days
Last view: 226 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: 1439
Next: 9

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

Last post: 5262 days
Last view: 5262 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: 8

Posts: 1/8
EXP: 1652
Next: 535

Since: 08-21-09

Last post: 3272 days
Last view: 2984 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: 90

Posts: 927/1975
EXP: 6937400
Next: 251209

Since: 02-19-07

Last post: 3551 days
Last view: 3175 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+4δ (2023-01-15)
© 2005-2023 Acmlm, blackhole89, Xkeeper et al.

Page rendered in 0.014 seconds. (342KB of memory used)
MySQL - queries: 52, rows: 76/76, time: 0.010 seconds.