ExtPackageReader.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365
  1. // Copyright 2017-2021 marynate. All Rights Reserved.
  2. #include "ExtPackageReader.h"
  3. #include "ExtContentBrowser.h"
  4. #include "ExtAssetData.h"
  5. #include "HAL/FileManager.h"
  6. #include "UObject/Class.h"
  7. #include "UObject/PackageTrailer.h"
  8. #include "Misc/PackageName.h"
  9. #include "AssetRegistry/AssetData.h"
  10. #include "Logging/MessageLog.h"
  11. #include "AssetRegistry/IAssetRegistry.h"
  12. //#include "AssetRegistry.h"
  13. FExtPackageReader::FExtPackageReader()
  14. {
  15. Loader = nullptr;
  16. PackageFileSize = 0;
  17. AssetRegistryDependencyDataOffset = INDEX_NONE;
  18. bLoaderOwner = false;
  19. this->SetIsLoading(true);
  20. this->SetIsPersistent(true);
  21. }
  22. FExtPackageReader::~FExtPackageReader()
  23. {
  24. if (Loader && bLoaderOwner)
  25. {
  26. delete Loader;
  27. }
  28. }
  29. bool FExtPackageReader::OpenPackageFile(const FString& InPackageFilename, EOpenPackageResult* OutErrorCode)
  30. {
  31. PackageFilename = InPackageFilename;
  32. Loader = IFileManager::Get().CreateFileReader(*PackageFilename);
  33. bLoaderOwner = true;
  34. return OpenPackageFile(OutErrorCode);
  35. }
  36. bool FExtPackageReader::OpenPackageFile(FArchive* InLoader, EOpenPackageResult* OutErrorCode)
  37. {
  38. Loader = InLoader;
  39. bLoaderOwner = false;
  40. PackageFilename = Loader->GetArchiveName();
  41. return OpenPackageFile(OutErrorCode);
  42. }
  43. bool FExtPackageReader::OpenPackageFile(EOpenPackageResult* OutErrorCode)
  44. {
  45. auto SetPackageErrorCode = [&](const EOpenPackageResult InErrorCode)
  46. {
  47. if (OutErrorCode)
  48. {
  49. *OutErrorCode = InErrorCode;
  50. }
  51. };
  52. if( Loader == nullptr )
  53. {
  54. // Couldn't open the file
  55. SetPackageErrorCode(EOpenPackageResult::NoLoader);
  56. return false;
  57. }
  58. // Read package file summary from the file
  59. *Loader << PackageFileSummary;
  60. // Validate the summary.
  61. // Make sure this is indeed a package
  62. if( PackageFileSummary.Tag != PACKAGE_FILE_TAG || Loader->IsError() )
  63. {
  64. // Unrecognized or malformed package file
  65. SetPackageErrorCode(EOpenPackageResult::MalformedTag);
  66. return false;
  67. }
  68. // Don't read packages without header
  69. if (PackageFileSummary.TotalHeaderSize == 0)
  70. {
  71. SetPackageErrorCode(EOpenPackageResult::FailedToLoad);
  72. return false;
  73. }
  74. if (!PackageFileSummary.IsFileVersionValid())
  75. {
  76. // Log a warning rather than an error. Linkerload gracefully handles this case.
  77. SetPackageErrorCode(EOpenPackageResult::Unversioned);
  78. return false;
  79. }
  80. // Don't read packages that are too old
  81. if( PackageFileSummary.IsFileVersionTooOld())
  82. {
  83. SetPackageErrorCode(EOpenPackageResult::VersionTooOld);
  84. return false;
  85. }
  86. // Don't read packages that were saved with an package version newer than the current one.
  87. if(PackageFileSummary.IsFileVersionTooNew() || PackageFileSummary.GetFileVersionLicenseeUE() > GPackageFileLicenseeUEVersion)
  88. {
  89. SetPackageErrorCode(EOpenPackageResult::VersionTooNew);
  90. return false;
  91. }
  92. // Check serialized custom versions against latest custom versions.
  93. #if ECB_WIP_IMPORT_CHECK_CUSTOM_VERSION // Ignore Custom Version Check
  94. TArray<FCustomVersionDifference> Diffs = FCurrentCustomVersions::Compare(PackageFileSummary.GetCustomVersionContainer().GetAllVersions(), *PackageFilename);
  95. for (FCustomVersionDifference Diff : Diffs)
  96. {
  97. if (Diff.Type == ECustomVersionDifference::Missing)
  98. {
  99. SetPackageErrorCode(EOpenPackageResult::CustomVersionMissing);
  100. return false;
  101. }
  102. else if (Diff.Type == ECustomVersionDifference::Invalid)
  103. {
  104. SetPackageErrorCode(EOpenPackageResult::CustomVersionInvalid);
  105. return false;
  106. }
  107. else if (Diff.Type == ECustomVersionDifference::Newer)
  108. {
  109. SetPackageErrorCode(EOpenPackageResult::VersionTooNew);
  110. return false;
  111. }
  112. }
  113. #endif //
  114. //make sure the filereader gets the correct version number (it defaults to latest version)
  115. SetUEVer(PackageFileSummary.GetFileVersionUE());
  116. SetLicenseeUEVer(PackageFileSummary.GetFileVersionLicenseeUE());
  117. SetEngineVer(PackageFileSummary.SavedByEngineVersion);
  118. Loader->SetUEVer(PackageFileSummary.GetFileVersionUE());
  119. Loader->SetLicenseeUEVer(PackageFileSummary.GetFileVersionLicenseeUE());
  120. Loader->SetEngineVer(PackageFileSummary.SavedByEngineVersion);
  121. SetByteSwapping(Loader->ForceByteSwapping());
  122. const FCustomVersionContainer& PackageFileSummaryVersions = PackageFileSummary.GetCustomVersionContainer();
  123. SetCustomVersions(PackageFileSummaryVersions);
  124. Loader->SetCustomVersions(PackageFileSummaryVersions);
  125. PackageFileSize = Loader->TotalSize();
  126. SetPackageErrorCode(EOpenPackageResult::Success);
  127. return true;
  128. }
  129. bool FExtPackageReader::StartSerializeSection(int64 Offset)
  130. {
  131. check(Loader);
  132. if (Offset <= 0 || Offset > PackageFileSize)
  133. {
  134. return false;
  135. }
  136. ClearError();
  137. Loader->ClearError();
  138. Seek(Offset);
  139. return !IsError();
  140. }
  141. namespace UA::AssetRegistry
  142. {
  143. class FNameMapAwareArchive : public FArchiveProxy
  144. {
  145. TArray<FNameEntryId> NameMap;
  146. public:
  147. FNameMapAwareArchive(FArchive& Inner)
  148. : FArchiveProxy(Inner)
  149. {}
  150. FORCEINLINE virtual FArchive& operator<<(FName& Name) override
  151. {
  152. FArchive& Ar = *this;
  153. int32 NameIndex;
  154. Ar << NameIndex;
  155. int32 Number = 0;
  156. Ar << Number;
  157. if (NameMap.IsValidIndex(NameIndex))
  158. {
  159. // if the name wasn't loaded (because it wasn't valid in this context)
  160. FNameEntryId MappedName = NameMap[NameIndex];
  161. // simply create the name from the NameMap's name and the serialized instance number
  162. Name = FName::CreateFromDisplayId(MappedName, Number);
  163. }
  164. else
  165. {
  166. Name = FName();
  167. SetCriticalError();
  168. }
  169. return *this;
  170. }
  171. void SerializeNameMap(const FPackageFileSummary& PackageFileSummary)
  172. {
  173. Seek(PackageFileSummary.NameOffset);
  174. NameMap.Reserve(PackageFileSummary.NameCount);
  175. FNameEntrySerialized NameEntry(ENAME_LinkerConstructor);
  176. for (int32 Idx = NameMap.Num(); Idx < PackageFileSummary.NameCount; ++Idx)
  177. {
  178. *this << NameEntry;
  179. NameMap.Emplace(FName(NameEntry).GetDisplayIndex());
  180. }
  181. }
  182. };
  183. FString ReconstructFullClassPath(FArchive& BinaryArchive, const FString& PackageName, const FPackageFileSummary& PackageFileSummary, const FString& AssetClassName,
  184. const TArray<FObjectImport>* InImports = nullptr, const TArray<FObjectExport>* InExports = nullptr)
  185. {
  186. FName ClassFName(*AssetClassName);
  187. FLinkerTables LinkerTables;
  188. if (!InImports || !InExports)
  189. {
  190. FNameMapAwareArchive NameMapArchive(BinaryArchive);
  191. NameMapArchive.SerializeNameMap(PackageFileSummary);
  192. // Load the linker tables
  193. if (!InImports)
  194. {
  195. BinaryArchive.Seek(PackageFileSummary.ImportOffset);
  196. for (int32 ImportMapIndex = 0; ImportMapIndex < PackageFileSummary.ImportCount; ++ImportMapIndex)
  197. {
  198. NameMapArchive << LinkerTables.ImportMap.Emplace_GetRef();
  199. }
  200. }
  201. if (!InExports)
  202. {
  203. BinaryArchive.Seek(PackageFileSummary.ExportOffset);
  204. for (int32 ExportMapIndex = 0; ExportMapIndex < PackageFileSummary.ExportCount; ++ExportMapIndex)
  205. {
  206. NameMapArchive << LinkerTables.ExportMap.Emplace_GetRef();
  207. }
  208. }
  209. }
  210. if (InImports)
  211. {
  212. LinkerTables.ImportMap = *InImports;
  213. }
  214. if (InExports)
  215. {
  216. LinkerTables.ExportMap = *InExports;
  217. }
  218. FString ClassPathName;
  219. // Now look through the exports' classes and find the one matching the asset class
  220. for (const FObjectExport& Export : LinkerTables.ExportMap)
  221. {
  222. if (Export.ClassIndex.IsImport())
  223. {
  224. if (LinkerTables.ImportMap[Export.ClassIndex.ToImport()].ObjectName == ClassFName)
  225. {
  226. ClassPathName = LinkerTables.GetImportPathName(Export.ClassIndex.ToImport());
  227. break;
  228. }
  229. }
  230. else if (Export.ClassIndex.IsExport())
  231. {
  232. if (LinkerTables.ExportMap[Export.ClassIndex.ToExport()].ObjectName == ClassFName)
  233. {
  234. ClassPathName = LinkerTables.GetExportPathName(PackageName, Export.ClassIndex.ToExport());
  235. break;
  236. }
  237. }
  238. }
  239. if (ClassPathName.IsEmpty())
  240. {
  241. //UE_LOG(LogAssetRegistry, Error, TEXT("Failed to find an import or export matching asset class short name \"%s\"."), *AssetClassName);
  242. // Just pass through the short class name
  243. ClassPathName = AssetClassName;
  244. }
  245. return ClassPathName;
  246. }
  247. };
  248. #define ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING(MessageKey, PackageFileName) \
  249. do \
  250. {\
  251. FFormatNamedArguments CorruptPackageWarningArguments; \
  252. CorruptPackageWarningArguments.Add(TEXT("FileName"), FText::FromString(PackageFileName)); \
  253. FMessageLog("AssetRegistry").Warning(FText::Format(NSLOCTEXT("AssetRegistry", MessageKey, "Cannot read AssetRegistry Data in {FileName}, skipping it. Error: " MessageKey "."), CorruptPackageWarningArguments)); \
  254. } while (false)
  255. bool FExtPackageReader::ReadAssetRegistryData (TArray<FAssetData*>& AssetDataList)
  256. {
  257. if (!StartSerializeSection(PackageFileSummary.AssetRegistryDataOffset))
  258. {
  259. return false;
  260. }
  261. FString PackageName;
  262. if (!FPackageName::TryConvertFilenameToLongPackageName(PackageFilename, PackageName))
  263. {
  264. // Path was possibly unmounted
  265. return false;
  266. }
  267. FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
  268. const bool bIsMapPackage = (PackageFileSummary.GetPackageFlags() & PKG_ContainsMap) != 0;
  269. // ? To avoid large patch sizes, we have frozen cooked package format at the format before VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS
  270. bool bPreDependencyFormat = PackageFileSummary.GetFileVersionUE() < VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS;// || !!(PackageFileSummary.PackageFlags & PKG_FilterEditorOnly);
  271. if (bPreDependencyFormat)
  272. {
  273. AssetRegistryDependencyDataOffset = INDEX_NONE;
  274. }
  275. else
  276. {
  277. *this << AssetRegistryDependencyDataOffset;
  278. }
  279. // Load the object count
  280. int32 ObjectCount = 0;
  281. *this << ObjectCount;
  282. const int32 MinBytesPerObject = 1;
  283. // Check invalid object count
  284. if (this->IsError() || ObjectCount < 0 || PackageFileSize < this->Tell() + ObjectCount * MinBytesPerObject)
  285. {
  286. return false;
  287. }
  288. // Worlds that were saved before they were marked public do not have asset data so we will synthesize it here to make sure we see all legacy umaps
  289. // We will also do this for maps saved after they were marked public but no asset data was saved for some reason. A bug caused this to happen for some maps.
  290. if (bIsMapPackage)
  291. {
  292. const bool bLegacyPackage = PackageFileSummary.GetFileVersionUE() < VER_UE4_PUBLIC_WORLDS;
  293. const bool bNoMapAsset = (ObjectCount == 0);
  294. if (bLegacyPackage || bNoMapAsset)
  295. {
  296. FString AssetName = FPackageName::GetLongPackageAssetName(PackageName);
  297. AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(*AssetName), FTopLevelAssetPath(TEXT("/Script/Engine"), TEXT("World")), FAssetDataTagMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.GetPackageFlags()));
  298. }
  299. }
  300. const int32 MinBytesPerTag = 1;
  301. // UAsset files usually only have one asset, maps and redirectors have multiple
  302. for(int32 ObjectIdx = 0; ObjectIdx < ObjectCount; ++ObjectIdx)
  303. {
  304. FString ObjectPath;
  305. FString ObjectClassName;
  306. int32 TagCount = 0;
  307. *this << ObjectPath;
  308. *this << ObjectClassName;
  309. *this << TagCount;
  310. // check invalid tag count
  311. if (this->IsError() || TagCount < 0 || PackageFileSize < this->Tell() + TagCount * MinBytesPerTag)
  312. {
  313. return false;
  314. }
  315. FAssetDataTagMap TagsAndValues;
  316. TagsAndValues.Reserve(TagCount);
  317. for(int32 TagIdx = 0; TagIdx < TagCount; ++TagIdx)
  318. {
  319. FString Key;
  320. FString Value;
  321. *this << Key;
  322. *this << Value;
  323. // check invalid tag
  324. if (this->IsError())
  325. {
  326. return false;
  327. }
  328. if (!Key.IsEmpty() && !Value.IsEmpty())
  329. {
  330. TagsAndValues.Add(FName(*Key), Value);
  331. }
  332. }
  333. // Before world were RF_Public, other non-public assets were added to the asset data table in map packages.
  334. // Here we simply skip over them
  335. if (bIsMapPackage && PackageFileSummary.GetFileVersionUE() < VER_UE4_PUBLIC_WORLDS)
  336. {
  337. if (ObjectPath != FPackageName::GetLongPackageAssetName(PackageName))
  338. {
  339. continue;
  340. }
  341. }
  342. // if we have an object path that starts with the package then this asset is outer-ed to another package
  343. const bool bFullObjectPath = ObjectPath.StartsWith(TEXT("/"), ESearchCase::CaseSensitive);
  344. // if we do not have a full object path already, build it
  345. if (!bFullObjectPath)
  346. {
  347. // if we do not have a full object path, ensure that we have a top level object for the package and not a sub object
  348. if (!ensureMsgf(!ObjectPath.Contains(TEXT("."), ESearchCase::CaseSensitive), TEXT("Cannot make FAssetData for sub object %s in package %s!"), *ObjectPath, *PackageName))
  349. {
  350. ECB_LOG(Warning, TEXT("Cannot make FAssetData for sub object %s!"), *ObjectPath);
  351. continue;
  352. }
  353. ObjectPath = PackageName + TEXT(".") + ObjectPath;
  354. }
  355. // Previously export couldn't have its outer as an import
  356. else if (PackageFileSummary.GetFileVersionUE() < VER_UE4_NON_OUTER_PACKAGE_IMPORT)
  357. {
  358. ECB_LOG(Warning, TEXT("Package has invalid export %s, resave source package!"), *ObjectPath);
  359. continue;
  360. }
  361. ObjectClassName = UA::AssetRegistry::ReconstructFullClassPath(*this, PackageName, PackageFileSummary,
  362. ObjectClassName, &ImportMap, &ExportMap);
  363. // Create a new FAssetData for this asset and update it with the gathered data
  364. AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(*ObjectPath), FTopLevelAssetPath(ObjectClassName), MoveTemp(TagsAndValues), PackageFileSummary.ChunkIDs, PackageFileSummary.GetPackageFlags()));
  365. }
  366. return true;
  367. }
  368. bool FExtPackageReader::ReadAssetRegistryData(FExtAssetData& OutAssetData)
  369. {
  370. if (!StartSerializeSection(PackageFileSummary.AssetRegistryDataOffset))
  371. {
  372. return false;
  373. }
  374. #if ECB_LEGACY
  375. // Determine the package name and path
  376. FString PackageName = FPackageName::FilenameToLongPackageName(PackageFilename);
  377. FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
  378. #endif
  379. const bool bIsMapPackage = (PackageFileSummary.GetPackageFlags() & PKG_ContainsMap) != 0;
  380. // Load the object count
  381. int32 ObjectCount = 0;
  382. {
  383. // ? To avoid large patch sizes, we have frozen cooked package format at the format before VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS
  384. bool bPreDependencyFormat = PackageFileSummary.GetFileVersionUE() < VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS;// || !!(PackageFileSummary.PackageFlags & PKG_FilterEditorOnly);
  385. int64 DependencyDataOffset;
  386. if (!bPreDependencyFormat)
  387. {
  388. *this << DependencyDataOffset;
  389. }
  390. // Load the object count
  391. *this << ObjectCount;
  392. const int32 MinBytesPerObject = 1;
  393. // Check invalid object count
  394. if (this->IsError() || ObjectCount < 0 || PackageFileSize < this->Tell() + ObjectCount * MinBytesPerObject)
  395. {
  396. return false;
  397. }
  398. }
  399. OutAssetData.AssetCount = ObjectCount;
  400. #if ECB_TODO // do we need really special treatment of legacy map asset?
  401. // Worlds that were saved before they were marked public do not have asset data so we will synthesize it here to make sure we see all legacy umaps
  402. // We will also do this for maps saved after they were marked public but no asset data was saved for some reason. A bug caused this to happen for some maps.
  403. if (bIsMapPackage)
  404. {
  405. const bool bLegacyPackage = PackageFileSummary.GetFileVersionUE4() < VER_UE4_PUBLIC_WORLDS;
  406. const bool bNoMapAsset = (ObjectCount == 0);
  407. if (bLegacyPackage || bNoMapAsset)
  408. {
  409. FString AssetName = FPackageName::GetLongPackageAssetName(PackageName);
  410. AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(*AssetName), FName(TEXT("World")), FAssetDataTagMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags));
  411. }
  412. }
  413. #endif
  414. const int32 MinBytesPerTag = 1;
  415. // UAsset files usually only have one asset, maps and redirectors have multiple
  416. //for (int32 ObjectIdx = 0; ObjectIdx < ObjectCount; ++ObjectIdx)
  417. if (ObjectCount > 0) // Only care about first
  418. {
  419. FString ObjectPath;
  420. FString ObjectClassName;
  421. int32 TagCount = 0;
  422. *this << ObjectPath;
  423. *this << ObjectClassName;
  424. *this << TagCount;
  425. // check invalid tag count
  426. if (this->IsError() || TagCount < 0 || PackageFileSize < this->Tell() + TagCount * MinBytesPerTag)
  427. {
  428. return false;
  429. }
  430. ECB_LOG(Display, TEXT("\t\t%s'%s' (%d Tags)"), *ObjectClassName, *ObjectPath, TagCount); // Output : StaticMesh'SM_Test_LOD0' (14 Tags)
  431. OutAssetData.AssetName = FName(*ObjectPath);
  432. OutAssetData.AssetClass = FName(*ObjectClassName);
  433. FAssetDataTagMap TagsAndValues;
  434. TagsAndValues.Reserve(TagCount);
  435. for (int32 TagIdx = 0; TagIdx < TagCount; ++TagIdx)
  436. {
  437. FString Key;
  438. FString Value;
  439. *this << Key;
  440. *this << Value;
  441. // check invalid tag
  442. if (this->IsError())
  443. {
  444. return false;
  445. }
  446. if (!Key.IsEmpty() && !Value.IsEmpty())
  447. {
  448. TagsAndValues.Add(FName(*Key), Value);
  449. //ECB_LOG(Display, TEXT("\t\t\t\"%s\": \"%s\""), *Key, *Value);
  450. }
  451. }
  452. OutAssetData.TagsAndValues = FAssetDataTagMapSharedView(MoveTemp(TagsAndValues));
  453. #if ECB_TODO
  454. if (ObjectPath.StartsWith(TEXT("/"), ESearchCase::CaseSensitive))
  455. {
  456. // This should never happen, it means that package A has an export with an outer of package B
  457. ECB_LOG(Warning, TEXT("Package %s has invalid export %s, resave source package!"), *PackageName, *ObjectPath);
  458. continue;
  459. }
  460. if (!ensureMsgf(!ObjectPath.Contains(TEXT("."), ESearchCase::CaseSensitive), TEXT("Cannot make FAssetData for sub object %s!"), *ObjectPath))
  461. {
  462. continue;
  463. }
  464. FString AssetName = ObjectPath;
  465. // Before world were RF_Public, other non-public assets were added to the asset data table in map packages.
  466. // Here we simply skip over them
  467. if (bIsMapPackage && PackageFileSummary.GetFileVersionUE4() < VER_UE4_PUBLIC_WORLDS)
  468. {
  469. if (AssetName != FPackageName::GetLongPackageAssetName(PackageName))
  470. {
  471. continue;
  472. }
  473. }
  474. // Create a new FAssetData for this asset and update it with the gathered data
  475. AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(*AssetName), FName(*ObjectClassName), MoveTemp(TagsAndValues), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags));
  476. #endif
  477. }
  478. return true;
  479. }
  480. bool FExtPackageReader::SerializeAssetRegistryDependencyData(FExtPackageDependencyData& DependencyData)
  481. {
  482. if (AssetRegistryDependencyDataOffset == INDEX_NONE)
  483. {
  484. // For old package versions that did not write out the dependency flags, set default values of the flags
  485. DependencyData.ImportUsedInGame.Init(true, DependencyData.ImportMap.Num());
  486. DependencyData.SoftPackageUsedInGame.Init(true, DependencyData.SoftPackageReferenceList.Num());
  487. return true;
  488. }
  489. if (!StartSerializeSection(AssetRegistryDependencyDataOffset))
  490. {
  491. return false;
  492. }
  493. if (!UE::AssetRegistry::ReadPackageDataDependencies(*this, DependencyData.ImportUsedInGame, DependencyData.SoftPackageUsedInGame))
  494. {
  495. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeAssetRegistryDependencyData", PackageFilename);
  496. return false;
  497. }
  498. return true;
  499. }
  500. bool FExtPackageReader::SerializePackageTrailer(FAssetPackageData& PackageData)
  501. {
  502. if (!StartSerializeSection(PackageFileSummary.PayloadTocOffset))
  503. {
  504. PackageData.SetHasVirtualizedPayloads(false);
  505. return true;
  506. }
  507. UE::FPackageTrailer Trailer;
  508. if (!Trailer.TryLoad(*this))
  509. {
  510. // This is not necessarily corrupt; TryLoad will return false if the trailer is empty
  511. PackageData.SetHasVirtualizedPayloads(false);
  512. return true;
  513. }
  514. PackageData.SetHasVirtualizedPayloads(Trailer.GetNumPayloads(UE::EPayloadStorageType::Virtualized) > 0);
  515. return true;
  516. }
  517. bool FExtPackageReader::ReadAssetDataFromThumbnailCache(TArray<FAssetData*>& AssetDataList)
  518. {
  519. if (!StartSerializeSection(PackageFileSummary.ThumbnailTableOffset))
  520. {
  521. return false;
  522. }
  523. // Determine the package name and path
  524. FString PackageName = FPackageName::FilenameToLongPackageName(PackageFilename);
  525. FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
  526. // Load the thumbnail count
  527. int32 ObjectCount = 0;
  528. *this << ObjectCount;
  529. // Iterate over every thumbnail entry and harvest the objects classnames
  530. for(int32 ObjectIdx = 0; ObjectIdx < ObjectCount; ++ObjectIdx)
  531. {
  532. // Serialize the classname
  533. FString AssetClassName;
  534. *this << AssetClassName;
  535. // Serialize the object path.
  536. FString ObjectPathWithoutPackageName;
  537. *this << ObjectPathWithoutPackageName;
  538. // Serialize the rest of the data to get at the next object
  539. int32 FileOffset = 0;
  540. *this << FileOffset;
  541. FString GroupNames;
  542. FString AssetName;
  543. if (!ensureMsgf(!ObjectPathWithoutPackageName.Contains(TEXT("."), ESearchCase::CaseSensitive), TEXT("Cannot make FAssetData for sub object %s!"), *ObjectPathWithoutPackageName))
  544. {
  545. continue;
  546. }
  547. // Create a new FAssetData for this asset and update it with the gathered data
  548. AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(*ObjectPathWithoutPackageName), FTopLevelAssetPath(AssetClassName), FAssetDataTagMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.GetPackageFlags()));
  549. }
  550. return true;
  551. }
  552. bool FExtPackageReader::ReadAssetDataFromThumbnailCache(FExtAssetData& OutAssetData)
  553. {
  554. if (!StartSerializeSection(PackageFileSummary.ThumbnailTableOffset))
  555. {
  556. return false;
  557. }
  558. #if ECB_LEGACY
  559. // Determine the package name and path
  560. FString PackageName = FPackageName::FilenameToLongPackageName(PackageFilename);
  561. FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
  562. #endif
  563. // Load the thumbnail count
  564. int32 ObjectCount = 0;
  565. *this << ObjectCount;
  566. OutAssetData.ThumbCount = ObjectCount;
  567. // Iterate over every thumbnail entry and harvest the objects classnames
  568. //for (int32 ObjectIdx = 0; ObjectIdx < ObjectCount; ++ObjectIdx)
  569. if (ObjectCount > 0)
  570. {
  571. // Serialize the classname
  572. FString AssetClassName;
  573. *this << AssetClassName;
  574. // Serialize the object path.
  575. FString ObjectPathWithoutPackageName;
  576. *this << ObjectPathWithoutPackageName;
  577. // Serialize the rest of the data to get at the next object
  578. int32 FileOffset = 0;
  579. *this << FileOffset;
  580. bool bHaveValidClassName = !AssetClassName.IsEmpty() && AssetClassName != TEXT("???");
  581. if (OutAssetData.AssetClass == NAME_None && bHaveValidClassName)
  582. {
  583. OutAssetData.AssetClass = FName(*AssetClassName);
  584. }
  585. const bool bHaveValidAssetName = !ObjectPathWithoutPackageName.IsEmpty();
  586. if (OutAssetData.AssetName == NAME_None && bHaveValidAssetName)
  587. {
  588. OutAssetData.AssetName = FName(*ObjectPathWithoutPackageName);
  589. }
  590. if (FileOffset > 0 && FileOffset < PackageFileSize)
  591. {
  592. OutAssetData.SetHasThumbnail(true);
  593. }
  594. #if ECB_LEGACY
  595. FString GroupNames;
  596. FString AssetName;
  597. if (!ensureMsgf(!ObjectPathWithoutPackageName.Contains(TEXT("."), ESearchCase::CaseSensitive), TEXT("Cannot make FAssetData for sub object %s!"), *ObjectPathWithoutPackageName))
  598. {
  599. continue;
  600. }
  601. // Create a new FAssetData for this asset and update it with the gathered data
  602. AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), FName(*ObjectPathWithoutPackageName), FName(*AssetClassName), FAssetDataTagMap(), PackageFileSummary.ChunkIDs, PackageFileSummary.PackageFlags));
  603. #endif
  604. }
  605. return true;
  606. }
  607. bool FExtPackageReader::ReadDependencyData(FExtAssetData& OutAssetData)
  608. {
  609. FExtPackageDependencyData DependencyData;
  610. DependencyData.PackageName = OutAssetData.PackageName;// FName(*FPackageName::FilenameToLongPackageName(PackageFilename));
  611. if (!SerializeNameMap())
  612. {
  613. return false;
  614. }
  615. if (!SerializeImportMap())
  616. {
  617. return false;
  618. }
  619. const bool bReadPackageData = false;
  620. if (bReadPackageData/*EnumHasAnyFlags(Options, EReadOptions::PackageData)*/)
  621. {
  622. DependencyData.bHasPackageData = true;
  623. FAssetPackageData& PackageData = DependencyData.PackageData;
  624. PackageData.DiskSize = PackageFileSize;
  625. PRAGMA_DISABLE_DEPRECATION_WARNINGS
  626. PackageData.PackageGuid = PackageFileSummary.Guid;
  627. PRAGMA_ENABLE_DEPRECATION_WARNINGS
  628. PackageData.SetCustomVersions(PackageFileSummary.GetCustomVersionContainer().GetAllVersions());
  629. PackageData.FileVersionUE = PackageFileSummary.GetFileVersionUE();
  630. PackageData.FileVersionLicenseeUE = PackageFileSummary.GetFileVersionLicenseeUE();
  631. PackageData.SetIsLicenseeVersion(PackageFileSummary.SavedByEngineVersion.IsLicenseeVersion());
  632. PackageData.Extension = FPackagePath::ParseExtension(PackageFilename);
  633. if (!SerializeImportedClasses(DependencyData.ImportMap, PackageData.ImportedClasses))
  634. {
  635. return false;
  636. }
  637. if (!SerializePackageTrailer(PackageData))
  638. {
  639. return false;
  640. }
  641. }
  642. const bool bReadDependencies = true;
  643. if (bReadDependencies/*EnumHasAnyFlags(Options, EReadOptions::Dependencies)*/)
  644. {
  645. DependencyData.bHasDependencyData = true;
  646. if (!SerializeSoftPackageReferenceList(DependencyData.SoftPackageReferenceList))
  647. {
  648. return false;
  649. }
  650. if (!SerializeSearchableNamesMap(DependencyData))
  651. {
  652. return false;
  653. }
  654. if (!SerializeAssetRegistryDependencyData(DependencyData))
  655. {
  656. return false;
  657. }
  658. SerializeExportMap();
  659. DependencyData.ImportMap = ImportMap;
  660. DependencyData.ExportMap = ExportMap;
  661. }
  662. FName LinkerName = *PackageFilename;
  663. auto& HardDependentPackages = OutAssetData.HardDependentPackages;
  664. for (int32 i = 0; i < ImportMap.Num(); ++i)
  665. {
  666. FObjectImport& import = ImportMap[i];
  667. FName DependentPackageName = NAME_None;
  668. if (!import.OuterIndex.IsNull())
  669. {
  670. // Find the package which contains this import. import.SourceLinker is cleared in EndLoad, so we'll need to do this manually now.
  671. FPackageIndex OutermostLinkerIndex = import.OuterIndex;
  672. for (FPackageIndex LinkerIndex = import.OuterIndex; !LinkerIndex.IsNull(); )
  673. {
  674. OutermostLinkerIndex = LinkerIndex;
  675. LinkerIndex = DependencyData.ImpExp(LinkerIndex).OuterIndex;
  676. }
  677. check(!OutermostLinkerIndex.IsNull());
  678. DependentPackageName = DependencyData.ImpExp(OutermostLinkerIndex).ObjectName;
  679. }
  680. if (DependentPackageName == NAME_None && import.ClassName == NAME_Package)
  681. {
  682. DependentPackageName = import.ObjectName;
  683. }
  684. if (DependentPackageName != NAME_None && DependentPackageName != LinkerName)
  685. {
  686. HardDependentPackages.Add(DependentPackageName);
  687. }
  688. if (import.ClassPackage != NAME_None && import.ClassPackage != LinkerName)
  689. {
  690. HardDependentPackages.Add(import.ClassPackage);
  691. }
  692. }
  693. if (HardDependentPackages.Num())
  694. {
  695. ECB_LOG(Display, TEXT("----------FPackageReader::ReadDependencyData-----------------"));
  696. ECB_LOG(Display, TEXT("\tPackages referenced by %s:"), *LinkerName.ToString());
  697. int32 i = 0;
  698. for (const FName& Dependent : HardDependentPackages)
  699. {
  700. ECB_LOG(Display, TEXT("\t\t%d) %s"), i, *Dependent.ToString());
  701. i++;
  702. }
  703. }
  704. // Get SoftReferences
  705. {
  706. ECB_LOG(Display, TEXT("----------FPackageReader::GetSoftReferences-----------------"));
  707. OutAssetData.SoftReferencesList.Append(DependencyData.SoftPackageReferenceList);
  708. int32 SoftIdx = 0;
  709. for (const FName& SoftPackageName : OutAssetData.SoftReferencesList)
  710. {
  711. ECB_LOG(Display, TEXT("\t\t%d) %s"), SoftIdx, *SoftPackageName.ToString());
  712. SoftIdx++;
  713. }
  714. }
  715. return true;
  716. }
  717. bool FExtPackageReader::ReadThumbnail(FObjectThumbnail& OutThumbnail)
  718. {
  719. if (PackageFileSummary.ThumbnailTableOffset > 0)
  720. {
  721. // Seek the the part of the file where the thumbnail table lives
  722. Seek(PackageFileSummary.ThumbnailTableOffset);
  723. // Load the thumbnail count
  724. int32 ThumbnailCount = 0;
  725. *this << ThumbnailCount;
  726. // Load the names and file offsets for the thumbnails in this package
  727. if (ThumbnailCount > 0)
  728. {
  729. FString ObjectClassName;
  730. *this << ObjectClassName;
  731. FString ObjectPathWithoutPackageName;
  732. *this << ObjectPathWithoutPackageName;
  733. // File offset to image data
  734. int32 FileOffset = 0;
  735. *this << FileOffset;
  736. if (FileOffset > 0)
  737. {
  738. Seek(FileOffset);
  739. // Load the image data
  740. OutThumbnail.Serialize(*this);
  741. return true;
  742. }
  743. }
  744. }
  745. return false;
  746. }
  747. bool FExtPackageReader::ReadAssetRegistryDataIfCookedPackage(TArray<FAssetData*>& AssetDataList, TArray<FString>& CookedPackageNamesWithoutAssetData)
  748. {
  749. if (!!(GetPackageFlags() & PKG_FilterEditorOnly))
  750. {
  751. const FString PackageName = FPackageName::FilenameToLongPackageName(PackageFilename);
  752. bool bFoundAtLeastOneAsset = false;
  753. // If the packaged is saved with the right version we have the information
  754. // which of the objects in the export map as the asset.
  755. // Otherwise we need to store a temp minimal data and then force load the asset
  756. // to re-generate its registry data
  757. if (UEVer() >= VER_UE4_COOKED_ASSETS_IN_EDITOR_SUPPORT)
  758. {
  759. const FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
  760. SerializeNameMap();
  761. SerializeImportMap();
  762. SerializeExportMap();
  763. for (FObjectExport& Export : ExportMap)
  764. {
  765. if (Export.bIsAsset)
  766. {
  767. // We need to get the class name from the import/export maps
  768. FString ObjectClassName;
  769. if (Export.ClassIndex.IsNull())
  770. {
  771. ObjectClassName = UClass::StaticClass()->GetPathName();
  772. }
  773. else if (Export.ClassIndex.IsExport())
  774. {
  775. const FObjectExport& ClassExport = ExportMap[Export.ClassIndex.ToExport()];
  776. ObjectClassName = PackageName;
  777. ObjectClassName += '.';
  778. ClassExport.ObjectName.AppendString(ObjectClassName);
  779. }
  780. else if (Export.ClassIndex.IsImport())
  781. {
  782. const FObjectImport& ClassImport = ImportMap[Export.ClassIndex.ToImport()];
  783. const FObjectImport& ClassPackageImport = ImportMap[ClassImport.OuterIndex.ToImport()];
  784. ClassPackageImport.ObjectName.AppendString(ObjectClassName);
  785. ObjectClassName += '.';
  786. ClassImport.ObjectName.AppendString(ObjectClassName);
  787. }
  788. AssetDataList.Add(new FAssetData(FName(*PackageName), FName(*PackagePath), Export.ObjectName, FTopLevelAssetPath(ObjectClassName), FAssetDataTagMap(), TArray<int32>(), GetPackageFlags()));
  789. bFoundAtLeastOneAsset = true;
  790. }
  791. }
  792. }
  793. if (!bFoundAtLeastOneAsset)
  794. {
  795. CookedPackageNamesWithoutAssetData.Add(PackageName);
  796. }
  797. return true;
  798. }
  799. return false;
  800. }
  801. bool FExtPackageReader::ReadDependencyData(FExtPackageDependencyData& OutDependencyData)
  802. {
  803. OutDependencyData.PackageName = FName(*FPackageName::FilenameToLongPackageName(PackageFilename));
  804. OutDependencyData.PackageData.DiskSize = PackageFileSize;
  805. PRAGMA_DISABLE_DEPRECATION_WARNINGS
  806. OutDependencyData.PackageData.PackageGuid = PackageFileSummary.Guid;
  807. PRAGMA_ENABLE_DEPRECATION_WARNINGS
  808. SerializeNameMap();
  809. SerializeImportMap();
  810. SerializeSoftPackageReferenceList(OutDependencyData.SoftPackageReferenceList);
  811. SerializeSearchableNamesMap(OutDependencyData);
  812. return true;
  813. }
  814. bool FExtPackageReader::SerializeNameMap()
  815. {
  816. if( PackageFileSummary.NameCount > 0 )
  817. {
  818. if (!StartSerializeSection(PackageFileSummary.NameOffset))
  819. {
  820. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeNameMapInvalidNameOffset", PackageFilename);
  821. return false;
  822. }
  823. const int MinSizePerNameEntry = 1;
  824. if (PackageFileSize < Tell() + PackageFileSummary.NameCount * MinSizePerNameEntry)
  825. {
  826. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeNameMapInvalidNameCount", PackageFilename);
  827. return false;
  828. }
  829. for ( int32 NameMapIdx = 0; NameMapIdx < PackageFileSummary.NameCount; ++NameMapIdx )
  830. {
  831. // Read the name entry from the file.
  832. FNameEntrySerialized NameEntry(ENAME_LinkerConstructor);
  833. *this << NameEntry;
  834. if (IsError())
  835. {
  836. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeNameMapInvalidName", PackageFilename);
  837. return false;
  838. }
  839. NameMap.Add(FName(NameEntry));
  840. }
  841. }
  842. return true;
  843. }
  844. bool FExtPackageReader::SerializeImportMap()
  845. {
  846. if (ImportMap.Num() > 0)
  847. {
  848. return true;
  849. }
  850. if (PackageFileSummary.ImportCount > 0)
  851. {
  852. if (!StartSerializeSection(PackageFileSummary.ImportOffset))
  853. {
  854. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeImportMapInvalidImportOffset", PackageFilename);
  855. return false;
  856. }
  857. const int MinSizePerImport = 1;
  858. if (PackageFileSize < Tell() + PackageFileSummary.ImportCount * MinSizePerImport)
  859. {
  860. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeImportMapInvalidImportCount", PackageFilename);
  861. return false;
  862. }
  863. ImportMap.Reserve(PackageFileSummary.ImportCount);
  864. for (int32 ImportMapIdx = 0; ImportMapIdx < PackageFileSummary.ImportCount; ++ImportMapIdx)
  865. {
  866. *this << ImportMap.Emplace_GetRef();
  867. if (IsError())
  868. {
  869. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeImportMapInvalidImport", PackageFilename);
  870. ImportMap.Reset();
  871. return false;
  872. }
  873. }
  874. }
  875. return true;
  876. }
  877. static FName CoreUObjectPackageName(TEXT("/Script/CoreUObject"));
  878. static FName ScriptStructName(TEXT("ScriptStruct"));
  879. bool FExtPackageReader::SerializeImportedClasses(const TArray<FObjectImport>& InImportMap, TArray<FName>& OutClassNames)
  880. {
  881. OutClassNames.Reset();
  882. TSet<int32> ClassImportIndices;
  883. if (PackageFileSummary.ExportCount > 0)
  884. {
  885. if (!StartSerializeSection(PackageFileSummary.ExportOffset))
  886. {
  887. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeExportMapInvalidExportOffset", PackageFilename);
  888. return false;
  889. }
  890. const int MinSizePerExport = 1;
  891. if (PackageFileSize < Tell() + PackageFileSummary.ExportCount * MinSizePerExport)
  892. {
  893. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeExportMapInvalidExportCount", PackageFilename);
  894. return false;
  895. }
  896. FObjectExport ExportBuffer;
  897. for (int32 ExportMapIdx = 0; ExportMapIdx < PackageFileSummary.ExportCount; ++ExportMapIdx)
  898. {
  899. *this << ExportBuffer;
  900. if (IsError())
  901. {
  902. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeExportMapInvalidExport", PackageFilename);
  903. return false;
  904. }
  905. if (ExportBuffer.ClassIndex.IsImport())
  906. {
  907. ClassImportIndices.Add(ExportBuffer.ClassIndex.ToImport());
  908. }
  909. }
  910. }
  911. // Any imports of types UScriptStruct are an imported struct and need to be added to ImportedClasses
  912. // This covers e.g. DataTable, which has a RowStruct pointer that it uses in its native serialization to
  913. // serialize data into its rows
  914. // TODO: Projects may create their own ScriptStruct subclass, and if they use one of these subclasses
  915. // as a serialized-external-struct-pointer then we will miss it. In a future implementation we will
  916. // change the PackageReader to report all imports, and allow the AssetRegistry to decide which ones
  917. // are classes based on its class database.
  918. for (int32 ImportIndex = 0; ImportIndex < InImportMap.Num(); ++ImportIndex)
  919. {
  920. const FObjectImport& ObjectImport = InImportMap[ImportIndex];
  921. if (ObjectImport.ClassPackage == CoreUObjectPackageName && ObjectImport.ClassName == ScriptStructName)
  922. {
  923. ClassImportIndices.Add(ImportIndex);
  924. }
  925. }
  926. TArray<FName, TInlineAllocator<5>> ParentChain;
  927. FNameBuilder ClassObjectPath;
  928. for (int32 ClassImportIndex : ClassImportIndices)
  929. {
  930. ParentChain.Reset();
  931. ClassObjectPath.Reset();
  932. if (!InImportMap.IsValidIndex(ClassImportIndex))
  933. {
  934. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeImportedClassesInvalidClassIndex", PackageFilename);
  935. return false;
  936. }
  937. bool bParentChainComplete = false;
  938. int32 CurrentParentIndex = ClassImportIndex;
  939. for (;;)
  940. {
  941. const FObjectImport& ObjectImport = InImportMap[CurrentParentIndex];
  942. ParentChain.Add(ObjectImport.ObjectName);
  943. if (ObjectImport.OuterIndex.IsImport())
  944. {
  945. CurrentParentIndex = ObjectImport.OuterIndex.ToImport();
  946. if (!InImportMap.IsValidIndex(CurrentParentIndex))
  947. {
  948. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeImportedClassesInvalidImportInParentChain",
  949. PackageFilename);
  950. return false;
  951. }
  952. }
  953. else if (ObjectImport.OuterIndex.IsNull())
  954. {
  955. bParentChainComplete = true;
  956. break;
  957. }
  958. else
  959. {
  960. check(ObjectImport.OuterIndex.IsExport());
  961. // Ignore classes in an external package but with an object in this package as one of their outers;
  962. // We do not need to handle that case yet for Import Classes, and we would have to make this
  963. // loop more complex (searching in both ExportMap and ImportMap) to do so
  964. break;
  965. }
  966. }
  967. if (bParentChainComplete)
  968. {
  969. int32 NumTokens = ParentChain.Num();
  970. check(NumTokens >= 1);
  971. const TCHAR Delimiters[] = { '.', SUBOBJECT_DELIMITER_CHAR, '.' };
  972. int32 DelimiterIndex = 0;
  973. ParentChain[NumTokens - 1].AppendString(ClassObjectPath);
  974. for (int32 TokenIndex = NumTokens - 2; TokenIndex >= 0; --TokenIndex)
  975. {
  976. ClassObjectPath << Delimiters[DelimiterIndex];
  977. DelimiterIndex = FMath::Min(DelimiterIndex + 1, static_cast<int32>(UE_ARRAY_COUNT(Delimiters)) - 1);
  978. ParentChain[TokenIndex].AppendString(ClassObjectPath);
  979. }
  980. OutClassNames.Emplace(ClassObjectPath);
  981. }
  982. }
  983. OutClassNames.Sort(FNameLexicalLess());
  984. return true;
  985. }
  986. bool FExtPackageReader::SerializeExportMap()
  987. {
  988. if (ExportMap.Num() > 0)
  989. {
  990. return true;
  991. }
  992. if (PackageFileSummary.ExportCount > 0)
  993. {
  994. if (!StartSerializeSection(PackageFileSummary.ExportOffset))
  995. {
  996. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeExportMapInvalidExportOffset", PackageFilename);
  997. return false;
  998. }
  999. const int MinSizePerExport = 1;
  1000. if (PackageFileSize < Tell() + PackageFileSummary.ExportCount * MinSizePerExport)
  1001. {
  1002. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeExportMapInvalidExportCount", PackageFilename);
  1003. return false;
  1004. }
  1005. ExportMap.Reserve(PackageFileSummary.ExportCount);
  1006. for (int32 ExportMapIdx = 0; ExportMapIdx < PackageFileSummary.ExportCount; ++ExportMapIdx)
  1007. {
  1008. *this << ExportMap.Emplace_GetRef();
  1009. if (IsError())
  1010. {
  1011. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeExportMapInvalidExport", PackageFilename);
  1012. ExportMap.Reset();
  1013. return false;
  1014. }
  1015. }
  1016. }
  1017. return true;
  1018. }
  1019. bool FExtPackageReader::SerializeSoftPackageReferenceList(TArray<FName>& OutSoftPackageReferenceList)
  1020. {
  1021. if (UEVer() >= VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP && PackageFileSummary.SoftPackageReferencesOffset > 0 && PackageFileSummary.SoftPackageReferencesCount > 0)
  1022. {
  1023. if (!StartSerializeSection(PackageFileSummary.SoftPackageReferencesOffset))
  1024. {
  1025. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeSoftPackageReferenceListInvalidReferencesOffset", PackageFilename);
  1026. return false;
  1027. }
  1028. const int MinSizePerSoftPackageReference = 1;
  1029. if (PackageFileSize < Tell() + PackageFileSummary.SoftPackageReferencesCount * MinSizePerSoftPackageReference)
  1030. {
  1031. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeSoftPackageReferenceListInvalidReferencesCount", PackageFilename);
  1032. return false;
  1033. }
  1034. if (UEVer() < VER_UE4_ADDED_SOFT_OBJECT_PATH)
  1035. {
  1036. for (int32 ReferenceIdx = 0; ReferenceIdx < PackageFileSummary.SoftPackageReferencesCount; ++ReferenceIdx)
  1037. {
  1038. FString PackageName;
  1039. *this << PackageName;
  1040. if (IsError())
  1041. {
  1042. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeSoftPackageReferenceListInvalidReferencePreSoftObjectPath", PackageFilename);
  1043. return false;
  1044. }
  1045. if (UEVer() < VER_UE4_KEEP_ONLY_PACKAGE_NAMES_IN_STRING_ASSET_REFERENCES_MAP)
  1046. {
  1047. PackageName = FPackageName::GetNormalizedObjectPath(PackageName);
  1048. if (!PackageName.IsEmpty())
  1049. {
  1050. PackageName = FPackageName::ObjectPathToPackageName(PackageName);
  1051. }
  1052. }
  1053. OutSoftPackageReferenceList.Add(FName(*PackageName));
  1054. }
  1055. }
  1056. else
  1057. {
  1058. for (int32 ReferenceIdx = 0; ReferenceIdx < PackageFileSummary.SoftPackageReferencesCount; ++ReferenceIdx)
  1059. {
  1060. FName PackageName;
  1061. *this << PackageName;
  1062. if (IsError())
  1063. {
  1064. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeSoftPackageReferenceListInvalidReference", PackageFilename);
  1065. return false;
  1066. }
  1067. OutSoftPackageReferenceList.Add(PackageName);
  1068. }
  1069. }
  1070. }
  1071. return true;
  1072. }
  1073. bool FExtPackageReader::SerializeSearchableNamesMap(FExtPackageDependencyData& OutDependencyData)
  1074. {
  1075. if (UEVer() >= VER_UE4_ADDED_SEARCHABLE_NAMES && PackageFileSummary.SearchableNamesOffset > 0)
  1076. {
  1077. if (!StartSerializeSection(PackageFileSummary.SearchableNamesOffset))
  1078. {
  1079. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeSearchableNamesMapInvalidOffset", PackageFilename);
  1080. return false;
  1081. }
  1082. OutDependencyData.SerializeSearchableNamesMap(*this);
  1083. if (IsError())
  1084. {
  1085. ECB_PACKAGEREADER_CORRUPTPACKAGE_WARNING("SerializeSearchableNamesMapInvalidSearchableNamesMap", PackageFilename);
  1086. return false;
  1087. }
  1088. }
  1089. return true;
  1090. }
  1091. void FExtPackageReader::Serialize( void* V, int64 Length )
  1092. {
  1093. check(Loader);
  1094. Loader->Serialize( V, Length );
  1095. }
  1096. bool FExtPackageReader::Precache( int64 PrecacheOffset, int64 PrecacheSize )
  1097. {
  1098. check(Loader);
  1099. return Loader->Precache( PrecacheOffset, PrecacheSize );
  1100. }
  1101. void FExtPackageReader::Seek( int64 InPos )
  1102. {
  1103. check(Loader);
  1104. Loader->Seek( InPos );
  1105. }
  1106. int64 FExtPackageReader::Tell()
  1107. {
  1108. check(Loader);
  1109. return Loader->Tell();
  1110. }
  1111. int64 FExtPackageReader::TotalSize()
  1112. {
  1113. check(Loader);
  1114. return Loader->TotalSize();
  1115. }
  1116. uint32 FExtPackageReader::GetPackageFlags() const
  1117. {
  1118. return PackageFileSummary.GetPackageFlags();
  1119. }
  1120. const FPackageFileSummary& FExtPackageReader::GetPackageFileSummary() const
  1121. {
  1122. return PackageFileSummary;
  1123. }
  1124. int32 FExtPackageReader::GetSoftPackageReferencesCount() const
  1125. {
  1126. if (UEVer() >= VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP && PackageFileSummary.SoftPackageReferencesOffset > 0 && PackageFileSummary.SoftPackageReferencesCount > 0)
  1127. {
  1128. return PackageFileSummary.SoftPackageReferencesCount;
  1129. }
  1130. return 0;
  1131. }
  1132. FArchive& FExtPackageReader::operator<<( FName& Name )
  1133. {
  1134. check(Loader);
  1135. int32 NameIndex;
  1136. FArchive& Ar = *this;
  1137. Ar << NameIndex;
  1138. if( !NameMap.IsValidIndex(NameIndex) )
  1139. {
  1140. ECB_LOG(Fatal, TEXT("Bad name index %i/%i"), NameIndex, NameMap.Num() );
  1141. }
  1142. // if the name wasn't loaded (because it wasn't valid in this context)
  1143. if (NameMap[NameIndex] == NAME_None)
  1144. {
  1145. int32 TempNumber;
  1146. Ar << TempNumber;
  1147. Name = NAME_None;
  1148. }
  1149. else
  1150. {
  1151. int32 Number;
  1152. Ar << Number;
  1153. // simply create the name from the NameMap's name and the serialized instance number
  1154. Name = FName(NameMap[NameIndex], Number);
  1155. }
  1156. return *this;
  1157. }
  1158. FName FExtPackageDependencyData::GetImportPackageName(int32 ImportIndex)
  1159. {
  1160. FName Result;
  1161. for (FPackageIndex LinkerIndex = FPackageIndex::FromImport(ImportIndex); !LinkerIndex.IsNull();)
  1162. {
  1163. FObjectResource* Resource = &ImpExp(LinkerIndex);
  1164. LinkerIndex = Resource->OuterIndex;
  1165. if (LinkerIndex.IsNull())
  1166. {
  1167. Result = Resource->ObjectName;
  1168. }
  1169. }
  1170. return Result;
  1171. }