//
// Lower Score Panel
//
- String fgColor = WebColors.toString(FG_TOOLTIP_DEFAULT);
+ String fgColor = WebColors.toString(FG_TOOLTIP_DEFAULT, false);
lowerRangePanel = new JPanel(new GridLayout(2, 1));
JLabel lowLabel =
new GHtmlLabel("low");
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java
index 7f8ae726cd..55a7648354 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/options/editor/ColorEditor.java
@@ -88,7 +88,8 @@ public class ColorEditor extends PropertyEditorSupport {
private void updateColor(Color newColor) {
// change the color to a darker value if the color being set is light
- String colorString = WebColors.toString(ColorUtils.contrastForegroundColor(newColor));
+ String colorString =
+ WebColors.toString(ColorUtils.contrastForegroundColor(newColor), false);
previewLabel.setText(
"click");
diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java
index dffbef38a4..a196b96305 100644
--- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java
+++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/ClientUtil.java
@@ -132,6 +132,21 @@ public class ClientUtil {
return rsa;
}
+ /**
+ * Determine if a connected {@link RepositoryServerAdapter} already exists for the specified server.
+ * @param host server name or address
+ * @param port server port, 0 indicates that default port applies.
+ * @return true if connection already exists, else false
+ */
+ public static boolean isConnected(String host, int port) {
+ if (port <= 0) {
+ port = GhidraServerHandle.DEFAULT_PORT;
+ }
+ ServerInfo server = new ServerInfo(host, port);
+ RepositoryServerAdapter rsa = serverHandles.get(server);
+ return rsa != null && rsa.isConnected();
+ }
+
/**
* Eliminate the specified repository server from the connection cache
* @param host host name or IP address
diff --git a/Ghidra/Framework/Gui/src/main/java/ghidra/util/WebColors.java b/Ghidra/Framework/Gui/src/main/java/ghidra/util/WebColors.java
index 2f93bdecab..cb19c04294 100644
--- a/Ghidra/Framework/Gui/src/main/java/ghidra/util/WebColors.java
+++ b/Ghidra/Framework/Gui/src/main/java/ghidra/util/WebColors.java
@@ -23,6 +23,11 @@ import java.util.Map;
* Class for web color support. This class defines many of the colors used by html. This class
* includes methods for converting a color to a string (name or hex value) and for converting
* those strings back to a color.
+ *
+ * Usage Note: Java's HTML rendering engine supports colors in hex form ('#aabb11'). Also, the
+ * engine supports many web color names ('silver'). However, not all web color names defined in
+ * this file are supported. Thus, when specifying HTML colors, do not rely on these web color
+ * names.
*/
public abstract class WebColors {
private static final Map nameToColorMap = new HashMap<>();
@@ -229,7 +234,7 @@ public abstract class WebColors {
}
/**
- * Returns the hex value string for the given color
+ * Returns the hex value string for the given color
* @param color the color
* @return the string
*/
@@ -382,7 +387,7 @@ public abstract class WebColors {
value = value.substring(4, value.length() - 1);
}
- // strip off to comma separated values
+ // strip off to comma separated values
String[] split = value.split(",");
if (split.length != 3) {
return null;
@@ -404,7 +409,7 @@ public abstract class WebColors {
value = value.substring(5, value.length() - 1);
}
- // strip off to comma separated values
+ // strip off to comma separated values
value = value.replaceAll(" ", "");
String[] split = value.split(",");
if (split.length != 4) {
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java
index 7a13516e27..0bb4d082bf 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainFileProxy.java
@@ -23,8 +23,10 @@ import java.util.*;
import javax.swing.Icon;
+import ghidra.framework.client.*;
import ghidra.framework.model.*;
import ghidra.framework.protocol.ghidra.GhidraURL;
+import ghidra.framework.remote.RepositoryItem;
import ghidra.framework.store.ItemCheckoutStatus;
import ghidra.framework.store.Version;
import ghidra.framework.store.db.PackedDatabase;
@@ -114,25 +116,81 @@ public class DomainFileProxy implements DomainFile {
return parentPath + DomainFolder.SEPARATOR + getName();
}
+ private URL getSharedFileURL(URL sharedProjectURL) {
+ try {
+ // Direct URL construction done so that ghidra protocol
+ // extension may be supported
+ String urlStr = sharedProjectURL.toExternalForm();
+ if (urlStr.endsWith("/")) {
+ urlStr = urlStr.substring(0, urlStr.length() - 1);
+ }
+ urlStr += getPathname();
+ return new URL(urlStr);
+ }
+ catch (MalformedURLException e) {
+ // ignore
+ }
+ return null;
+ }
+
+ private URL getSharedFileURL(Properties properties) {
+ if (properties == null) {
+ return null;
+ }
+ String serverName = properties.getProperty(ProjectFileManager.SERVER_NAME);
+ String repoName = properties.getProperty(ProjectFileManager.REPOSITORY_NAME);
+ if (serverName == null || repoName == null) {
+ return null;
+ }
+ int port = Integer.parseInt(properties.getProperty(ProjectFileManager.PORT_NUMBER, "0"));
+
+ if (!ClientUtil.isConnected(serverName, port)) {
+ return null; // avoid initiating a server connection.
+ }
+
+ RepositoryAdapter repository = null;
+ try {
+ RepositoryServerAdapter repositoryServer =
+ ClientUtil.getRepositoryServer(serverName, port);
+ Set repoNames = Set.of(repositoryServer.getRepositoryNames());
+ if (!repoNames.contains(repoName)) {
+ return null; // only consider repos which user has access to
+ }
+ repository = repositoryServer.getRepository(repoName);
+ if (repository == null) {
+ return null;
+ }
+ repository.connect();
+ RepositoryItem item = repository.getItem(parentPath, name);
+ if (item == null || !Objects.equals(item.getFileID(), fileID)) {
+ return null;
+ }
+ ServerInfo serverInfo = repository.getServerInfo();
+ return GhidraURL.makeURL(serverInfo.getServerName(),
+ serverInfo.getPortNumber(), repository.getName(),
+ item.getPathName());
+ }
+ catch (IOException e) {
+ // ignore
+ }
+ finally {
+ if (repository != null) {
+ repository.disconnect();
+ }
+ }
+ return null;
+ }
+
@Override
public URL getSharedProjectURL() {
if (projectLocation != null && version == DomainFile.DEFAULT_VERSION) {
URL projectURL = projectLocation.getURL();
if (GhidraURL.isServerRepositoryURL(projectURL)) {
- try {
- // Direct URL construction done so that ghidra protocol
- // extension may be supported
- String urlStr = projectURL.toExternalForm();
- if (urlStr.endsWith("/")) {
- urlStr = urlStr.substring(0, urlStr.length() - 1);
- }
- urlStr += getPathname();
- return new URL(urlStr);
- }
- catch (MalformedURLException e) {
- // ignore
- }
+ return getSharedFileURL(projectURL);
}
+ Properties properties =
+ ProjectFileManager.readProjectProperties(projectLocation.getProjectDir());
+ return getSharedFileURL(properties);
}
return null;
}
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java
index d19a74468c..0e43d51276 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/ProjectFileManager.java
@@ -49,10 +49,11 @@ public class ProjectFileManager implements ProjectData {
private static final String TEST_REPOSITORY_PATH = System.getProperty("Repository");
- private static final String SERVER_NAME = "SERVER";
- private static final String PORT_NUMBER = "PORT_NUMBER";
- private static final String REPOSITORY_NAME = "REPOSITORY_NAME";
- private static final String OWNER = "OWNER";
+ public static final String SERVER_NAME = "SERVER";
+ public static final String PORT_NUMBER = "PORT_NUMBER";
+ public static final String REPOSITORY_NAME = "REPOSITORY_NAME";
+ public static final String OWNER = "OWNER";
+
private static final String PROPERTY_FILENAME = "project";
private static final int USER_DATA_RECONCILE_DELAY_MS = 5 * 60 * 1000; // 5-minutes
@@ -204,6 +205,38 @@ public class ProjectFileManager implements ProjectData {
}
}
+ /**
+ * Read the contents of the project properties file to include the following values if relavent:
+ * {@value #OWNER}, {@value #SERVER_NAME}, {@value #REPOSITORY_NAME}, {@value #PORT_NUMBER}
+ * @param projectDir project directory (*.rep)
+ * @return project properties or null if invalid project directory specified
+ */
+ public static Properties readProjectProperties(File projectDir) {
+ try {
+ PropertyFile pf =
+ new PropertyFile(projectDir, PROPERTY_FILENAME, "/", PROPERTY_FILENAME);
+ if (pf.exists()) {
+ Properties properties = new Properties();
+
+ properties.setProperty(OWNER, pf.getString(OWNER, null));
+
+ String serverName = pf.getString(SERVER_NAME, null);
+ String repoName = pf.getString(REPOSITORY_NAME, null);
+ int port = pf.getInt(PORT_NUMBER, 0);
+ if (serverName != null && repoName != null) {
+ properties.setProperty(SERVER_NAME, serverName);
+ properties.setProperty(REPOSITORY_NAME, repoName);
+ properties.setProperty(PORT_NUMBER, Integer.toString(port));
+ }
+ return properties;
+ }
+ }
+ catch (IOException e) {
+ // ignore
+ }
+ return null;
+ }
+
private void init(boolean create, boolean isInWritableProject)
throws IOException, LockException {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
index 594973c4dd..fbf24a611e 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/FileDataTypeManager.java
@@ -22,8 +22,8 @@ import db.DBConstants;
import generic.jar.ResourceFile;
import ghidra.framework.store.db.PackedDBHandle;
import ghidra.framework.store.db.PackedDatabase;
-import ghidra.program.model.lang.CompilerSpec;
-import ghidra.program.model.lang.Language;
+import ghidra.program.model.lang.*;
+import ghidra.program.util.DefaultLanguageService;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.*;
@@ -98,6 +98,54 @@ public class FileDataTypeManager extends StandAloneDataTypeManager
}
}
+ /**
+ * Create a new data-type file archive using the default data organization
+ * @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
+ * @return data-type manager backed by specified packedDbFile
+ * @throws IOException if an IO error occurs
+ */
+ public static FileDataTypeManager createFileArchive(File packedDbfile, LanguageID languageId,
+ CompilerSpecID compilerSpecId)
+ throws LanguageNotFoundException, CompilerSpecNotFoundException, IOException {
+ try {
+ FileDataTypeManager dtm =
+ new FileDataTypeManager(new ResourceFile(packedDbfile), DBConstants.CREATE,
+ TaskMonitor.DUMMY);
+
+ LanguageService languageService = DefaultLanguageService.getLanguageService();
+ Language language = languageService.getLanguage(languageId);
+ CompilerSpec compilerSpec = language.getCompilerSpecByID(compilerSpecId);
+
+ //dtm.setProgramArchitecture()
+ return dtm;
+ }
+ catch (CancelledException e) {
+ throw new AssertException(e); // unexpected without task monitor use
+ }
+ }
+
+ /**
+ * Create a new data-type file archive using the default data organization
+ * @param packedDbfile archive file (filename must end with DataTypeFileManager.SUFFIX)
+ * @return data-type manager backed by specified packedDbFile
+ * @throws IOException if an IO error occurs
+ */
+ public static FileDataTypeManager createFileArchive(File packedDbfile, String languageId,
+ String compilerSpecId) throws IOException {
+ try {
+ FileDataTypeManager dtm =
+ new FileDataTypeManager(new ResourceFile(packedDbfile), DBConstants.CREATE,
+ TaskMonitor.DUMMY);
+
+ //dtm.setProgramArchitecture()
+
+ return dtm;
+ }
+ catch (CancelledException e) {
+ throw new AssertException(e); // unexpected without task monitor use
+ }
+ }
+
/**
* Open an existing data-type file archive using the default data organization.
*