예제 #1
0
        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();
            }
        }
예제 #2
0
        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;
        }