public static byte[] decode(byte[] src) { if (!IsYaz0(src)) { return(src); } uint decompressedSize = EndianBytesOperator.readUInt(src, 0x04); byte[] dst = new byte[decompressedSize]; uint srcPos = 0x10; uint dstPos = 0; byte Opcode = 0x00; List <KeyValuePair <int, KeyValuePair <int, int> > > finds = new List <KeyValuePair <int, KeyValuePair <int, int> > >(); while (true) { Opcode = src[srcPos]; srcPos++; for (int i = 0; i < 8; i++, Opcode <<= 1) { if ((Opcode & 0x80) != 0) { dst[dstPos] = src[srcPos]; dstPos++; srcPos++; } else { byte b1 = src[srcPos]; byte b2 = src[srcPos + 1]; srcPos += 2; uint copyLen = 0; if ((b1 >> 4) == 0) { copyLen = (uint)src[srcPos] + 0x12; srcPos++; } else { copyLen = (uint)(b1 >> 4) + 0x02; } uint dist = (uint)((b1 & 0x0F) << 8 | b2) + 1; uint copyPos = dstPos - dist; finds.Add(new KeyValuePair <int, KeyValuePair <int, int> >((int)dstPos, new KeyValuePair <int, int>((int)copyPos, (int)copyLen))); for (int j = 0; j < copyLen; j++) { dst[dstPos] = dst[copyPos]; dstPos++; copyPos++; } } if (dstPos >= decompressedSize) { return(dst); } } } }
public static bool IsYaz0(byte[] bytes) { return(EndianBytesOperator.readString(bytes, 0, 4) == "Yaz0"); }
public static byte[] encode(byte[] src) { //find need compressed position uint curPos = 0; uint endPos = (uint)src.Length; List <KeyValuePair <uint, KeyValuePair <uint, uint> > > finds = new List <KeyValuePair <uint, KeyValuePair <uint, uint> > >(); while (curPos + 0x03 <= endPos) { var find = searchNextNCPoses(src, curPos, endPos); if (find[0].Value.Value != 0) { finds.AddRange(find); } curPos = find[find.Count - 1].Key + find[find.Count - 1].Value.Value; } //compress byte[] temp = new byte[src.Length + src.Length / 8]; uint writeLen = 0; uint srcPos = 0; uint dstPos = 0x01; uint opcodePos = 0; uint cycle = 0x00; foreach (var find in finds) { //write data that does not need to be compressed while (srcPos < find.Key) { if (cycle == 8) { opcodePos = dstPos; dstPos++; cycle = 0x00; } temp[opcodePos] = (byte)(temp[opcodePos] | 0x80 >> (int)cycle); cycle++; temp[dstPos] = src[srcPos]; dstPos++; srcPos++; } //write data that need to compressed if (cycle == 8) { opcodePos = dstPos; dstPos++; cycle = 0x00; } cycle++; uint findLen = find.Value.Value; uint findPos = find.Value.Key; uint pos = find.Key; uint dist = pos - findPos - 1; if (findLen < 0x12) { byte b1 = (byte)((findLen - 2) << 4 | dist >> 8); byte b2 = (byte)(dist & 0xFF); temp[dstPos] = b1; temp[dstPos + 1] = b2; dstPos += 2; } else { byte b1 = (byte)(dist >> 8); byte b2 = (byte)(dist & 0xFF); byte b3 = (byte)(findLen - 0x12); temp[dstPos] = b1; temp[dstPos + 1] = b2; temp[dstPos + 2] = b3; dstPos += 3; } srcPos += findLen; } //write data that does not need to be compressed while (srcPos < src.Length) { if (cycle == 8) { opcodePos = dstPos; dstPos++; cycle = 0x00; } temp[opcodePos] = (byte)(temp[opcodePos] | 0x80 >> (int)cycle); cycle++; temp[dstPos] = src[srcPos]; dstPos++; srcPos++; } writeLen = dstPos; byte[] ret = new byte[writeLen + 0x10]; EndianBytesOperator.writeString(ret, 0, "Yaz0", 4); EndianBytesOperator.writeUInt(ret, 0x04, (uint)src.Length); for (int i = 0; i < writeLen; i++) { ret[i + 0x10] = temp[i]; } return(ret); }