/// <summary> /// Initialize table with decryption constants /// </summary> /// <param name="data"></param> /// <param name="game"></param> /// <param name="flags"></param> /// <param name="truth"></param> /// <param name="multiplier"></param> /// <param name="divisor"></param> public PKGTBL(Span <byte> data, string game, IDTableFlags flags, byte[] truth, ulong multiplier, ulong divisor) { if (flags != IDTableFlags.None) { var size = BinaryPrimitives.ReadUInt32LittleEndian(data); data = Read(data.Slice(4), game, (uint)data.Length - 4, size, flags, truth, multiplier, divisor); } Buffer = new Memory <byte>(data.ToArray()); if (data.GetDataType() == DataType.PackageInfo) { PackageInfo = new PKGINFO(data); // There's extra shit that I can't parse yet because the format is highly dependent on arbitrary values. Header = new IDTableHeader { Offset = PackageInfo.Resource.Pointers[1] + PackageInfo.InfoTable.Header.TextPointer + SizeHelper.SizeOf <BTIFHeader>() }; Entries = PackageInfo.InfoTable.Entries.Select(x => new IDTableEntry { PathOffset = x.NameOffset, OriginalPathOffset = -1, Flags = x.Flags, UniqueId = x.Checksum, CompressedSize = x.CompressedSize, DecompressedSize = x.DecompressedSize, Padding1 = PackageInfo.InfoTable.UnknownBuffer[x.UnknownIndex], Padding2 = PackageInfo.InfoTable.UnknownBuffer[x.UnknownIndex + 1] }).ToArray(); } else { Header = MemoryMarshal.Read <IDTableHeader>(data); Entries = MemoryMarshal.Cast <byte, IDTableEntry>(data.Slice(Header.Offset, Header.Count * SizeHelper.SizeOf <IDTableEntry>())).ToArray(); } }
/// <summary> /// Read a file with decryption constants /// </summary> /// <param name="file"></param> /// <param name="game"></param> /// <param name="compressedSize"></param> /// <param name="size"></param> /// <param name="flags"></param> /// <param name="truth"></param> /// <param name="multiplier"></param> /// <param name="divisor"></param> /// <returns></returns> public static Span <byte> Read(Span <byte> file, string game, uint compressedSize, uint size, IDTableFlags flags, byte[] truth, ulong multiplier, ulong divisor) { if (compressedSize > file.Length) { Logger.Warn("PKGINFO", "Compressed Size is larger than actual file! The package info might have drifted from the saved files. Please verify game data!"); } if (game == "VenusVacation" && file.IsKnown()) { return(file); } if (flags.HasFlag(IDTableFlags.Encrypted) && (game != "VenusVacation" || flags.HasFlag(IDTableFlags.Compressed))) { var key = XOREncryption.Xor(size, truth, multiplier, divisor); file = XOREncryption.Crypt(file, key); } // ReSharper disable once InvertIf if (flags.HasFlag(IDTableFlags.Compressed) && file[4] == 0x78) { try { var decompressedData = Stream8000Compression.Decompress(file, new CompressionOptions { Length = size }); if (decompressedData.Length != 0) { file = decompressedData; } } catch (Exception e) { Logger.Error("PKGINFO", e); } } return(file); }