public IoPackage( FArchive uasset, IoGlobalData globalData, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : base(uasset.Name.SubstringBeforeLast('.'), provider, mappings) { GlobalData = globalData; var uassetAr = new FAssetArchive(uasset, this); FExportBundleHeader[] exportBundleHeaders; FExportBundleEntry[] exportBundleEntries; FPackageId[] importedPackageIds; int allExportDataOffset; if (uassetAr.Game >= EGame.GAME_UE5_0) { // Summary var summary = uassetAr.Read <FPackageSummary5>(); Summary = new FPackageFileSummary { PackageFlags = summary.PackageFlags, TotalHeaderSize = summary.GraphDataOffset + (int)summary.HeaderSize, ExportCount = (summary.ExportBundleEntriesOffset - summary.ExportMapOffset) / Unsafe.SizeOf <FExportMapEntry>(), ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size }; // Name map NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr); Summary.NameCount = NameMap.Length; Name = CreateFNameFromMappedName(summary.Name).Text; // Import map uassetAr.Position = summary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = summary.ExportMapOffset; ExportMap = uasset.ReadArray <FExportMapEntry>(Summary.ExportCount); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundle entries uassetAr.Position = summary.ExportBundleEntriesOffset; exportBundleEntries = uassetAr.ReadArray <FExportBundleEntry>(Summary.ExportCount * 2); // Export bundle headers uassetAr.Position = summary.GraphDataOffset; var exportBundleHeadersCount = 1; // TODO just a placeholder until loading of package store entries are implemented exportBundleHeaders = uassetAr.ReadArray <FExportBundleHeader>(exportBundleHeadersCount); // We don't read the graph data importedPackageIds = Array.Empty <FPackageId>(); // TODO imported packages are now only stored in the package store entry, no longer in the graph data too allExportDataOffset = (int)summary.HeaderSize; } else { // Summary var summary = uassetAr.Read <FPackageSummary>(); Summary = new FPackageFileSummary { PackageFlags = summary.PackageFlags, TotalHeaderSize = summary.GraphDataOffset + summary.GraphDataSize, NameCount = summary.NameMapHashesSize / sizeof(ulong) - 1, ExportCount = (summary.ExportBundlesOffset - summary.ExportMapOffset) / Unsafe.SizeOf <FExportMapEntry>(), ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size }; // Name map uassetAr.Position = summary.NameMapNamesOffset; NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr, Summary.NameCount); Name = CreateFNameFromMappedName(summary.Name).Text; // Import map uassetAr.Position = summary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = summary.ExportMapOffset; ExportMap = uasset.ReadArray <FExportMapEntry>(Summary.ExportCount); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundles uassetAr.Position = summary.ExportBundlesOffset; LoadExportBundles(uassetAr, summary.GraphDataOffset - summary.ExportBundlesOffset, out exportBundleHeaders, out exportBundleEntries); // Graph data uassetAr.Position = summary.GraphDataOffset; importedPackageIds = LoadGraphData(uassetAr); allExportDataOffset = summary.GraphDataOffset + summary.GraphDataSize; } // Preload dependencies ImportedPackages = new Lazy <IoPackage?[]>(provider != null ? () => { var packages = new IoPackage?[importedPackageIds.Length]; for (int i = 0; i < importedPackageIds.Length; i++) { provider.TryLoadPackage(importedPackageIds[i], out packages[i]); } return(packages); } : Array.Empty <IoPackage?>); // Attach ubulk and uptnl if (ubulk != null) { uassetAr.AddPayload(PayloadType.UBULK, Summary.BulkDataStartOffset, ubulk); } if (uptnl != null) { uassetAr.AddPayload(PayloadType.UPTNL, Summary.BulkDataStartOffset, uptnl); } // Populate lazy exports var currentExportDataOffset = allExportDataOffset; foreach (var exportBundle in exportBundleHeaders) { for (var i = 0u; i < exportBundle.EntryCount; i++) { var entry = exportBundleEntries[exportBundle.FirstEntryIndex + i]; if (entry.CommandType == EExportCommandType.ExportCommandType_Serialize) { var localExportIndex = entry.LocalExportIndex; var export = ExportMap[localExportIndex]; var localExportDataOffset = currentExportDataOffset; ExportsLazy[localExportIndex] = new Lazy <UObject>(() => { // Create var obj = ConstructObject(ResolveObjectIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = CreateFNameFromMappedName(export.ObjectName).Text; obj.Outer = (ResolveObjectIndex(export.OuterIndex) as ResolvedExportObject)?.ExportObject.Value ?? this; obj.Super = ResolveObjectIndex(export.SuperIndex) as ResolvedExportObject; obj.Template = ResolveObjectIndex(export.TemplateIndex) as ResolvedExportObject; obj.Flags |= (EObjectFlags)export.ObjectFlags; // We give loaded objects the RF_WasLoaded flag in ConstructObject, so don't remove it again in here // Serialize uassetAr.AbsoluteOffset = (int)export.CookedSerialOffset - localExportDataOffset; uassetAr.Seek(localExportDataOffset, SeekOrigin.Begin); DeserializeObject(obj, uassetAr, (long)export.CookedSerialSize); // TODO right place ??? obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.PostLoad(); return(obj); }); currentExportDataOffset += (int)export.CookedSerialSize; } } } Summary.BulkDataStartOffset = currentExportDataOffset; }
public IoPackage( FArchive uasset, IoGlobalData globalData, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : base(uasset.Name.SubstringBeforeLast(".uasset"), provider, mappings) { if (provider == null) { throw new ParserException("Cannot load I/O store package without a file provider. This is needed to link the package imports."); } GlobalData = globalData; var uassetAr = new FAssetArchive(uasset, this); // Summary IoSummary = uassetAr.Read <FPackageSummary>(); Summary = new FPackageFileSummary { PackageFlags = (PackageFlags)IoSummary.PackageFlags, TotalHeaderSize = IoSummary.GraphDataOffset + IoSummary.GraphDataSize, NameCount = IoSummary.NameMapHashesSize / sizeof(ulong) - 1, ExportCount = (IoSummary.ExportBundlesOffset - IoSummary.ExportMapOffset) / Unsafe.SizeOf <FExportMapEntry>(), ImportCount = (IoSummary.ExportMapOffset - IoSummary.ImportMapOffset) / FPackageObjectIndex.Size }; // Name map uassetAr.Position = IoSummary.NameMapNamesOffset; NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr, Summary.NameCount); Name = CreateFNameFromMappedName(IoSummary.Name).Text; // Import map uassetAr.Position = IoSummary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = IoSummary.ExportMapOffset; ExportMap = uasset.ReadArray <FExportMapEntry>(Summary.ExportCount); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundles uassetAr.Position = IoSummary.ExportBundlesOffset; LoadExportBundles(uassetAr, out var exportBundleHeaders, out var exportBundleEntries); // Graph data uassetAr.Position = IoSummary.GraphDataOffset; var importedPackageIds = LoadGraphData(uassetAr); // Preload dependencies ImportedPackages = new Lazy <IoPackage?[]>(() => { var packages = new IoPackage?[importedPackageIds.Length]; for (int i = 0; i < importedPackageIds.Length; i++) { provider.TryLoadPackage(importedPackageIds[i], out packages[i]); } return(packages); }); // Attach ubulk and uptnl if (ubulk != null) { uassetAr.AddPayload(PayloadType.UBULK, Summary.BulkDataStartOffset, ubulk); } if (uptnl != null) { uassetAr.AddPayload(PayloadType.UPTNL, Summary.BulkDataStartOffset, uptnl); } // Populate lazy exports var allExportDataOffset = IoSummary.GraphDataOffset + IoSummary.GraphDataSize; var currentExportDataOffset = allExportDataOffset; foreach (var exportBundle in exportBundleHeaders) { for (var i = 0u; i < exportBundle.EntryCount; i++) { var entry = exportBundleEntries[exportBundle.FirstEntryIndex + i]; if (entry.CommandType == EExportCommandType.ExportCommandType_Serialize) { var localExportIndex = entry.LocalExportIndex; var export = ExportMap[localExportIndex]; var localExportDataOffset = currentExportDataOffset; ExportsLazy[localExportIndex] = new Lazy <UObject>(() => { // Create var objectName = CreateFNameFromMappedName(export.ObjectName); var obj = ConstructObject(ResolveObjectIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = objectName.Text; obj.Outer = (ResolveObjectIndex(export.OuterIndex) as ResolvedExportObject)?.ExportObject.Value ?? this; obj.Template = ResolveObjectIndex(export.TemplateIndex) as ResolvedExportObject; obj.Flags = (int)export.ObjectFlags; var exportType = obj.ExportType; // Serialize uassetAr.AbsoluteOffset = (int)export.CookedSerialOffset - localExportDataOffset; uassetAr.Seek(localExportDataOffset, SeekOrigin.Begin); var validPos = uassetAr.Position + (long)export.CookedSerialSize; try { obj.Deserialize(uassetAr, validPos); #if DEBUG if (validPos != uassetAr.Position) { Log.Warning("Did not read {0} correctly, {1} bytes remaining", exportType, validPos - uassetAr.Position); } else { Log.Debug("Successfully read {0} at {1} with size {2}", exportType, localExportDataOffset, export.CookedSerialSize); } #endif // TODO right place ??? obj.PostLoad(); } catch (Exception e) { Log.Error(e, "Could not read {0} correctly", exportType); } return(obj); }); currentExportDataOffset += (int)export.CookedSerialSize; } } } Summary.BulkDataStartOffset = currentExportDataOffset; }
public IoPackage(FArchive uasset, IoGlobalData globalData, FArchive?ubulk = null, FArchive?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : this(uasset, globalData, ubulk != null ? new Lazy <FArchive?>(() => ubulk) : null, uptnl != null ? new Lazy <FArchive?>(() => uptnl) : null, provider, mappings) { }
public IoPackage( FArchive uasset, IoGlobalData globalData, FIoContainerHeader?containerHeader = null, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : base(uasset.Name.SubstringBeforeLast('.'), provider, mappings) { GlobalData = globalData; var uassetAr = new FAssetArchive(uasset, this); FExportBundleHeader[] exportBundleHeaders; FExportBundleEntry[] exportBundleEntries; FPackageId[] importedPackageIds; int allExportDataOffset; if (uassetAr.Game >= EGame.GAME_UE5_0) { // Summary var summary = uassetAr.Read <FZenPackageSummary>(); Summary = new FPackageFileSummary { PackageFlags = summary.PackageFlags, TotalHeaderSize = summary.GraphDataOffset + (int)summary.HeaderSize, ExportCount = (summary.ExportBundleEntriesOffset - summary.ExportMapOffset) / FExportMapEntry.Size, ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size }; // Versioning info if (summary.bHasVersioningInfo != 0) { var versioningInfo = new FZenPackageVersioningInfo(uassetAr); Summary.FileVersionUE = versioningInfo.PackageVersion; Summary.FileVersionLicenseeUE = (EUnrealEngineObjectLicenseeUEVersion)versioningInfo.LicenseeVersion; Summary.CustomVersionContainer = versioningInfo.CustomVersions; if (!uassetAr.Versions.bExplicitVer) { uassetAr.Versions.Ver = versioningInfo.PackageVersion; uassetAr.Versions.CustomVersions = versioningInfo.CustomVersions.ToList(); } } else { Summary.bUnversioned = true; } // Name map NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr); Summary.NameCount = NameMap.Length; Name = CreateFNameFromMappedName(summary.Name).Text; // Find store entry by package name FFilePackageStoreEntry?storeEntry = null; if (containerHeader != null) { var storeEntryIdx = Array.IndexOf(containerHeader.PackageIds, FPackageId.FromName(Name)); if (storeEntryIdx != -1) { storeEntry = containerHeader.StoreEntries[storeEntryIdx]; } else { Log.Warning("Couldn't find store entry for package {0}, its data will not be fully read", Name); } } // Imported public export hashes uassetAr.Position = summary.ImportedPublicExportHashesOffset; ImportedPublicExportHashes = uassetAr.ReadArray <ulong>((summary.ImportMapOffset - summary.ImportedPublicExportHashesOffset) / sizeof(ulong)); // Import map uassetAr.Position = summary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = summary.ExportMapOffset; ExportMap = uasset.ReadArray(Summary.ExportCount, () => new FExportMapEntry(uassetAr)); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundle entries uassetAr.Position = summary.ExportBundleEntriesOffset; exportBundleEntries = uassetAr.ReadArray <FExportBundleEntry>(Summary.ExportCount * 2); // Export bundle headers uassetAr.Position = summary.GraphDataOffset; var exportBundleHeadersCount = storeEntry?.ExportBundleCount ?? 1; exportBundleHeaders = uassetAr.ReadArray <FExportBundleHeader>(exportBundleHeadersCount); // We don't read the graph data importedPackageIds = storeEntry?.ImportedPackages ?? Array.Empty <FPackageId>(); allExportDataOffset = (int)summary.HeaderSize; } else { // Summary var summary = uassetAr.Read <FPackageSummary>(); Summary = new FPackageFileSummary { PackageFlags = summary.PackageFlags, TotalHeaderSize = summary.GraphDataOffset + summary.GraphDataSize, NameCount = summary.NameMapHashesSize / sizeof(ulong) - 1, ExportCount = (summary.ExportBundlesOffset - summary.ExportMapOffset) / FExportMapEntry.Size, ImportCount = (summary.ExportMapOffset - summary.ImportMapOffset) / FPackageObjectIndex.Size, bUnversioned = true }; // Name map uassetAr.Position = summary.NameMapNamesOffset; NameMap = FNameEntrySerialized.LoadNameBatch(uassetAr, Summary.NameCount); Name = CreateFNameFromMappedName(summary.Name).Text; // Import map uassetAr.Position = summary.ImportMapOffset; ImportMap = uasset.ReadArray <FPackageObjectIndex>(Summary.ImportCount); // Export map uassetAr.Position = summary.ExportMapOffset; ExportMap = uasset.ReadArray(Summary.ExportCount, () => new FExportMapEntry(uassetAr)); ExportsLazy = new Lazy <UObject> [Summary.ExportCount]; // Export bundles uassetAr.Position = summary.ExportBundlesOffset; LoadExportBundles(uassetAr, summary.GraphDataOffset - summary.ExportBundlesOffset, out exportBundleHeaders, out exportBundleEntries); // Graph data uassetAr.Position = summary.GraphDataOffset; importedPackageIds = LoadGraphData(uassetAr); allExportDataOffset = summary.GraphDataOffset + summary.GraphDataSize; } // Preload dependencies ImportedPackages = new Lazy <IoPackage?[]>(provider != null ? () => { var packages = new IoPackage?[importedPackageIds.Length]; for (int i = 0; i < importedPackageIds.Length; i++) { provider.TryLoadPackage(importedPackageIds[i], out packages[i]); } return(packages); } : Array.Empty <IoPackage?>); // Attach ubulk and uptnl if (ubulk != null) { uassetAr.AddPayload(PayloadType.UBULK, Summary.BulkDataStartOffset, ubulk); } if (uptnl != null) { uassetAr.AddPayload(PayloadType.UPTNL, Summary.BulkDataStartOffset, uptnl); } // Populate lazy exports var currentExportDataOffset = allExportDataOffset; foreach (var exportBundle in exportBundleHeaders) { for (var i = 0u; i < exportBundle.EntryCount; i++) { var entry = exportBundleEntries[exportBundle.FirstEntryIndex + i]; if (entry.CommandType == EExportCommandType.ExportCommandType_Serialize) { var localExportIndex = entry.LocalExportIndex; var export = ExportMap[localExportIndex]; var localExportDataOffset = currentExportDataOffset; ExportsLazy[localExportIndex] = new Lazy <UObject>(() => { // Create var obj = ConstructObject(ResolveObjectIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = CreateFNameFromMappedName(export.ObjectName).Text; obj.Outer = (ResolveObjectIndex(export.OuterIndex) as ResolvedExportObject)?.ExportObject.Value ?? this; obj.Super = ResolveObjectIndex(export.SuperIndex) as ResolvedExportObject; obj.Template = ResolveObjectIndex(export.TemplateIndex) as ResolvedExportObject; obj.Flags |= export.ObjectFlags; // We give loaded objects the RF_WasLoaded flag in ConstructObject, so don't remove it again in here // Serialize var Ar = (FAssetArchive)uassetAr.Clone(); Ar.AbsoluteOffset = (int)export.CookedSerialOffset - localExportDataOffset; Ar.Position = localExportDataOffset; DeserializeObject(obj, Ar, (long)export.CookedSerialSize); // TODO right place ??? obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.PostLoad(); return(obj); }); currentExportDataOffset += (int)export.CookedSerialSize; } } } Summary.BulkDataStartOffset = currentExportDataOffset; IsFullyLoaded = true; }