public BlockEntry FromData(Span <byte> xorData, PackfileHeader header) { if (header.IsEncrypted) { XorKey1 = Bits.ToUInt32(xorData.Slice(12)); // 0xC XorKey2 = Bits.ToUInt32(xorData.Slice(28)); // 0x1C var key1 = header.BuildXorKey(Bits.GetBytes(XorKey1)); var key2 = header.BuildXorKey(Bits.GetBytes(XorKey2)); for (int i = 0; i < 16; i++) { xorData[i + 0] ^= key1[i];// XOR bytes 0 to 16 } for (int i = 0; i < 16; i++) { xorData[i + 16] ^= key2[i];// XOR bytes 16 to 32 } // The XOR keys at offset 0xC and 0x1C in xorData are trashed now. They are manually restored in game code. } DecompressedOffset = Bits.ToUInt64(xorData.Slice(0)); // 0x0 DecompressedSize = Bits.ToUInt32(xorData.Slice(8)); // 0x8 Offset = Bits.ToUInt64(xorData.Slice(16)); // 0x10 Size = Bits.ToUInt32(xorData.Slice(24)); // 0x18 return(this); }
public FileEntry FromData(Span <byte> xorData, PackfileHeader header) { if (header.IsEncrypted) { XorKey1 = Bits.ToUInt32(xorData.Slice(4)); // 0x4 XorKey2 = Bits.ToUInt32(xorData.Slice(28)); // 0x1C var key1 = header.BuildXorKey(Bits.GetBytes(XorKey1)); var key2 = header.BuildXorKey(Bits.GetBytes(XorKey2)); for (int i = 0; i < 16; i++) { xorData[i + 0] ^= key1[i];// XOR bytes 0 to 16 } for (int i = 0; i < 16; i++) { xorData[i + 16] ^= key2[i];// XOR bytes 16 to 32 } // The XOR keys at offset 0x4 and 0x1C in xorData are trashed now. They seem to ignore it. } //_ = Bits.ToUInt32(xorData.Slice(0)); // 0x0 Not used? PathHash = Bits.ToUInt64(xorData.Slice(8)); // 0x8 DecompressedOffset = Bits.ToUInt64(xorData.Slice(16)); // 0x10 DecompressedSize = Bits.ToUInt32(xorData.Slice(24)); // 0x18 return(this); }
public void ToData(BinaryWriter writer, PackfileHeader header) { Span <byte> data = stackalloc byte[DataHeaderSize]; Bits.TryWriteBytes(data.Slice(0), DecompressedOffset); // 0x0 Bits.TryWriteBytes(data.Slice(8), DecompressedSize); // 0x8 Bits.TryWriteBytes(data.Slice(16), Offset); // 0x10 Bits.TryWriteBytes(data.Slice(24), Size); // 0x18 if (header.IsEncrypted) { var key1 = header.BuildXorKey(Bits.GetBytes(XorKey1)); var key2 = header.BuildXorKey(Bits.GetBytes(XorKey2)); for (int i = 0; i < 16; i++) { data[i + 0] ^= key1[i];// XOR bytes 0 to 16 } for (int i = 0; i < 16; i++) { data[i + 16] ^= key2[i];// XOR bytes 16 to 32 } } Bits.TryWriteBytes(data.Slice(12), XorKey1); // 0xC Bits.TryWriteBytes(data.Slice(28), XorKey2); // 0x1C writer.Write(data.ToArray()); }
public PackfileReader(string archivePath) { _archivePath = archivePath; using var handle = File.OpenRead(_archivePath); using var reader = new BinaryReader(handle, Encoding.UTF8, true); Header = new PackfileHeader().FromData(reader); FileEntries = new List <FileEntry>((int)Header.FileEntryCount); BlockEntries = new List <BlockEntry>((int)Header.BlockEntryCount); Span <byte> fileData = reader.ReadBytes(Header.FileEntryCount * FileEntry.DataHeaderSize); for (int i = 0; i < Header.FileEntryCount; i++) { var data = fileData.Slice(i * FileEntry.DataHeaderSize, FileEntry.DataHeaderSize); FileEntries.Add(new FileEntry().FromData(data, Header)); } Span <byte> blockData = reader.ReadBytes(Header.BlockEntryCount * BlockEntry.DataHeaderSize); for (int i = 0; i < Header.BlockEntryCount; i++) { var data = blockData.Slice(i * BlockEntry.DataHeaderSize, BlockEntry.DataHeaderSize); BlockEntries.Add(new BlockEntry().FromData(data, Header)); } }
/// <summary> /// Open an archive (.bin) file and prepare for writing. /// </summary> /// <param name="archivePath">Disk path</param> /// <param name="encrypted">Encrypt file data</param> /// <param name="mode">File creation mode</param> public PackfileWriter(string archivePath, bool encrypted = false, FileMode mode = FileMode.CreateNew) { _fileHandle = new FileStream(archivePath, mode, FileAccess.ReadWrite, FileShare.Read); Header = new PackfileHeader(); _fileEntries = new List <FileEntry>(); _blockEntries = new List <BlockEntry>(); Header.IsEncrypted = encrypted; }
public PackfileWriter(string archivePath, bool encrypted = false, bool allowOverwrite = false) { _archivePath = archivePath; _allowOverwrite = allowOverwrite; Header = new PackfileHeader(); FileEntries = new List <FileEntry>(); BlockEntries = new List <BlockEntry>(); Header.IsEncrypted = encrypted; }
/// <summary> /// Open an archive (.bin) file and prepare for writing. /// </summary> /// <param name="archivePath">Disk path</param> /// <param name="encrypted">Encrypt file data</param> /// <param name="mode">File creation mode</param> public PackfileWriterFast(string archivePath, bool encrypted = false, FileMode mode = FileMode.CreateNew) { _archivePath = archivePath; _fileMode = mode; Header = new PackfileHeader(); _fileEntries = new List <FileEntry>(); _blockEntries = new List <BlockEntry>(); Header.IsEncrypted = encrypted; }
public static PackfileHeader FromData(BinaryReader reader) { var x = new PackfileHeader(); x.Magic = reader.ReadUInt32(); // 0 _ = reader.ReadBytesStrict(20); // 4 x.FileEntryCount = reader.ReadUInt32(); // 24 _ = reader.ReadUInt32(); // 28 x.BlockEntryCount = reader.ReadUInt32(); // 32 _ = reader.ReadUInt32(); // 36 return(x); }
public Packfile(string archivePath, FileMode mode = FileMode.Open) { if (mode == FileMode.Open) { ArchiveFileHandle = File.Open(archivePath, mode, FileAccess.Read, FileShare.Read); using (var reader = new BinaryReader(ArchiveFileHandle, Encoding.UTF8, true)) { Header = PackfileHeader.FromData(reader); if (Header.Magic != PackfileHeader.HardcodedMagic) { throw new InvalidDataException("Unknown header magic"); } FileEntries = new FileEntry[Header.FileEntryCount]; BlockEntries = new BlockEntry[Header.BlockEntryCount]; for (uint i = 0; i < FileEntries.Length; i++) { FileEntries[i] = FileEntry.FromData(reader); } for (uint i = 0; i < BlockEntries.Length; i++) { BlockEntries[i] = BlockEntry.FromData(reader); } } } else if (mode == FileMode.Create || mode == FileMode.CreateNew) { throw new NotImplementedException("Writing archives is not supported at the moment"); } else { throw new NotImplementedException("Archive file mode must be Open, Create, or CreateNew"); } }
/// <summary> /// Open an archive (.bin) file and prepare for reading /// </summary> /// <param name="archivePath">Disk path</param> public PackfileReader(string archivePath) { _fileHandle = CreateReadStream(archivePath); using var reader = new BinaryReader(_fileHandle, Encoding.UTF8, true); Header = PackfileHeader.FromData(reader); _fileEntries = new List <FileEntry>((int)Header.FileEntryCount); _blockEntries = new List <BlockEntry>(Header.BlockEntryCount); Span <byte> fileData = reader.ReadBytesStrict((int)Header.FileEntryCount * FileEntry.DataHeaderSize); Span <byte> blockData = reader.ReadBytesStrict(Header.BlockEntryCount * BlockEntry.DataHeaderSize); for (int i = 0; i < (int)Header.FileEntryCount; i++) { var data = fileData.Slice(i * FileEntry.DataHeaderSize); _fileEntries.Add(FileEntry.FromData(data, Header)); } for (int i = 0; i < Header.BlockEntryCount; i++) { var data = blockData.Slice(i * BlockEntry.DataHeaderSize); _blockEntries.Add(BlockEntry.FromData(data, Header)); } }