Skip to content

Commit 5373c45

Browse files
YAY0 Compression Update
-Added support for compressing data with YAY0 compression algorithm. -Updated ReadMe to reflect current status of algorithm support.
1 parent 4f26025 commit 5373c45

File tree

2 files changed

+191
-2
lines changed

2 files changed

+191
-2
lines changed

PeepsCompress/PeepsCompress/YAY0.cs

Lines changed: 190 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,197 @@ class YAY0 : SlidingWindowAlgorithm
1313

1414
public override byte[] compress(byte[] file, int offset)
1515
{
16-
throw new NotImplementedException();
16+
List<byte> layoutBits = new List<byte>();
17+
List<byte> dictionary = new List<byte>();
18+
19+
List<byte> uncompressedData = new List<byte>();
20+
List<int[]> compressedData = new List<int[]>();
21+
22+
int maxDictionarySize = 4096;
23+
int maxMatchLength = 255 + 0x12;
24+
int minMatchLength = 3;
25+
int decompressedSize = 0;
26+
27+
for (int i = 0; i < file.Length; i++)
28+
{
29+
if (dictionary.Contains(file[i]))
30+
{
31+
//check for best match
32+
int[] matches = findAllMatches(ref dictionary, file[i]);
33+
int[] bestMatch = findLargestMatch(ref dictionary, matches, ref file, i, maxMatchLength);
34+
35+
if (bestMatch[1] >= minMatchLength)
36+
{
37+
//add to compressedData
38+
layoutBits.Add(0);
39+
bestMatch[0] = dictionary.Count - bestMatch[0]; //sets offset in relation to end of dictionary
40+
41+
for (int j = 0; j < bestMatch[1]; j++)
42+
{
43+
dictionary.Add(file[i + j]);
44+
}
45+
46+
i = i + bestMatch[1] - 1;
47+
48+
compressedData.Add(bestMatch);
49+
decompressedSize += bestMatch[1];
50+
}
51+
else
52+
{
53+
//add to uncompressed data
54+
layoutBits.Add(1);
55+
uncompressedData.Add(file[i]);
56+
dictionary.Add(file[i]);
57+
decompressedSize++;
58+
}
59+
}
60+
else
61+
{
62+
//uncompressed data
63+
layoutBits.Add(1);
64+
uncompressedData.Add(file[i]);
65+
dictionary.Add(file[i]);
66+
decompressedSize++;
67+
}
68+
69+
if (dictionary.Count > maxDictionarySize)
70+
{
71+
int overflow = dictionary.Count - maxDictionarySize;
72+
dictionary.RemoveRange(0, overflow);
73+
}
74+
}
75+
76+
return buildYAY0CompressedBlock(ref layoutBits, ref uncompressedData, ref compressedData, decompressedSize, offset);
1777
}
78+
79+
public byte[] buildYAY0CompressedBlock(ref List<byte> layoutBits, ref List<byte> uncompressedData, ref List<int[]> offsetLengthPairs, int decompressedSize, int offset)
80+
{
81+
List<byte> finalYAY0Block = new List<byte>();
82+
List<byte> layoutBytes = new List<byte>();
83+
List<byte> compressedDataBytes = new List<byte>();
84+
List<byte> extendedLengthBytes = new List<byte>();
85+
86+
int compressedOffset = 16 + offset; //header size
87+
int uncompressedOffset;
88+
89+
//add Yay0 magic number
90+
finalYAY0Block.AddRange(Encoding.ASCII.GetBytes("Yay0"));
91+
92+
//add decompressed data size
93+
byte[] decompressedSizeArray = BitConverter.GetBytes(decompressedSize);
94+
Array.Reverse(decompressedSizeArray);
95+
finalYAY0Block.AddRange(decompressedSizeArray);
96+
97+
//assemble layout bytes
98+
while (layoutBits.Count > 0)
99+
{
100+
while (layoutBits.Count < 8)
101+
{
102+
layoutBits.Add(0);
103+
}
104+
105+
string layoutBitsString = layoutBits[0].ToString() + layoutBits[1].ToString() + layoutBits[2].ToString() + layoutBits[3].ToString()
106+
+ layoutBits[4].ToString() + layoutBits[5].ToString() + layoutBits[6].ToString() + layoutBits[7].ToString();
107+
108+
byte[] layoutByteArray = new byte[1];
109+
layoutByteArray[0] = Convert.ToByte(layoutBitsString, 2);
110+
layoutBytes.Add(layoutByteArray[0]);
111+
layoutBits.RemoveRange(0, (layoutBits.Count < 8) ? layoutBits.Count : 8);
112+
113+
}
114+
115+
//assemble offsetLength shorts
116+
foreach (int[] offsetLengthPair in offsetLengthPairs)
117+
{
118+
//if < 18, set 4 bits -2 as matchLength
119+
//if >= 18, set matchLength == 0, write length to new byte - 0x12
120+
121+
int adjustedOffset = offsetLengthPair[0];
122+
int adjustedLength = (offsetLengthPair[1] >= 18) ? 0 : offsetLengthPair[1] - 2; //vital, 4 bit range is 0-15. Number must be at least 3 (if 2, when -2 is done, it will think it is 3 byte format), -2 is how it can store up to 17 without an extra byte because +2 will be added on decompression
123+
124+
int compressedInt = ((adjustedLength << 12) | adjustedOffset - 1);
125+
126+
byte[] compressed2Byte = new byte[2];
127+
compressed2Byte[0] = (byte)(compressedInt & 0XFF);
128+
compressed2Byte[1] = (byte)((compressedInt >> 8) & 0xFF);
129+
130+
compressedDataBytes.Add(compressed2Byte[1]);
131+
compressedDataBytes.Add(compressed2Byte[0]);
132+
133+
if (adjustedLength == 0)
134+
{
135+
extendedLengthBytes.Add((byte)(offsetLengthPair[1] - 18));
136+
}
137+
}
138+
139+
//pad layout bits if needed
140+
while (layoutBytes.Count % 4 != 0)
141+
{
142+
layoutBytes.Add(0);
143+
}
144+
145+
compressedOffset += layoutBytes.Count;
146+
147+
//add final compresseed offset
148+
byte[] compressedOffsetArray = BitConverter.GetBytes(compressedOffset);
149+
Array.Reverse(compressedOffsetArray);
150+
finalYAY0Block.AddRange(compressedOffsetArray);
151+
152+
//add final uncompressed offset
153+
uncompressedOffset = compressedOffset + compressedDataBytes.Count;
154+
byte[] uncompressedOffsetArray = BitConverter.GetBytes(uncompressedOffset);
155+
Array.Reverse(uncompressedOffsetArray);
156+
finalYAY0Block.AddRange(uncompressedOffsetArray);
157+
158+
//add layout bits
159+
foreach (byte layoutByte in layoutBytes) //add layout bytes to file
160+
{
161+
finalYAY0Block.Add(layoutByte);
162+
}
163+
164+
//add compressed data
165+
foreach (byte compressedByte in compressedDataBytes) //add compressed bytes to file
166+
{
167+
finalYAY0Block.Add(compressedByte);
168+
}
169+
170+
//non-compressed/additional-length bytes
171+
{
172+
for (int i = 0; i < layoutBytes.Count; i++)
173+
{
174+
BitArray arrayOfBits = new BitArray(new byte[1] { layoutBytes[i] });
175+
176+
for (int j = 7; j > -1 && finalYAY0Block.Count < decompressedSize; j--)
177+
{
178+
if (arrayOfBits[j] == true)
179+
{
180+
finalYAY0Block.Add(uncompressedData[0]);
181+
uncompressedData.RemoveAt(0);
182+
}
183+
else
184+
{
185+
if (compressedDataBytes.Count > 0)
186+
{
187+
int length = compressedDataBytes[0] >> 4;
188+
compressedDataBytes.RemoveRange(0, 2);
189+
190+
if (length == 0)
191+
{
192+
finalYAY0Block.Add(extendedLengthBytes[0]);
193+
extendedLengthBytes.RemoveAt(0);
194+
}
195+
196+
197+
}
198+
}
199+
}
200+
}
201+
}
202+
203+
return finalYAY0Block.ToArray();
204+
}
205+
206+
18207
public override byte[] decompress(BinaryReader br, int offset, FileStream inputFile)
19208
{
20209
List<byte> newFile = new List<byte>();

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Supports the following algorithms:
88
Nintendo: <br>
99
MIO0: Compression ✔ | Decompression ✔ <br>
1010
Yaz0: Compression ✔ | Decompression ✔ <br>
11-
Yay0: Compression \* | Decompression ✔ <br>
11+
Yay0: Compression | Decompression ✔ <br>
1212

1313
\*: In development <br>
1414
\*\*: Planned

0 commit comments

Comments
 (0)