diff --git a/include/Compression.hpp b/include/Compression.hpp index c8112cf..4509aa0 100644 --- a/include/Compression.hpp +++ b/include/Compression.hpp @@ -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); + } } } diff --git a/include/utility.hpp b/include/utility.hpp index df12c56..95a8a51 100644 --- a/include/utility.hpp +++ b/include/utility.hpp @@ -40,9 +40,6 @@ bool isSystemBigEndian(); void fillRandom(Uint8 * rndArea, Uint8 count); -void yaz0Decode(Uint8* src, Uint8* dst, Uint32 uncompressedSize); - - } // utility } // zelda diff --git a/src/Compression.cpp b/src/Compression.cpp index c4fc99a..55c1f39 100644 --- a/src/Compression.cpp +++ b/src/Compression.cpp @@ -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 0) + { + data[pos] = currCodeByte; + pos++; + for (i=0;i= 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 diff --git a/src/ZQuestFile.cpp b/src/ZQuestFile.cpp index dc0c528..8a83126 100644 --- a/src/ZQuestFile.cpp +++ b/src/ZQuestFile.cpp @@ -14,6 +14,7 @@ // along with libZelda. If not, see #include "ZQuestFile.hpp" +#include 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; } } diff --git a/src/utility.cpp b/src/utility.cpp index 3d64365..3f172a7 100644 --- a/src/utility.cpp +++ b/src/utility.cpp @@ -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