* Squashed a bug in ZQuestFile

* Moved yaz0Decode to zelda::compression
* Added yaz0Encode (NOT TESTED)
This commit is contained in:
Antidote 2013-07-26 23:39:03 -07:00
parent b7b4df52f3
commit 162d2753dc
5 changed files with 223 additions and 64 deletions

View File

@ -24,8 +24,14 @@ namespace io
{
namespace Compression
{
// Zlib compression
Int32 decompressZlib(Uint8* src, Uint32 srcLen, Uint8* dst, Uint32 dstLen);
Int32 compressZlib(const Uint8* src, Uint32 srcLen, Uint8* dst, Uint32 dstLen);
// Yaz0 encoding
Uint32 yaz0Decode(Uint8* src, Uint8* dst, Uint32 uncompressedSize);
Uint32 yaz0Encode(Uint8* src, Uint32 srcSize, Uint8* data);
}
}
}

View File

@ -40,9 +40,6 @@ bool isSystemBigEndian();
void fillRandom(Uint8 * rndArea, Uint8 count);
void yaz0Decode(Uint8* src, Uint8* dst, Uint32 uncompressedSize);
} // utility
} // zelda

View File

@ -103,6 +103,220 @@ Int32 compressZlib(const Uint8 *src, Uint32 srcLen, Uint8 *dst, Uint32 dstLen)
return ret;
}
//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).
Uint32 yaz0Decode(Uint8* src, Uint8* dst, Uint32 uncompressedSize)
{
Uint32 srcPlace = 0, dstPlace = 0; //current read/write positions
Int32 validBitCount = 0; //number of valid bits left in "code" byte
Uint8 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
Uint8 byte1 = src[srcPlace];
Uint8 byte2 = src[srcPlace + 1];
srcPlace += 2;
Uint32 dist = ((byte1 & 0xF) << 8) | byte2;
Uint32 copySource = dstPlace - (dist + 1);
Uint32 numBytes = byte1 >> 4;
if(numBytes == 0)
{
numBytes = src[srcPlace] + 0x12;
srcPlace++;
}
else
numBytes += 2;
//copy run
for(Uint32 i = 0; i < numBytes; ++i)
{
dst[dstPlace] = dst[copySource];
copySource++;
dstPlace++;
}
}
//use next bit from "code" byte
currCodeByte <<= 1;
validBitCount-=1;
}
return dstPlace;
}
// Yaz0 encode
typedef struct
{
Uint32 srcPos, dstPos;
} yaz0_Ret;
Uint32 simpleEnc(Uint8* src, Int32 size, Int32 pos, Uint32 *pMatchPos);
Uint32 nintendoEnc(Uint8* src, Int32 size, Int32 pos, Uint32 *pMatchPos);
Uint32 yaz0Encode(Uint8* src, Uint32 srcSize, Uint8* data)
{
yaz0_Ret r = { 0, 0 };
Int32 pos = 0;
Uint8 dst[24]; // 8 codes * 3 bytes maximum
Uint32 dstSize = 0;
Uint32 i;
Uint32 validBitCount = 0; //number of valid bits left in "code" byte
Uint8 currCodeByte = 0;
while(r.srcPos < srcSize)
{
Uint32 numBytes;
Uint32 matchPos;
numBytes = nintendoEnc(src, srcSize, r.srcPos, &matchPos);
if (numBytes < 3)
{
//straight copy
dst[r.dstPos] = src[r.srcPos];
r.dstPos++;
r.srcPos++;
//set flag for straight copy
currCodeByte |= (0x80 >> validBitCount);
}
else
{
//RLE part
Uint32 dist = r.srcPos - matchPos - 1;
Uint8 byte1, byte2, byte3;
if (numBytes >= 0x12) // 3 byte encoding
{
byte1 = 0 | (dist >> 8);
byte2 = dist & 0xff;
dst[r.dstPos++] = byte1;
dst[r.dstPos++] = byte2;
// maximum runlength for 3 byte encoding
if (numBytes > 0xff+0x12)
numBytes = 0xff+0x12;
byte3 = numBytes - 0x12;
dst[r.dstPos++] = byte3;
}
else // 2 byte encoding
{
byte1 = ((numBytes - 2) << 4) | (dist >> 8);
byte2 = dist & 0xff;
dst[r.dstPos++] = byte1;
dst[r.dstPos++] = byte2;
}
r.srcPos += numBytes;
}
validBitCount++;
//write eight codes
if(validBitCount == 8)
{
data[pos] = currCodeByte;
pos++;
for (i=0;i</*=*/r.dstPos;pos++,i++)
data[pos] = dst[i];
dstSize += r.dstPos+1;
currCodeByte = 0;
validBitCount = 0;
r.dstPos = 0;
}
}
if(validBitCount > 0)
{
data[pos] = currCodeByte;
pos++;
for (i=0;i</*=*/r.dstPos;pos++,i++)
data[pos] = dst[i];
dstSize += r.dstPos+1;
currCodeByte = 0;
validBitCount = 0;
r.dstPos = 0;
}
return dstSize;
}
// a lookahead encoding scheme for ngc Yaz0
Uint32 nintendoEnc(Uint8* src, Int32 size, Int32 pos, Uint32 *pMatchPos)
{
Uint32 numBytes = 1;
static Uint32 numBytes1;
static Uint32 matchPos;
static Int32 prevFlag = 0;
// if prevFlag is set, it means that the previous position was determined by look-ahead try.
// so just use it. this is not the best optimization, but nintendo's choice for speed.
if (prevFlag == 1) {
*pMatchPos = matchPos;
prevFlag = 0;
return numBytes1;
}
prevFlag = 0;
numBytes = simpleEnc(src, size, pos, &matchPos);
*pMatchPos = matchPos;
// if this position is RLE encoded, then compare to copying 1 byte and next position(pos+1) encoding
if (numBytes >= 3) {
numBytes1 = simpleEnc(src, size, pos+1, &matchPos);
// if the next position encoding is +2 longer than current position, choose it.
// this does not guarantee the best optimization, but fairly good optimization with speed.
if (numBytes1 >= numBytes+2) {
numBytes = 1;
prevFlag = 1;
}
}
return numBytes;
}
// simple and straight encoding scheme for Yaz0
Uint32 simpleEnc(Uint8* src, Int32 size, Int32 pos, Uint32 *pMatchPos)
{
int startPos = pos - 0x1000, j, i;
Uint32 numBytes = 1;
Uint32 matchPos = 0;
if (startPos < 0)
startPos = 0;
for (i = startPos; i < pos; i++)
{
for (j = 0; j < size-pos; j++)
{
if (src[i+j] != src[j+pos])
break;
}
if ((Uint32)j > numBytes)
{
numBytes = j;
matchPos = i;
}
}
*pMatchPos = matchPos;
if (numBytes == 2)
numBytes = 1;
return numBytes;
}
} // Compression
} // io
} // zelda

