-
Notifications
You must be signed in to change notification settings - Fork 12
Yaz0 and Yay0
##Yaz0
Yaz0 is a hybrid of RLE compression. (ShizZie says: "This is somewhat misleading. Run length encoding is only compression on a character-to-character basis, i.e. aaabbbbcccccc encodes to a2b3c5. Yaz0 compresses string-to-string, so it's more like LZMA."
You can see if you're dealing with the following compression if the first 4 bytes of the 16 byte long header contains Y a z 0. The second 4 bytes are in big-endian(uint32) and tells you how large the decompressed data is as well has give you a frame of reference on the size of your buffer. The following 8 bytes are always zero.
"First you read a "code" byte that tells you for the next 8 "read operations" what you have to do. Each bit of the "code" byte represents one "read operation" (from left to right, that is, 0x80 first, 0x01 last). If the bit is 1, copy one byte from the input buffer to the output buffer. Easy. If the bit is 0, things are a little bit more complicated, RLE compressed data is ahead. You have to read the next two bytes to decide how long your run is and what you should write to your output buffer.
15 8 7 0
a b
The upper nibble of the first byte (a) contains the information you need to determine how many bytes you're going to write to your output buffer for this "read operation". if a == 0, then you have to read a third byte from your input buffer, and add 0x12 to it. Otherwise, you simply add 2 to a. This is the number of bytes to write ("count") in this "read operation". byte2 and the lower nibble of byte1 (b) tell you from where to copy data to your output buffer: you move (dist = (b < <8) - byte2 + 1) bytes back in your outputBuffer and copy "count" bytes from thereto the end of the buffer. Note that count could be greater than dist which means that the copy source and copy destination might overlap." ~said it better than I could've.
###Decompression code
/*src points to the yaz0 source data (to the "real" source data, not at the header!) dst points to a buffer uncompressedSize bytes large (you get uncompressedSize from the second 4 bytes in the Yaz0 header). */
void decode(u8* src, u8* dst, int uncompressedSize)
{
int srcPlace = 0, dstPlace = 0; //current read/write positions
u32 validBitCount = 0; //number of valid bits left in "code" byte
u8 currCodeByte;
while(dstPlace < uncompressedSize)
{
//read new "code" byte if the current one is used up
if(validBitCount == 0)
{
currCodeByte = src[srcPlace];
++srcPlace;
validBitCount = 8;
}
if((currCodeByte & 0x80) != 0)
{
//straight copy
dst[dstPlace] = src[srcPlace];
dstPlace++;
srcPlace++;
}
else
{
//RLE part
u8 byte1 = src[srcPlace];
u8 byte2 = src[srcPlace + 1];
srcPlace += 2;
u32 dist = ((byte1 & 0xF) < < 8) - byte2;
u32 copySource = dstPlace - (dist + 1);
u32 numBytes = byte1 > > 4;
if (numBytes == 0)
{
numBytes = src[srcPlace] + 0x12;
srcPlace++;
}
else
{
numBytes += 2;
}
//copy run
for(int i = 0; i < numBytes; ++i)
{
dst[dstPlace] = dst[copySource];
copySource++;
dstPlace++;
}
//use next bit from "code" byte
currCodeByte < <= 1;
validBitCount-=1;
}
}
}
##Yay0
This format is used to store the fonts in the BIOS/IPL. It is compressed similar to the the Zelda 64 'Yaz0' compression.
0x000 ;Yay0
0x0004 ;size of decoded data in bytes
0x0008 ;offset to link table
0x000c ;offset to non-linked chunks and count modifiers table
0x0010 ;packed data (32 bit words) with 0 being a linked chunk and 1 being non linked chunk
###Decompression code
private void Decode(void* s, void* d)
{
u32 i, j, k;
u32 p, q;
u32 cnt;
i = r21 = *(u32*) (s + 4); // size of decoded data
j = r29 = *(u32*) (s + 8); // link table
k = r23 = *(u32*) (s + 12); // byte chunks and count modifiers
q = r31 = 0; // current offset in dest buffer
cnt = r28 = 0; // mask bit counter
p = r24 = 16; // current offset in mask table
do
{
// if all bits are done, get next mask
if (cnt == 0)
{
// read word from mask data block
r22 = *(u32*) (s + p);
p += 4;
cnt = 32; // bit counter
}
// if next bit is set, chunk is non-linked
if (r22 & 0x80000000)
{
// get next byte
*(u8*) (d + q) = *(u8*) (s + k);
k++;
q++;
}
// do copy, otherwise
else
{
// read 16-bit from link table
r26 = *(u16*) (s + j);
j += 2;
// 'offset'
r25 = q - (r26 & 0xfff);
// 'count'
r30 = r26 > >
12;
if (r30 == 0)
{
// get 'count' modifier
r5 = *(u8*) (s + k);
k++;
r30 = r5 + 18;
}
else r30 += 2;
// do block copy
r5 = d + r25;
for (i = 0; i < r30; i++)
{
*(u8*) (d + q) = *(u8*) (r5 - 1);
q++;
r5++;
}
}
// next bit in mask
r22 < <=
1;
cnt--;
} while (q < i);
}