@@ -1051,107 +1051,157 @@ void SharedCacheView::LogSecondaryFileName(std::string secondaryFileName)
10511051 GetParentView ()->StoreMetadata (VIEW_METADATA_KEY , GetMetadata ());
10521052}
10531053
1054- std::optional<std::string> SharedCacheView::GetPrimaryFilePath ()
1054+
1055+ std::string SharedCacheView::StorePrimaryProjectFile (ProjectFile* projectFile)
10551056{
1056- auto viewFile = GetFile ();
1057- auto databaseDir = std::filesystem::path (viewFile->GetFilename ()).parent_path ().string ();
1058- auto currentProjectFile = viewFile->GetProjectFile ();
1059- Ref<Project> project = nullptr ;
1060- if (currentProjectFile)
1061- project = currentProjectFile->GetProject ();
1057+ SetPrimaryFileLocation (projectFile->GetPathInProject (), projectFile->GetName ());
1058+ return projectFile->GetPathOnDisk ();
1059+ }
10621060
1063- auto storePrimaryProjectFile = [&](ProjectFile* projectFile) -> std::string {
1064- SetPrimaryFileLocation (projectFile->GetPathInProject (), projectFile->GetName ());
1065- return projectFile->GetPathOnDisk ();
1066- };
10671061
1068- auto storePrimaryFilePath = [&](const std::string& path) {
1069- if (project)
1062+ void SharedCacheView::StorePrimaryFilePath (const std::string& path, Project* project, const std::string& databaseDir)
1063+ {
1064+ if (project)
1065+ {
1066+ if (auto projectFile = project->GetFileByPathOnDisk (path))
10701067 {
1071- if (auto projectFile = project->GetFileByPathOnDisk (path))
1072- {
1073- SetPrimaryFileLocation (projectFile->GetPathInProject (), projectFile->GetName ());
1074- return ;
1075- }
1076-
1077- m_logger->LogWarnF (
1078- " Primary shared cache file '{}' is outside the current project. Add the shared cache files to the project to avoid selecting them on future opens." ,
1079- path);
1080- SetPrimaryFileName (BaseFileName (path));
1068+ SetPrimaryFileLocation (projectFile->GetPathInProject (), projectFile->GetName ());
10811069 return ;
10821070 }
10831071
1084- SetPrimaryFileLocation (PathRelativeTo (path, databaseDir), BaseFileName (path));
1085- };
1072+ m_logger->LogWarnF (
1073+ " Primary shared cache file '{}' is outside the current project. Add the shared cache files to the project to avoid selecting them on future opens." ,
1074+ path);
1075+ SetPrimaryFileName (BaseFileName (path));
1076+ return ;
1077+ }
10861078
1087- auto resolveProjectFilePath = [&](const std::string& projectPath) -> std::optional<std::string> {
1088- if (!project || projectPath.empty ())
1089- return std::nullopt ;
1079+ SetPrimaryFileLocation (PathRelativeTo (path, databaseDir), BaseFileName (path));
1080+ }
10901081
1091- try
1082+
1083+ std::optional<std::string> SharedCacheView::ResolveProjectFilePath (Project* project, const std::string& projectPath)
1084+ {
1085+ if (!project || projectPath.empty ())
1086+ return std::nullopt ;
1087+
1088+ try
1089+ {
1090+ auto matches = project->GetFilesByPathInProject (projectPath);
1091+ if (matches.size () > 1 )
10921092 {
1093- auto matches = project->GetFilesByPathInProject (projectPath);
1094- if (matches.size () > 1 )
1095- {
1096- m_logger->LogErrorF (
1097- " Multiple project files match primary shared cache path '{}'. Provide loader.dsc.primaryFilePath with an unambiguous project path." ,
1098- projectPath);
1099- return std::string ();
1100- }
1101- if (matches.size () == 1 )
1102- return storePrimaryProjectFile (matches[0 ]);
1093+ m_logger->LogErrorF (
1094+ " Multiple project files match primary shared cache path '{}'. Provide loader.dsc.primaryFilePath with an unambiguous project path." ,
1095+ projectPath);
1096+ return std::string ();
11031097 }
1104- catch (const std::exception& e)
1098+ if (matches.size () == 1 )
1099+ return StorePrimaryProjectFile (matches[0 ]);
1100+ }
1101+ catch (const std::exception& e)
1102+ {
1103+ m_logger->LogWarnForExceptionF (e, " Failed to resolve primary shared cache project path '{}': {}" , projectPath,
1104+ e.what ());
1105+ }
1106+
1107+ return std::nullopt ;
1108+ }
1109+
1110+
1111+ std::optional<std::string> SharedCacheView::ResolveUniqueProjectFileName (Project* project)
1112+ {
1113+ if (!project || m_primaryFileName.empty ())
1114+ return std::nullopt ;
1115+
1116+ std::vector<Ref<ProjectFile>> matches;
1117+ for (const auto & projectFile : project->GetFiles ())
1118+ if (projectFile->GetName () == m_primaryFileName)
1119+ matches.push_back (projectFile);
1120+
1121+ if (matches.empty ())
1122+ return std::nullopt ;
1123+
1124+ if (matches.size () > 1 )
1125+ {
1126+ std::string paths;
1127+ for (const auto & match : matches)
11051128 {
1106- m_logger->LogWarnForExceptionF (e, " Failed to resolve primary shared cache project path '{}': {}" , projectPath,
1107- e.what ());
1129+ if (!paths.empty ())
1130+ paths += " , " ;
1131+ paths += match->GetPathInProject ();
11081132 }
1133+ m_logger->LogErrorF (
1134+ " Multiple project files are named '{}': {}. Provide loader.dsc.primaryFilePath with the project path to the correct primary shared cache file." ,
1135+ m_primaryFileName, paths);
1136+ return std::string ();
1137+ }
1138+
1139+ return StorePrimaryProjectFile (matches[0 ]);
1140+ }
11091141
1142+
1143+ std::optional<std::string> SharedCacheView::ResolveMetadataPrimaryFilePath (Project* project, const std::string& databaseDir)
1144+ {
1145+ if (m_primaryFilePath.empty ())
11101146 return std::nullopt ;
1111- };
11121147
1113- auto resolveUniqueProjectFileName = [&]() -> std::optional<std::string> {
1114- if (!project || m_primaryFileName.empty ())
1115- return std::nullopt ;
1148+ if (project)
1149+ return ResolveProjectFilePath (project, m_primaryFilePath);
11161150
1117- std::vector<Ref<ProjectFile>> matches;
1118- for (const auto & projectFile : project->GetFiles ())
1119- if (projectFile->GetName () == m_primaryFileName)
1120- matches.push_back (projectFile);
1151+ auto path = ResolveRelativePath (m_primaryFilePath, databaseDir);
1152+ if (IsUsablePrimaryCachePath (path))
1153+ return path;
1154+ return std::nullopt ;
1155+ }
11211156
1122- if (matches.empty ())
1123- return std::nullopt ;
11241157
1125- if (matches.size () > 1 )
1126- {
1127- std::string paths;
1128- for (const auto & match : matches)
1129- {
1130- if (!paths.empty ())
1131- paths += " , " ;
1132- paths += match->GetPathInProject ();
1133- }
1134- m_logger->LogErrorF (
1135- " Multiple project files are named '{}': {}. Provide loader.dsc.primaryFilePath with the project path to the correct primary shared cache file." ,
1136- m_primaryFileName, paths);
1137- return std::string ();
1138- }
1158+ std::optional<std::string> SharedCacheView::PromptForPrimaryFile ()
1159+ {
1160+ if (!IsUIEnabled ())
1161+ {
1162+ m_logger->LogErrorF (
1163+ " Primary shared cache file '{}' could not be resolved. Provide loader.dsc.primaryFilePath when loading this database headlessly." ,
1164+ m_primaryFileName);
1165+ return std::nullopt ;
1166+ }
11391167
1140- return storePrimaryProjectFile (matches[0 ]);
1141- };
1168+ ShowMessageBox (" Select Primary Shared Cache File" ,
1169+ " Binary Ninja needs the original primary dyld shared cache file to reopen this database. "
1170+ " Select the primary dyld_shared_cache file, not another .bndb database." , OKButtonSet, InformationIcon);
11421171
1143- auto resolveMetadataPrimaryFilePath = [&]() -> std::optional<std::string> {
1144- if (m_primaryFilePath.empty ())
1145- return std::nullopt ;
1172+ std::string newPrimaryFilePath;
1173+ std::string prompt = " Select primary shared cache file" ;
1174+ if (!m_primaryFileName.empty ())
1175+ prompt += " '" + m_primaryFileName + " '" ;
1176+ if (!GetOpenFileNameInput (newPrimaryFilePath, prompt))
1177+ return std::nullopt ;
11461178
1147- if (project)
1148- return resolveProjectFilePath (m_primaryFilePath);
1179+ if (IsBndbPath (newPrimaryFilePath))
1180+ {
1181+ m_logger->LogAlertF (
1182+ " Selected primary shared cache path is a Binary Ninja database, not a dyld shared cache file: '{}'" ,
1183+ newPrimaryFilePath);
1184+ return std::nullopt ;
1185+ }
11491186
1150- auto path = ResolveRelativePath (m_primaryFilePath, databaseDir);
1151- if ( IsUsablePrimaryCachePath (path))
1152- return path;
1187+ if (! IsUsablePrimaryCachePath (newPrimaryFilePath))
1188+ {
1189+ m_logger-> LogAlertF ( " Selected primary shared cache path is not a usable file: '{}' " , newPrimaryFilePath) ;
11531190 return std::nullopt ;
1154- };
1191+ }
1192+
1193+ return newPrimaryFilePath;
1194+ }
1195+
1196+
1197+ std::optional<std::string> SharedCacheView::GetPrimaryFilePath ()
1198+ {
1199+ auto viewFile = GetFile ();
1200+ auto databaseDir = std::filesystem::path (viewFile->GetFilename ()).parent_path ().string ();
1201+ auto currentProjectFile = viewFile->GetProjectFile ();
1202+ Ref<Project> project = nullptr ;
1203+ if (currentProjectFile)
1204+ project = currentProjectFile->GetProject ();
11551205
11561206 auto settings = GetLoadSettings (GetTypeName ());
11571207 if (settings && settings->Contains (" loader.dsc.primaryFilePath" ))
@@ -1162,7 +1212,7 @@ std::optional<std::string> SharedCacheView::GetPrimaryFilePath()
11621212 settings->Reset (" loader.dsc.primaryFilePath" , this , SettingsResourceScope);
11631213 if (project)
11641214 {
1165- auto projectPathResult = resolveProjectFilePath ( configuredPrimaryFilePath);
1215+ auto projectPathResult = ResolveProjectFilePath (project, configuredPrimaryFilePath);
11661216 if (projectPathResult && projectPathResult->empty ())
11671217 return std::nullopt ;
11681218 if (projectPathResult)
@@ -1185,44 +1235,7 @@ std::optional<std::string> SharedCacheView::GetPrimaryFilePath()
11851235 }
11861236 }
11871237
1188- auto promptForPrimaryFile = [&]() -> std::optional<std::string> {
1189- if (!IsUIEnabled ())
1190- {
1191- m_logger->LogErrorF (
1192- " Primary shared cache file '{}' could not be resolved. Provide loader.dsc.primaryFilePath when loading this database headlessly." ,
1193- m_primaryFileName);
1194- return std::nullopt ;
1195- }
1196-
1197- ShowMessageBox (" Select Primary Shared Cache File" ,
1198- " Binary Ninja needs the original primary dyld shared cache file to reopen this database. "
1199- " Select the primary dyld_shared_cache file, not another .bndb database." , OKButtonSet, InformationIcon);
1200-
1201- std::string newPrimaryFilePath;
1202- std::string prompt = " Select primary shared cache file" ;
1203- if (!m_primaryFileName.empty ())
1204- prompt += " '" + m_primaryFileName + " '" ;
1205- if (!GetOpenFileNameInput (newPrimaryFilePath, prompt))
1206- return std::nullopt ;
1207-
1208- if (IsBndbPath (newPrimaryFilePath))
1209- {
1210- m_logger->LogAlertF (
1211- " Selected primary shared cache path is a Binary Ninja database, not a dyld shared cache file: '{}'" ,
1212- newPrimaryFilePath);
1213- return std::nullopt ;
1214- }
1215-
1216- if (!IsUsablePrimaryCachePath (newPrimaryFilePath))
1217- {
1218- m_logger->LogAlertF (" Selected primary shared cache path is not a usable file: '{}'" , newPrimaryFilePath);
1219- return std::nullopt ;
1220- }
1221-
1222- return newPrimaryFilePath;
1223- };
1224-
1225- if (auto metadataPrimaryPath = resolveMetadataPrimaryFilePath ())
1238+ if (auto metadataPrimaryPath = ResolveMetadataPrimaryFilePath (project, databaseDir))
12261239 {
12271240 if (metadataPrimaryPath->empty ())
12281241 return std::nullopt ;
@@ -1254,7 +1267,7 @@ std::optional<std::string> SharedCacheView::GetPrimaryFilePath()
12541267
12551268 if (!IsUsablePrimaryCachePath (primaryFilePath))
12561269 {
1257- auto promptedPrimaryFilePath = promptForPrimaryFile ();
1270+ auto promptedPrimaryFilePath = PromptForPrimaryFile ();
12581271 if (!promptedPrimaryFilePath)
12591272 return std::nullopt ;
12601273 primaryFilePath = *promptedPrimaryFilePath;
@@ -1268,7 +1281,7 @@ std::optional<std::string> SharedCacheView::GetPrimaryFilePath()
12681281 return std::nullopt ;
12691282 }
12701283
1271- storePrimaryFilePath (primaryFilePath);
1284+ StorePrimaryFilePath (primaryFilePath, project, databaseDir );
12721285 }
12731286
12741287 // 3. If we are not in a project, the filesystem path is ready to use.
@@ -1295,10 +1308,10 @@ std::optional<std::string> SharedCacheView::GetPrimaryFilePath()
12951308 // We are looking for the file with file name we stored in metadata.
12961309 if (pj->GetName () != m_primaryFileName)
12971310 continue ;
1298- return storePrimaryProjectFile (pj);
1311+ return StorePrimaryProjectFile (pj);
12991312 }
13001313
1301- if (auto uniqueProjectPath = resolveUniqueProjectFileName ( ))
1314+ if (auto uniqueProjectPath = ResolveUniqueProjectFileName (project ))
13021315 {
13031316 if (uniqueProjectPath->empty ())
13041317 return std::nullopt ;
@@ -1310,7 +1323,7 @@ std::optional<std::string> SharedCacheView::GetPrimaryFilePath()
13101323
13111324 // 6. If automatic project resolution failed, ask the user in UI mode. Headless callers must provide
13121325 // loader.dsc.primaryFilePath or arrange files so one of the automatic resolution paths works.
1313- auto promptedPrimaryFilePath = promptForPrimaryFile ();
1326+ auto promptedPrimaryFilePath = PromptForPrimaryFile ();
13141327 if (!promptedPrimaryFilePath)
13151328 return std::nullopt ;
13161329 std::string newPrimaryFilePath = *promptedPrimaryFilePath;
0 commit comments