public IoPackageReader(BinaryReader uasset, Stream ubulk, FIoGlobalData globalData, bool onlyInfo = false) { Loader = uasset; _ubulk = ubulk; GlobalData = globalData; Summary = new FPackageSummary(this); var nameMap = new List <FNameEntrySerialized>(); var nameHashes = new List <ulong>(); if (Summary.NameMapNamesSize > 0) { Loader.BaseStream.Seek(Summary.NameMapNamesOffset, SeekOrigin.Begin); var nameMapNames = Loader.ReadBytes(Summary.NameMapNamesSize); Loader.BaseStream.Seek(Summary.NameMapHashesOffset, SeekOrigin.Begin); var nameMapHashes = Loader.ReadBytes(Summary.NameMapHashesSize); FNameEntrySerialized.LoadNameBatch(nameMap, nameHashes, nameMapNames, nameMapHashes); } NameMap = nameMap.ToArray(); Loader.BaseStream.Seek(Summary.ImportMapOffset, SeekOrigin.Begin); var importMapCount = (Summary.ExportMapOffset - Summary.ImportMapOffset) / /*sizeof(FPackageObjectIndex)*/ sizeof(ulong); ImportMap = new FPackageObjectIndex[importMapCount]; for (int i = 0; i < importMapCount; i++) { ImportMap[i] = new FPackageObjectIndex(Loader); } Loader.BaseStream.Seek(Summary.ExportMapOffset, SeekOrigin.Begin); var exportMapCount = (Summary.ExportBundlesOffset - Summary.ExportMapOffset) / FExportMapEntry.SIZE; ExportMap = new FExportMapEntry[exportMapCount]; for (int i = 0; i < exportMapCount; i++) { ExportMap[i] = new FExportMapEntry(this); } ExportBundle = new FExportBundle(this); if (!onlyInfo) { ReadContent(); } }
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; }