Yet Another Gamecube Documentation

12  Memory Card Structure


index

12.1  Overview


one "block" on memcard equals 0x2000 bytes, the first 5 blocks are used for the filesystem (0xa000 bytes).

Offset Size Description
0x0000 0x2000 Header
0x2000 0x2000 Directory
0x4000 0x2000 Directory backup (*)
0x6000 0x2000 Block Allocation Map
0x8000 0x2000 Block Allocation Map backup (*)
0xa000   file(s) data


(*) If a change is to be made that will alter the Master File Table, such as moving or deleting a file, copying a file from another memory card, or creating a new save game file, the GameCube will first backup the Master File Table to this location. Presumably, if the operation fails for certain reasons, the GameCube will restore the Backup File Table to the Master File Table.
index

12.2  Header


Offset Size Description
0x0000   ?
0x000c 8 time of format (OSTime value)
0x0014   unique card id (?)
0x0020 2 padding zeroes
0x0022 2 size of memcard in Mbits
0x0024 2 encoding (ASCII or japanese)
0x0026   unused (0xff)
0x01fa 2 update Counter (?, probably unused)
0x01fc 2 Checksum 1 (?)
0x01fe 2 Checksum 2 (?)
0x0200 0x1e00 unused (0xff)

index

12.3  Directory


Offset Size Description
0x0000   Directory Entries (max 127)
0x0ffa 2 update Counter
0x0ffc 2 Checksum 1
0x0ffe 2 Checksum 2

index

12.3.1  Directory Entries


offset length description
0x00 0x04 Gamecode
0x04 0x02 Makercode
0x06 0x01 reserved/unused (always 0xff, has no effect)
0x07 0x01 banner gfx format and icon animation (Image Key)
   
bit(s) description
2 Icon Animation 0: forward 1: ping-pong
1 0: No Banner 1: Banner present
0 Banner Color 0: RGB5A3 1: CI8
0x08 0x20 filename
0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000
0x2c 0x04 image data offset
0x30 0x02 icon gfx format (2bits per icon)
   
bits Description
00 no icon
01 CI8 with a shared color palette after the last frame
10 RGB5A3
11 CI8 with a unique color palette after itself
0x32 0x02 animation speed (2bits per icon) (*1)
   
bits Description
00 no icon
01 Icon lasts for 4 frames
10 Icon lasts for 8 frames
11 Icon lasts for 12 frames
0x34 0x01 file-permissions
   
bit permission Description
4 no move File cannot be moved by the IPL
3 no copy File cannot be copied by the IPL
2 public Can be read by any game
0x35 0x01 copy counter (*2)
0x36 0x02 block no of first block of file (0 == offset 0)
0x38 0x02 file-length (number of blocks in file)
0x3a 0x02 reserved/unused (always 0xffff, has no effect)
0x3c 0x04 Address of the two comments within the file data (*3)


(*1) Clearly, the animation rate is unimportant when there is only one frame of icon data; nevertheless, a value for that one frame must still be set, or that one frame will not be shown. It is illegal to specify that a frame does not exist if it does; a value of 00 indicates that no frame exists, and should not be mistaken for meaning that this frame should not be shown. If you specify blank frames to slow the frame rate, these also cannot be 00.

(*2) This byte contains an 8-bit integer that indicates how many times the file has been copied from one memory card to another.

(*3) Each file has two 32 character strings which the IPL displays at the bottom of the memory card screen, next to the banner. The two strings (64 bytes) must fit within one block (8192 bytes), they are not allowed to cross sector boundaries.
12.3.1.1   Image Data

Image data consists of a banner image and an icon. The banner image is not required, dependant on the value of the Image Key. If the banner image is not present, the icon image is displayed where the banner image would be displayed (centered horizontally). The icon image is required, and immediately follows the banner if present. Otherwise, it is located at the start of the image data.
    12.3.1.1.1  Banner Image   The banner size is 96*32 pixels, making 3072 pixels in total (= 0x0c00 bytes in 8bit, 0x1800 bytes in 16bit mode). If the Banner is in CI8 mode, the palette follows immediately after the banners pixel data.
    12.3.1.1.2  Icon Image   Immediately following the banner (if present) is the Icon Image. This can have a variable number of frames (up to eight), each 32*32 pixels, making 1024 pixels per frame in total. (= 0x0400 bytes in 8bit, 0x0800 byte in 16bit mode). If the Icon is in CI8 mode, its palette either follows immediately after its pixel data or after the pixel data of all 8 icons, depending on the icon gfx format field.
    12.3.1.1.3  Palettes   Palettes in the image data are in RGB5A3 pixel format, and are 0x100 entries large. (= 0x200 bytes)
index

12.4  Block Allocation Map


Offset Size Description
0x0000 2 Checksum 1
0x0002 2 Checksum 2
0x0004 2 update Counter
0x0006 2 free Blocks
0x0008 2 last allocated Block
0x000a 0x1ff8 Map of allocated Blocks


This is an array of 0x0ffc 16 bit values, each holding info about one allocated block on the memory card. (thus the maximum memcard size is limited to 2048 blocks (16 Megabytes, 128Mbit))

each 16 bit value at position X in the array has the following meaning:

value Description
0x0000 block is not allocated (ie, free)
0xffff last allocated block of a file
any other allocated block, usually equals (x+1) (==next block of file)


scan through a file like this:

thisblock=firstblock;
do
{
    // process block
    // next block
    thisblock=((unsigned short*)0x6000)[thisblock];
}
while (thisblock!=0xffff); 
 
note:

although this scheme could do it, i have never stumbled about a file yet that is NOT linear on the memcard anyway. from this point of view using this allocation map seems to be a bit stupid...more testing needed :)
index

12.5  Checksums


The Checksums for the Directory and Block Allocation Map are simple 16bit additive checksums (ie nothing fancy or particular safe) which can be easily calculated like this:

void checksums(unsigned short *buf, int num, unsigned short *c1, unsigned short *c2)
{
    int i;
    *c1 = 0;*c2 = 0;
    for (i = 0; i < num; ++i)
    {
        *c1 += buf[i];
        *c2 += (buf[i] ^ 0xffff);
    }
    if (*c1 == 0xffff)
    {
        *c1 = 0;
    }
    if (*c2 == 0xffff)
    {
        *c2 = 0;
    }
}
index