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*=*/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
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