虚幻4 加载蓝图的的过程(1)——读取文件头

来源:互联网 发布:c语言加密解密程序 编辑:程序博客网 时间:2024/06/05 14:28

首先是读取文件头:

文件头结构体:

Engine_Updating\Engine\Source\Runtime\CoreUObject\Public\UObject\Linker.h

/** * A "table of contents" for an Unreal package file.  Stored at the top of the file. */struct FPackageFileSummary{/** * Magic tag compared against PACKAGE_FILE_TAG to ensure that package is an Unreal package. */int32Tag;private:/* UE4 file version */int32FileVersionUE4;/* Licensee file version */int32FileVersionLicenseeUE4;/* Custom version numbers. Keyed off a unique tag for each custom component. */FCustomVersionContainer CustomVersionContainer;public:/** * Total size of all information that needs to be read in to create a FLinkerLoad. This includes * the package file summary, name table and import & export maps. */int32TotalHeaderSize;/** * The flags for the package */uint32PackageFlags;/** * The Generic Browser folder name that this package lives in */FStringFolderName;/** * Number of names used in this package */int32NameCount;/** * Location into the file on disk for the name data */int32 NameOffset;/** * Number of gatherable text data items in this package */int32GatherableTextDataCount;/** * Location into the file on disk for the gatherable text data items */int32 GatherableTextDataOffset;/** * Number of exports contained in this package */int32ExportCount;/** * Location into the file on disk for the ExportMap data */int32ExportOffset;/** * Number of imports contained in this package */int32ImportCount;/** * Location into the file on disk for the ImportMap data */int32ImportOffset;/*** Location into the file on disk for the DependsMap data*/int32DependsOffset;/** * Number of references contained in this package */int32StringAssetReferencesCount;/** * Location into the file on disk for the string asset references map data */int32StringAssetReferencesOffset;/** * Thumbnail table offset */int32ThumbnailTableOffset;/** * Current id for this package */FGuidGuid;/** * Data about previous versions of this package */TArray<FGenerationInfo> Generations;/** * Engine version this package was saved with. For hotfix releases and engine versions which maintain strict binary compatibility with another version, this may differ from CompatibleWithEngineVersion. */FEngineVersion SavedByEngineVersion;/** * Engine version this package is compatible with. See SavedByEngineVersion. */FEngineVersion CompatibleWithEngineVersion;/** * Flags used to compress the file on save and uncompress on load. */uint32CompressionFlags;/** * Value that is used to determine if the package was saved by Epic (or licensee) or by a modder, etc */uint32PackageSource;/** * Array of compressed chunks in case this package was stored compressed. */TArray<FCompressedChunk> CompressedChunks;/** * List of additional packages that are needed to be cooked for this package (ie streaming levels) */TArray<FString>AdditionalPackagesToCook;/**  * If true, this file will not be saved with version numbers or was saved without version numbers. In this case they are assumed to be the current version.  * This is only used for full cooks for distribution because it is hard to guarantee correctness  **/bool bUnversioned;#if WITH_ENGINE/** * Information about the textures stored in the package. */FTextureAllocationsTextureAllocations;#endif// WITH_ENGINE/** * Location into the file on disk for the asset registry tag data */int32 AssetRegistryDataOffset;/** Offset to the location in the file where the bulkdata starts */int64BulkDataStartOffset;/** * Offset to the location in the file where the FWorldTileInfo data starts */int32 WorldTileInfoDataOffset;/** * Streaming install ChunkIDs */TArray<int32>ChunkIDs;/** Constructor */COREUOBJECT_API FPackageFileSummary();int32 GetFileVersionUE4() const{return FileVersionUE4;}int32 GetFileVersionLicenseeUE4() const{return FileVersionLicenseeUE4;}const FCustomVersionContainer& GetCustomVersionContainer() const{return CustomVersionContainer;}void SetCustomVersionContainer(const FCustomVersionContainer& InContainer){CustomVersionContainer = InContainer;}void SetFileVersions(const int32 EpicUE4, const int32 LicenseeUE4, const bool bInSaveUnversioned = false){FileVersionUE4 = EpicUE4;FileVersionLicenseeUE4 = LicenseeUE4;bUnversioned = bInSaveUnversioned;}/** I/O function */friend COREUOBJECT_API FArchive& operator<<( FArchive& Ar, FPackageFileSummary& Sum );};


读取文件头函数位置:

Engine_Updating\Engine\Source\Runtime\CoreUObject\Private\UObject\PackageFileSummary.cpp

FArchive& operator<<( FArchive& Ar, FPackageFileSummary& Sum ){bool bCanStartSerializing = true;int64 ArchiveSize = 0;if (Ar.IsLoading()){// Sanity checks before we even start serializing the archiveArchiveSize = Ar.TotalSize();const int64 MinimumPackageSize = 32; // That should get us safely to Sum.TotalHeaderSizebCanStartSerializing = ArchiveSize >= MinimumPackageSize;UE_CLOG(!bCanStartSerializing, LogLinker, Warning,TEXT("Failed to read package file summary, the file \"%s\" is too small (%lld bytes, expected at least %lld bytes)"),*Ar.GetArchiveName(), ArchiveSize, MinimumPackageSize);}if (bCanStartSerializing){Ar << Sum.Tag;}// only keep loading if we match the magicif( Sum.Tag == PACKAGE_FILE_TAG || Sum.Tag == PACKAGE_FILE_TAG_SWAPPED ){// The package has been stored in a separate endianness than the linker expected so we need to force// endian conversion. Latent handling allows the PC version to retrieve information about cooked packages.if( Sum.Tag == PACKAGE_FILE_TAG_SWAPPED ){// Set proper tag.Sum.Tag = PACKAGE_FILE_TAG;// Toggle forced byte swapping.if( Ar.ForceByteSwapping() ){Ar.SetByteSwapping( false );}else{Ar.SetByteSwapping( true );}}/** * The package file version number when this package was saved. * * Lower 16 bits stores the UE3 engine version * Upper 16 bits stores the UE4/licensee version * For newer packages this is -6 *-2 indicates presence of enum-based custom versions *-3 indicates guid-based custom versions *-4 indicates removal of the UE3 version. Packages saved with this ID cannot be loaded in older engine versions  *-5 indicates the replacement of writing out the "UE3 version" so older versions of engine can gracefully fail to open newer packages *-6 indicates optimizations to how custom versions are being serialized */const int32 CurrentLegacyFileVersion = -6;int32 LegacyFileVersion = CurrentLegacyFileVersion;Ar << LegacyFileVersion;if (Ar.IsLoading()){if (LegacyFileVersion < 0) // means we have modern version numbers{if (LegacyFileVersion < CurrentLegacyFileVersion){// we can't safely load more than this because the legacy version code differs in ways we can not predict.// Make sure that the linker will fail to load with it.Sum.FileVersionUE4 = 0;Sum.FileVersionLicenseeUE4 = 0;return Ar;}if (LegacyFileVersion != -4){int32 LegacyUE3Version = 0;Ar << LegacyUE3Version;}Ar << Sum.FileVersionUE4;Ar << Sum.FileVersionLicenseeUE4;if (LegacyFileVersion <= -2){Sum.CustomVersionContainer.Serialize(Ar, GetCustomVersionFormatForArchive(LegacyFileVersion));}if (!Sum.FileVersionUE4 && !Sum.FileVersionLicenseeUE4){// this file is unversioned, remember that, then use current versionsSum.bUnversioned = true;Sum.FileVersionUE4 = GPackageFileUE4Version;Sum.FileVersionLicenseeUE4 = GPackageFileLicenseeUE4Version;Sum.CustomVersionContainer = FCustomVersionContainer::GetRegistered();}}else{// This is probably an old UE3 file, make sure that the linker will fail to load with it.Sum.FileVersionUE4 = 0;Sum.FileVersionLicenseeUE4 = 0;}}else{if (Sum.bUnversioned){int32 Zero = 0;Ar << Zero; // LegacyUE3versionAr << Zero; // VersionUE4Ar << Zero; // VersionLicenseeUE4FCustomVersionContainer NoCustomVersions;NoCustomVersions.Serialize(Ar);}else{// Must write out the last UE3 engine version, so that older versions identify it as newint32 LegacyUE3Version = 864;Ar << LegacyUE3Version;Ar << Sum.FileVersionUE4;Ar << Sum.FileVersionLicenseeUE4;// Serialise custom version map.Sum.CustomVersionContainer.Serialize(Ar);}}Ar << Sum.TotalHeaderSize;Ar << Sum.FolderName;Ar << Sum.PackageFlags;#if WITH_EDITORif (Ar.IsLoading()){// This flag should never be saved and its reused, so we need to make sure it hasn't been loaded.Sum.PackageFlags &= ~PKG_NewlyCreated;}#endif // WITH_EDITORif( Sum.PackageFlags & PKG_FilterEditorOnly ){Ar.SetFilterEditorOnly(true);}Ar << Sum.NameCount<< Sum.NameOffset;if (Sum.FileVersionUE4 >= VER_UE4_SERIALIZE_TEXT_IN_PACKAGES){Ar << Sum.GatherableTextDataCount<< Sum.GatherableTextDataOffset;}Ar << Sum.ExportCount<< Sum.ExportOffset;Ar << Sum.ImportCount<< Sum.ImportOffset;Ar << Sum.DependsOffset;if (Ar.IsLoading() && (Sum.FileVersionUE4 < VER_UE4_OLDEST_LOADABLE_PACKAGE || Sum.FileVersionUE4 > GPackageFileUE4Version)){return Ar; // we can't safely load more than this because the below was different in older files.}if (Ar.IsSaving() || Sum.FileVersionUE4 >= VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP){Ar << Sum.StringAssetReferencesCount << Sum.StringAssetReferencesOffset;}Ar << Sum.ThumbnailTableOffset;int32 GenerationCount = Sum.Generations.Num();Ar << Sum.Guid << GenerationCount;if( Ar.IsLoading() && GenerationCount > 0 ){Sum.Generations.Empty( 1 );Sum.Generations.AddUninitialized( GenerationCount );}for( int32 i=0; i<GenerationCount; i++ ){Sum.Generations[i].Serialize(Ar, Sum);}if( Sum.GetFileVersionUE4() >= VER_UE4_ENGINE_VERSION_OBJECT ){if(Ar.IsCooking() || (Ar.IsSaving() && !FEngineVersion::Current().HasChangelist())){FEngineVersion EmptyEngineVersion;Ar << EmptyEngineVersion;}else{Ar << Sum.SavedByEngineVersion;}}else{int32 EngineChangelist = 0;Ar << EngineChangelist;if(Ar.IsLoading() && EngineChangelist != 0){Sum.SavedByEngineVersion.Set(4, 0, 0, EngineChangelist, TEXT(""));}}if (Sum.GetFileVersionUE4() >= VER_UE4_PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION ){if(Ar.IsCooking() || (Ar.IsSaving() && !FEngineVersion::Current().HasChangelist())){FEngineVersion EmptyEngineVersion;Ar << EmptyEngineVersion;}else{Ar << Sum.CompatibleWithEngineVersion;}}else{if (Ar.IsLoading()){Sum.CompatibleWithEngineVersion = Sum.SavedByEngineVersion;}}Ar << Sum.CompressionFlags;Ar << Sum.CompressedChunks;Ar << Sum.PackageSource;Ar << Sum.AdditionalPackagesToCook;#if WITH_ENGINE//@todo legacyAr << Sum.TextureAllocations;#elsecheck(!"this can't serialize successfully");#endif// WITH_ENGINEAr << Sum.AssetRegistryDataOffset;Ar << Sum.BulkDataStartOffset;if (Sum.GetFileVersionUE4() >= VER_UE4_WORLD_LEVEL_INFO){Ar << Sum.WorldTileInfoDataOffset;}if (Sum.GetFileVersionUE4() >= VER_UE4_CHANGED_CHUNKID_TO_BE_AN_ARRAY_OF_CHUNKIDS){Ar << Sum.ChunkIDs;}else if (Sum.GetFileVersionUE4() >= VER_UE4_ADDED_CHUNKID_TO_ASSETDATA_AND_UPACKAGE){// handle conversion of single ChunkID to an array of ChunkIDsif (Ar.IsLoading()){int ChunkID = -1;Ar << ChunkID;// don't load <0 entries since an empty array represents the same thing nowif (ChunkID >= 0){Sum.ChunkIDs.Add( ChunkID );}}}}return Ar;}