public List <object> GetExportProperties(FObjectExport export) { List <object> properties = new List <object>(); long lastPos = this._openExportStream.Position; if (this._openExportStream.Position != export.ExportFileOffset) { this._openExportStream.Seek(export.ExportFileOffset, SeekOrigin.Begin); } while (this._openExportStream.Position < export.ExportFileOffset + export.SerialSize) { long propPos = this._openExportStream.Position; (bool, object?)property = GetProperty(); if (property.Item1) { properties.Add(property.Item2); } else if (property.Item2 is not null) { properties.Add(property.Item2); this._openExportStream.Seek(propPos, SeekOrigin.Begin); this._openExportStream.Seek((int)((dynamic)property.Item2).Size + 25, SeekOrigin.Current); } else { break; } } this._openExportStream.Seek(lastPos, SeekOrigin.Begin); return(properties); }
PackageReader(BinaryReader uasset, BinaryReader uexp, Stream ubulk) { Loader = uasset; PackageFileSummary = new FPackageFileSummary(Loader); NameMap = SerializeNameMap(); ImportMap = SerializeImportMap(); ExportMap = SerializeExportMap(); DataExports = new IUExport[ExportMap.Length]; DataExportTypes = new FName[ExportMap.Length]; Loader = uexp; for (int i = 0; i < ExportMap.Length; i++) { FObjectExport Export = ExportMap[i]; { FName ExportType; if (Export.ClassIndex.IsNull) { ExportType = DataExportTypes[i] = ReadFName(); // check if this is true, I don't know if Fortnite ever uses this } else if (Export.ClassIndex.IsExport) { ExportType = DataExportTypes[i] = ExportMap[Export.ClassIndex.AsExport].SuperIndex.Resource.ObjectName; } else if (Export.ClassIndex.IsImport) { ExportType = DataExportTypes[i] = ImportMap[Export.ClassIndex.AsImport].ObjectName; } else { throw new FileLoadException("Can't get class name"); // Shouldn't reach this unless the laws of math have bent to MagmaReef's will } if (ExportType.String.Equals("BlueprintGeneratedClass")) { continue; } var pos = Position = Export.SerialOffset - PackageFileSummary.TotalHeaderSize; DataExports[i] = ExportType.String switch { "Texture2D" => new UTexture2D(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), "CurveTable" => new UCurveTable(this), "DataTable" => new UDataTable(this), "FontFace" => new UFontFace(this, ubulk), "SoundWave" => new USoundWave(this, ubulk, ExportMap.Sum(e => e.SerialSize) + PackageFileSummary.TotalHeaderSize), "StringTable" => new UStringTable(this), _ => new UObject(this), }; #if DEBUG if (pos + Export.SerialSize != Position) { System.Diagnostics.Debug.WriteLine($"[ExportType={ExportType.String}] Didn't read {Export.ObjectName} correctly (at {Position}, should be {pos + Export.SerialSize}, {pos + Export.SerialSize - Position} behind)"); } #endif } } return; }
public static IExportObject VisitSubtype(BinaryReader reader, FObjectExport export, FPackageFileSummary summary) { if (ExportVisitors.TryGetValue(export.ClassIndex.Name, out var visitor)) { return(visitor(reader, export, summary)); } return(null); }
public ExportLoader(Package package, FObjectExport export, FAssetArchive archive) { _package = package; _export = export; _archive = archive; Lazy = new(() => { Fire(LoadPhase.Serialize); return(_object); }); export.ExportObject = Lazy; }
public static IExportObject Deserialize(BinaryReader reader, FObjectExport export, FPackageFileSummary summary) { var instance = new StringTable(); instance.Name = LSerializer.FString(reader); var count = reader.ReadInt32(); for (int i = 0; i < count; ++i) { instance.Add(LSerializer.FString(reader), LSerializer.FString(reader)); } return(instance); }
public static IExportObject Deserialize(BinaryReader reader, FObjectExport export, FPackageFileSummary summary) { StringTable stringTable = new StringTable(); stringTable.Name = LSerializer.FString(reader); int num = reader.ReadInt32(); for (int i = 0; i < num; i++) { stringTable.Add(LSerializer.FString(reader), LSerializer.FString(reader)); } return(stringTable); }
FObjectExport[] SerializeExportMap() { if (PackageFileSummary.ExportCount > 0) { Loader.BaseStream.Position = PackageFileSummary.ExportOffset; var OutExportMap = new FObjectExport[PackageFileSummary.ExportCount]; for (int ExportMapIdx = 0; ExportMapIdx < PackageFileSummary.ExportCount; ++ExportMapIdx) { OutExportMap[ExportMapIdx] = new FObjectExport(this); } return(OutExportMap); } return(Array.Empty <FObjectExport>()); }
public static IExportObject Deserialize(BinaryReader reader, FObjectExport export, FPackageFileSummary summary) { var instance = new UDataTable(); var count = reader.ReadInt32(); for (int i = 0; i < count; ++i) { var index = LSerializer.Deserialize <FName>(reader); index.Ref(summary); var uobj = new UObject(reader, summary, false); uobj.Name = index; instance.Add(index, uobj); } return(instance); }
public static IExportObject Deserialize(BinaryReader reader, FObjectExport export, FPackageFileSummary summary) { UDataTable uDataTable = new UDataTable(); int num = reader.ReadInt32(); for (int i = 0; i < num; i++) { FName fName = LSerializer.Deserialize <FName>(reader); fName.Ref(summary); UObject uObject = new UObject(reader, summary, pad: false); uObject.Name = fName; uDataTable.Add(fName, uObject); } return(uDataTable); }
private MemoryStream GetUEventStream(FObjectExport export, Stream uasset, Stream uexp) { Span <byte> buffer = new Span <byte>(new byte[export.SerialSize]); if (uexp != null) { uexp.Position = export.SerialOffset - Summary.TotalHeaderSize; uexp.Read(buffer); } else { uasset.Position = export.SerialOffset; uasset.Read(buffer); } return(new MemoryStream(buffer.ToArray())); }
public static IExportObject Deserialize(BinaryReader reader, FObjectExport export, FPackageFileSummary summary) { var instance = new EndTextResource(); var count = reader.ReadInt32(); for (int i = 0; i < count; ++i) { var key = LSerializer.FString(reader); if (string.IsNullOrEmpty(key) || key[0] != '$') { throw new InvalidDataException("The key does not start with magic symbol"); } var obj = LSerializer.Deserialize <FF7TxtRes>(reader); obj.GetEntries(reader, summary); instance.Add(key, obj); } return(instance); }
public UAsset(byte[] data, int version) : base(data) { Version = version; ReadSummary(); Seek(Summary.NameOffset); foreach (var i in Enumerable.Range(0, Summary.NameCount)) { var entry = new FNameEntrySerialized(); entry.Serialize(this); NameMap.Add(entry.Name); } Seek(Summary.GatherableTextDataOffset); foreach (var i in Enumerable.Range(0, Summary.GatherableTextDataCount)) { Debugger.Break(); // check whether it reads stuff properly var gatherable = new FGatherableTextData(); gatherable.Serialize(this); GatherableTextDataMap.Add(gatherable); } Seek(Summary.ImportOffset); foreach (var i in Enumerable.Range(0, Summary.ImportCount)) { var imp = new FObjectImport(); imp.Serialize(this); ImportMap.Add(imp); } Seek(Summary.ExportOffset); foreach (var i in Enumerable.Range(0, Summary.ExportCount)) { var exp = new FObjectExport(); exp.Serialize(this); ExportMap.Add(exp); } Seek(Summary.StringAssetReferencesOffset); foreach (var i in Enumerable.Range(0, Summary.StringAssetReferencesCount)) { StringAssetReferences.Add(ToFString()); } // TODO: Fixup import, fixup exports, match exports with exporter object }
public UObject(BinaryReader data, FPackageFileSummary summary, bool pad = true, FObjectExport export = null) { while (true) { var start = data.BaseStream.Position; #if DEBUG CachedPos.Add(start); #endif var name = LSerializer.Deserialize <FName>(data); name.Ref(summary); if (name == "None") { break; } data.BaseStream.Position = start; var tag = LSerializer.Deserialize <FPropertyTag>(data); data.BaseStream.Position = start; tag.Ref(summary); tag = VisitorFactory.Visit(data, tag, summary); tag.Ref(summary); Add(tag); } if (pad) { data.BaseStream.Position += 4; } if (export != null) { ObjectData = VisitorFactory.VisitSubtype(data, export, summary); } }
public UObject(FObjectExport exportObject) : base(exportObject) { Properties = new List <FPropertyTag>(); }
public Package(FArchive uasset, FArchive?uexp, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null, bool useLazySerialization = true) : base(uasset.Name.SubstringBeforeLast(".uasset"), provider, mappings) { // We clone the version container because it can be modified with package specific versions when reading the summary uasset.Versions = (VersionContainer)uasset.Versions.Clone(); var uassetAr = new FAssetArchive(uasset, this); Summary = new FPackageFileSummary(uassetAr); uassetAr.SeekAbsolute(Summary.NameOffset, SeekOrigin.Begin); NameMap = new FNameEntrySerialized[Summary.NameCount]; uassetAr.ReadArray(NameMap, () => new FNameEntrySerialized(uassetAr)); uassetAr.SeekAbsolute(Summary.ImportOffset, SeekOrigin.Begin); ImportMap = new FObjectImport[Summary.ImportCount]; uassetAr.ReadArray(ImportMap, () => new FObjectImport(uassetAr)); uassetAr.SeekAbsolute(Summary.ExportOffset, SeekOrigin.Begin); ExportMap = new FObjectExport[Summary.ExportCount]; // we need this to get its final size in some case uassetAr.ReadArray(ExportMap, () => new FObjectExport(uassetAr)); FAssetArchive uexpAr = uexp != null ? new FAssetArchive(uexp, this, (int)uassetAr.Length) : uassetAr; // allows embedded uexp data if (ubulk != null) { //var offset = (int) (Summary.TotalHeaderSize + ExportMap.Sum(export => export.SerialSize)); var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UBULK, offset, ubulk); } if (uptnl != null) { var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UPTNL, offset, uptnl); } if (useLazySerialization) { foreach (var export in ExportMap) { export.ExportObject = new Lazy <UObject>(() => { // Create var obj = ConstructObject(ResolvePackageIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = export.ObjectName.Text; obj.Outer = (ResolvePackageIndex(export.OuterIndex) as ResolvedExportObject)?.Object.Value ?? this; obj.Super = ResolvePackageIndex(export.SuperIndex) as ResolvedExportObject; obj.Template = ResolvePackageIndex(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 uexpAr.SeekAbsolute(export.SerialOffset, SeekOrigin.Begin); DeserializeObject(obj, uexpAr, export.SerialSize); // TODO right place ??? obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.PostLoad(); return(obj); }); } } else { var newObjNames = new List <string>(); foreach (var export in ExportMap) { if (export.ExportObject == null) { var obj = ConstructObject(ResolvePackageIndex(export.ClassIndex)?.Object?.Value as UStruct); obj.Name = export.ObjectName.Text; obj.Super = ResolvePackageIndex(export.SuperIndex) as ResolvedExportObject; obj.Template = ResolvePackageIndex(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 export.ExportObject = new Lazy <UObject>(obj); newObjNames.Add(export.ObjectName.Text); } } foreach (var export in ExportMap) { if (newObjNames.Contains(export.ObjectName.Text)) { var obj = export.ExportObject.Value; uexpAr.SeekAbsolute(export.SerialOffset, SeekOrigin.Begin); DeserializeObject(obj, uexpAr, export.SerialSize); } } foreach (var export in ExportMap) { if (newObjNames.Contains(export.ObjectName.Text)) { var obj = export.ExportObject.Value; obj.Outer = (ResolvePackageIndex(export.OuterIndex) as ResolvedExportObject)?.Object.Value ?? this; } } foreach (var export in ExportMap) { if (newObjNames.Contains(export.ObjectName.Text)) { var obj = export.ExportObject.Value; obj.Flags |= EObjectFlags.RF_LoadCompleted; obj.PostLoad(); } } } }
public ResolvedExportObject(int index, Package package) : base(package, index) { _export = package.ExportMap[index]; }
protected UExport(FObjectExport exportObject) : this(exportObject.ClassName) { Export = exportObject; Name = exportObject.ObjectName.Text; }
public Package(FArchive uasset, FArchive uexp, Lazy <FArchive?>?ubulk = null, Lazy <FArchive?>?uptnl = null, IFileProvider?provider = null, TypeMappings?mappings = null) : base(uasset.Name.SubstringBeforeLast(".uasset"), provider, mappings) { var uassetAr = new FAssetArchive(uasset, this); Summary = new FPackageFileSummary(uassetAr); if (Summary.Tag != PackageMagic) { throw new ParserException(uassetAr, $"Invalid uasset magic: {Summary.Tag} != {PackageMagic}"); } uassetAr.Seek(Summary.NameOffset, SeekOrigin.Begin); NameMap = new FNameEntrySerialized[Summary.NameCount]; uassetAr.ReadArray(NameMap, () => new FNameEntrySerialized(uassetAr)); uassetAr.Seek(Summary.ImportOffset, SeekOrigin.Begin); ImportMap = new FObjectImport[Summary.ImportCount]; uassetAr.ReadArray(ImportMap, () => new FObjectImport(uassetAr)); uassetAr.Seek(Summary.ExportOffset, SeekOrigin.Begin); ExportMap = new FObjectExport[Summary.ExportCount]; // we need this to get its final size in some case uassetAr.ReadArray(ExportMap, () => new FObjectExport(uassetAr)); var uexpAr = new FAssetArchive(uexp, this, Summary.TotalHeaderSize); if (ubulk != null) { //var offset = (int) (Summary.TotalHeaderSize + ExportMap.Sum(export => export.SerialSize)); var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UBULK, offset, ubulk); } if (uptnl != null) { var offset = Summary.BulkDataStartOffset; uexpAr.AddPayload(PayloadType.UPTNL, offset, uptnl); } foreach (var it in ExportMap) { if (ResolvePackageIndex(it.ClassIndex)?.Object?.Value is not UStruct uStruct) { continue; } var export = ConstructObject(uStruct); export.Name = it.ObjectName.Text; export.Outer = (ResolvePackageIndex(it.OuterIndex) as ResolvedExportObject)?.Object?.Value ?? this; export.Template = ResolvePackageIndex(it.TemplateIndex) as ResolvedExportObject; export.Flags = (int)it.ObjectFlags; it.ExportType = export.GetType(); it.ExportObject = new Lazy <UObject>(() => { uexpAr.SeekAbsolute(it.RealSerialOffset, SeekOrigin.Begin); var validPos = uexpAr.Position + it.SerialSize; try { export.Deserialize(uexpAr, validPos); #if DEBUG if (validPos != uexpAr.Position) { Log.Warning("Did not read {0} correctly, {1} bytes remaining", export.ExportType, validPos - uexpAr.Position); } else { Log.Debug("Successfully read {0} at {1} with size {2}", export.ExportType, it.RealSerialOffset, it.SerialSize); } #endif // TODO right place ??? export.PostLoad(); } catch (Exception e) { Log.Error(e, "Could not read {0} correctly", export.ExportType); } return(export); }); } }
public UObject(BinaryReader data, FPackageFileSummary summary, bool pad = true, FObjectExport export = null) { while (true) { long position = data.BaseStream.Position; FName fName = LSerializer.Deserialize <FName>(data); fName.Ref(summary); if ((string)fName == "None") { break; } data.BaseStream.Position = position; FPropertyTag fPropertyTag = LSerializer.Deserialize <FPropertyTag>(data); data.BaseStream.Position = position; fPropertyTag.Ref(summary); fPropertyTag = VisitorFactory.Visit(data, fPropertyTag, summary); fPropertyTag.Ref(summary); Add(fPropertyTag); } if (pad) { data.BaseStream.Position += 4L; } if (export != null) { ObjectData = VisitorFactory.VisitSubtype(data, export, summary); } }