public byte[] Rebuild() { FileOutput f = new FileOutput(); f.Endian = endian; f.writeString("SARC"); f.writeShort(0x14); f.Endian = endian; f.writeShort(65279); byte[] sfat = RebuildSFATArchive(); f.writeInt(sfat.Length + 0x14); f.writeInt(sfatStartOffset + 0x14); f.writeInt(0x1000000); f.writeBytes(sfat); return(f.getBytes()); }
public static byte[] Decompress(byte[] data) { FileData f = new FileData(data); FileOutput output = new FileOutput(); f.Endian = Endianness.Big; f.seek(4); int uncompressedSize = f.readInt(); byte[] flags = f.read(8); //if ((flags[3] & 0x80) != 0) // f.Endian = Endianness.Little; byte[] src = f.read(data.Length - 0x10); byte[] dst = new byte[uncompressedSize]; int srcPlace = 0, dstPlace = 0; //current read/write positions uint validBitCount = 0; //number of valid bits left in "code" byte byte currCodeByte = 0; 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 byte byte1 = src[srcPlace]; byte byte2 = src[srcPlace + 1]; srcPlace += 2; uint dist = (uint)(((byte1 & 0xF) << 8) | byte2); uint copySource = (uint)(dstPlace - (dist + 1)); uint numBytes = (uint)(byte1 >> 4); if (numBytes == 0) { numBytes = (uint)(src[srcPlace] + 0x12); srcPlace++; } else { numBytes += 2; } //copy run for (int i = 0; i < numBytes; ++i) { dst[dstPlace] = dst[copySource]; copySource++; dstPlace++; } } //use next bit from "code" byte currCodeByte <<= 1; validBitCount -= 1; } return(dst); }
private byte[] RebuildSFATArchive() { FileOutput f = new FileOutput(); f.Endian = endian; f.writeString("SFAT"); f.writeShort(0xC); f.writeShort(files.Count); f.writeInt(0x65); int stringPos = 0; int dataPos = 0; bool isString = true; foreach (string filename in files.Keys) { if (filename.Contains("0x")) { isString = false; f.writeInt((int)Convert.ToInt32(filename, 16)); f.writeInt(0); } else { f.writeInt((int)GetHash(filename.ToArray(), filename.Length, 0x65)); f.writeInt(stringPos + 0x1000000); stringPos += GetSizeInChunks(filename.Length + 1, 4) / 4; } f.writeInt(dataPos); f.writeInt(dataPos + files[filename].Length); dataPos += files[filename].Length % padding == 0 ? files[filename].Length : files[filename].Length + (padding - files[filename].Length % padding); } f.writeHex("53464E5400080000"); if (isString) { foreach (string filename in files.Keys) { f.writeString(filename); f.writeByte(0); while (f.pos() % 4 != 0) { f.writeByte(0); } } } if (padding == -1 || padding < f.pos()) { while ((f.pos() + 0x14) % 0x100 != 0) { f.writeByte(0); } } else { f.writeBytes(new byte[padding - (f.pos() + 0x14)]); } sfatStartOffset = f.pos(); int cur = 0; foreach (string filename in files.Keys) { f.writeIntAt(f.pos() - sfatStartOffset, 0x14 + (cur * 0x10)); f.writeBytes(files[filename]); f.writeIntAt(f.pos() - sfatStartOffset, 0x18 + (cur * 0x10)); while ((f.pos() + 0x14) % padding != 0) { f.writeByte(0); } cur++; } return(f.getBytes()); }