View File

@ -14,6 +14,7 @@
// along with libZelda. If not, see <http://www.gnu.org/licenses/>
#include "ZQuestFile.hpp"
#include <string.h>
namespace zelda
{
@ -79,7 +80,8 @@ void ZQuestFile::setData(Uint8* data, Uint32 length)
if (!m_data || m_data != data)
{
delete[] m_data;
m_data = data;
m_data = new Uint8[length];
memcpy(m_data, data, length);
m_length = length;
}
}

View File

@ -111,65 +111,5 @@ double swapDouble(double val)
return (double)((Uint64)retVal);
}
//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 yaz0Decode(Uint8* src, Uint8* dst, Uint32 uncompressedSize)
{
Uint32 srcPlace = 0, dstPlace = 0; //current read/write positions
Int32 validBitCount = 0; //number of valid bits left in "code" byte
Uint8 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
Uint8 byte1 = src[srcPlace];
Uint8 byte2 = src[srcPlace + 1];
srcPlace += 2;
Uint32 dist = ((byte1 & 0xF) << 8) | byte2;
Uint32 copySource = dstPlace - (dist + 1);
Uint32 numBytes = byte1 >> 4;
if(numBytes == 0)
{
numBytes = src[srcPlace] + 0x12;
srcPlace++;
}
else
numBytes += 2;
//copy run
for(Uint32 i = 0; i < numBytes; ++i)
{
dst[dstPlace] = dst[copySource];
copySource++;
dstPlace++;
}
}
//use next bit from "code" byte
currCodeByte <<= 1;
validBitCount-=1;
}
}
} // utility
} // zelda