public FIoStoreTocResource(Stream tocStream, EIoStoreTocReadOptions readOptions = EIoStoreTocReadOptions.Default) { var streamBuffer = new byte[tocStream.Length]; tocStream.Read(streamBuffer, 0, streamBuffer.Length); using var reader = new BinaryReader(new MemoryStream(streamBuffer)); Header = new FIoStoreTocHeader(reader); reader.BaseStream.Position = Header.TocHeaderSize; var totalTocSize = tocStream.Length - Header.TocHeaderSize; var tocMetaSize = Header.TocEntryCount * FIoStoreTocEntryMeta.SIZE; var defaultTocSize = totalTocSize - Header.DirectoryIndexSize - tocMetaSize; var tocSize = defaultTocSize; if (readOptions.HasAnyFlags(EIoStoreTocReadOptions.ReadTocMeta)) { tocSize = totalTocSize; // Meta data is at the end of the TOC file } if (readOptions.HasAnyFlags(EIoStoreTocReadOptions.ReadDirectoryIndex)) { tocSize = defaultTocSize + Header.DirectoryIndexSize; } // Chunk IDs ChunkIds = new FIoChunkId[Header.TocEntryCount]; for (var i = 0; i < Header.TocEntryCount; i++) { ChunkIds[i] = new FIoChunkId(reader); } // Chunk offsets ChunkOffsetLengths = new FIoOffsetAndLength[Header.TocEntryCount]; for (var i = 0; i < Header.TocEntryCount; i++) { ChunkOffsetLengths[i] = new FIoOffsetAndLength(reader); } // Compression blocks CompressionBlocks = new FIoStoreTocCompressedBlockEntry[Header.TocCompressedBlockEntryCount]; for (var i = 0; i < Header.TocCompressedBlockEntryCount; i++) { CompressionBlocks[i] = new FIoStoreTocCompressedBlockEntry(reader); } // Compression methods CompressionMethods = new string[Header.CompressionMethodNameCount]; // Not doing +1 nor adding CompressionMethod none here since the FPakInfo implementation doesn't as well for (var i = 0; i < Header.CompressionMethodNameCount; i++) { CompressionMethods[i] = Encoding.ASCII.GetString(reader.ReadBytes((int)Header.CompressionMethodNameLength)).TrimEnd('\0'); } // Chunk block signatures if (Header.ContainerFlags.HasAnyFlags(EIoContainerFlags.Signed)) { var hashSize = reader.ReadInt32(); reader.BaseStream.Position += hashSize; // actually: var tocSignature = reader.ReadBytes(hashSize); reader.BaseStream.Position += hashSize; // actually: var blockSignature = reader.ReadBytes(hashSize); ChunkBlockSignatures = new FSHAHash[Header.TocCompressedBlockEntryCount]; for (var i = 0; i < Header.TocCompressedBlockEntryCount; i++) { ChunkBlockSignatures[i] = new FSHAHash(reader); } // You could verify hashes here but nah } // Directory index if (Header.Version >= EIoStoreTocVersion.DirectoryIndex && readOptions.HasAnyFlags(EIoStoreTocReadOptions.ReadDirectoryIndex) && Header.ContainerFlags.HasAnyFlags(EIoContainerFlags.Indexed) && Header.DirectoryIndexSize > 0) { DirectoryIndexBuffer = reader.ReadBytes((int)Header.DirectoryIndexSize); } // Meta if (readOptions.HasAnyFlags(EIoStoreTocReadOptions.ReadTocMeta)) { ChunkMetas = new FIoStoreTocEntryMeta[Header.TocEntryCount]; for (var i = 0; i < Header.TocEntryCount; i++) { ChunkMetas[i] = new FIoStoreTocEntryMeta(reader); } } }
public FIoGlobalData(FFileIoStoreReader globalReader, IReadOnlyCollection <FFileIoStoreReader> allReaders) { var globalNamesIoBuffer = globalReader.Read(new FIoChunkId(0, 0, EIoChunkType.LoaderGlobalNames)); var globalNameHashesIoBuffer = globalReader.Read(new FIoChunkId(0, 0, EIoChunkType.LoaderGlobalNameHashes)); var globalNameMap = new List <FNameEntrySerialized>(); GlobalNameHashes = new List <ulong>(); FNameEntrySerialized.LoadNameBatch(globalNameMap, GlobalNameHashes, globalNamesIoBuffer, globalNameHashesIoBuffer); GlobalNameMap = globalNameMap.ToArray(); var initialLoadIoBuffer = globalReader.Read(new FIoChunkId(0, 0, EIoChunkType.LoaderInitialLoadMeta)); var initialLoadIoReader = new BinaryReader(new MemoryStream(initialLoadIoBuffer, false)); var numScriptObjects = initialLoadIoReader.ReadInt32(); var scriptObjectByGlobalIdKeys = new FPackageObjectIndex[numScriptObjects]; var scriptObjectByGlobalIdValues = new FScriptObjectDesc[numScriptObjects]; var globalIndices = new Dictionary <FPackageObjectIndex, int>(numScriptObjects); for (var i = 0; i < numScriptObjects; i++) { var scriptObjectEntry = new FScriptObjectEntry(initialLoadIoReader); globalIndices.TryAdd(scriptObjectEntry.GlobalIndex, i); var mappedName = new FMappedName(scriptObjectEntry.ObjectName, GlobalNameMap, null); if (!mappedName.IsGlobal()) { Debug.WriteLine(i); } scriptObjectByGlobalIdKeys[i] = scriptObjectEntry.GlobalIndex; scriptObjectByGlobalIdValues[i] = new FScriptObjectDesc(GlobalNameMap[(int)mappedName.GetIndex()], mappedName, scriptObjectEntry); } for (var i = 0; i < numScriptObjects; i++) { var scriptObjectDesc = scriptObjectByGlobalIdValues[i]; if (!scriptObjectDesc.FullName.IsNone) { continue; } var scriptObjectStack = new Stack <FScriptObjectDesc>(); var current = i; string fullName = string.Empty; while (current > 0) { var currentDesc = scriptObjectByGlobalIdValues[current]; if (!currentDesc.FullName.IsNone) { fullName = currentDesc.FullName.String; break; } scriptObjectStack.Push(currentDesc); globalIndices.TryGetValue(currentDesc.OuterIndex, out current); } while (scriptObjectStack.Count != 0) { var currentStack = scriptObjectStack.Pop(); if (fullName.Length == 0 || fullName.EndsWith('/')) { fullName = string.Concat(fullName, currentStack.Name.String); } else { fullName = string.Concat(fullName, "/", currentStack.Name.String); } currentStack.FullName = new FName(fullName); } } ScriptObjectByGlobalId = Enumerable.Range(0, numScriptObjects).ToDictionary(i => scriptObjectByGlobalIdKeys[i], i => scriptObjectByGlobalIdValues[i]); var packageByPackageIdMap = new Dictionary <FPackageId, FPackageStoreEntry>(); foreach (var reader in allReaders) { var headerChunkId = new FIoChunkId(reader.ContainerId.Id, 0, EIoChunkType.ContainerHeader); if (reader.DoesChunkExist(headerChunkId) && !reader.IsEncrypted) { var buffer = reader.Read(headerChunkId); using var headerReader = new BinaryReader(new MemoryStream(buffer, false)); var containerHeader = new FContainerHeader(headerReader); using var storeEntryReader = new BinaryReader(new MemoryStream(containerHeader.StoreEntries)); var containerPackages = new List <FPackageDesc>(); for (var i = 0; i < containerHeader.PackageCount; i++) { var containerEntry = new FPackageStoreEntry(storeEntryReader); var packageId = containerHeader.PackageIds[i]; if (!packageByPackageIdMap.TryGetValue(packageId, out var packageDesc)) { /* * packageDesc = new FPackageDesc(); * packageDesc.PackageId = packageId; * packageDesc.Size = containerEntry.ExportBundlesSize; * packageDesc.Exports = new FExportDesc[containerEntry.ExportCount]; * packageDesc.ExportBundleCount = containerEntry.ExportBundleCount; * packageDesc.LoadOrder = containerEntry.LoadOrder; */ packageByPackageIdMap[packageId] = containerEntry; } //containerPackages.Add(packageDesc); } } } }