From 81212432a327560317f0fe3522221499b8bbf2bb Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:49:29 -0400 Subject: [PATCH] GP-4970 - Fixed broken help TOC link that points to generated file --- .../src/global/docs/UserAgreement.html | 3 + Ghidra/Features/BSim/build.gradle | 8 +-- Ghidra/Features/Base/build.gradle | 18 +++-- .../Base/src/main/help/help/TOC_Source.xml | 2 +- .../ghidra/app/plugin/core/totd/tips.txt | 6 +- Ghidra/Features/PDB/build.gradle | 2 +- .../PDB/src/main/help/help/TOC_Source.xml | 2 +- .../PDB/src/main/help/help/topics/Pdb/PDB.htm | 4 +- .../java/ghidra/framework/Application.java | 1 + .../Help/src/main/java/help/GHelpBuilder.java | 37 +++++++++- .../main/java/help/GHelpHTMLEditorKit.java | 42 ++++------- .../Help/src/main/java/help/GHelpSet.java | 49 ++++--------- .../src/main/java/help/HelpBuildUtils.java | 72 ++++++++++++++++++- .../main/java/help/JavaHelpFilesBuilder.java | 5 +- .../help/validator/JavaHelpValidator.java | 26 +++---- .../java/help/validator/LinkDatabase.java | 16 ++--- .../GeneratedDirectoryHelpModuleLocation.java | 43 +++++++++++ .../location/HelpModuleCollection.java | 65 +++++++---------- .../location/HelpModuleLocation.java | 1 + gradle/helpProject.gradle | 18 +++-- 20 files changed, 261 insertions(+), 159 deletions(-) create mode 100644 Ghidra/Framework/Help/src/main/java/help/validator/location/GeneratedDirectoryHelpModuleLocation.java diff --git a/Ghidra/Configurations/Public_Release/src/global/docs/UserAgreement.html b/Ghidra/Configurations/Public_Release/src/global/docs/UserAgreement.html index 1285f35cee..7fe98a6e27 100644 --- a/Ghidra/Configurations/Public_Release/src/global/docs/UserAgreement.html +++ b/Ghidra/Configurations/Public_Release/src/global/docs/UserAgreement.html @@ -1,4 +1,7 @@ + + Ghidra User Agreement + diff --git a/Ghidra/Features/BSim/build.gradle b/Ghidra/Features/BSim/build.gradle index f573ad83d9..a7b3909fe9 100755 --- a/Ghidra/Features/BSim/build.gradle +++ b/Ghidra/Features/BSim/build.gradle @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -66,7 +66,7 @@ def installPoint = "../help/help" /** * Build the pdf docs for BSim and place into the '$installPoint' directory. - * A build (ex: 'gradle buildLocalTSSI_Release') will place the pdf in the distribution. + * A build (ex: 'gradle buildLocalPublic_Release') will place the pdf in the distribution. * There is an associated, auto-generated clean task. **/ task buildBSimHelpPdf(type: Exec) { @@ -136,7 +136,7 @@ task buildBSimHelpPdf(type: Exec) { /** * Build the html docs for BSim and place into the '$installPoint' directory. - * A build (ex: 'gradle buildLocalTSSI_Release') will place the html files in the distribution. + * A build (ex: 'gradle buildLocalPublic_Release') will place the html files in the distribution. **/ task buildBSimHelpHtml(type: Exec) { diff --git a/Ghidra/Features/Base/build.gradle b/Ghidra/Features/Base/build.gradle index 92eb4e0297..57fa777292 100644 --- a/Ghidra/Features/Base/build.gradle +++ b/Ghidra/Features/Base/build.gradle @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -140,11 +140,19 @@ tasks.register('generateExtraHelpFiles') { } } -// Base's help includes the file generated by the 'generateExtraHelpFiles' task. Signal that we -// depend on that task and it's output file. -tasks.named('buildHelp') { +tasks.named('buildHelpFiles') { + dependsOn(tasks.named('generateExtraHelpFiles')) inputs.files tasks.named('generateExtraHelpFiles').get().outputs + + doFirst { + // Add the generated help path to the args passed to GHelpBuilder. Add the build dir that + // contains the file generated in 'generateExtraHelpFiles': + // def htmlTipsFile = file('build/help/main/help/topics/Misc/Tips.htm') + // This file is needed to correctly generate help ID -> file mappings. + args "-hpg" + args file('build/help/main/help').toString() + } } def createTipsHelpFile(input, output) { diff --git a/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml b/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml index b87c1a2b75..c6db849633 100644 --- a/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml +++ b/Ghidra/Features/Base/src/main/help/help/TOC_Source.xml @@ -379,7 +379,7 @@ - + diff --git a/Ghidra/Features/Base/src/main/resources/ghidra/app/plugin/core/totd/tips.txt b/Ghidra/Features/Base/src/main/resources/ghidra/app/plugin/core/totd/tips.txt index 94b4b70295..a7807cc913 100644 --- a/Ghidra/Features/Base/src/main/resources/ghidra/app/plugin/core/totd/tips.txt +++ b/Ghidra/Features/Base/src/main/resources/ghidra/app/plugin/core/totd/tips.txt @@ -75,7 +75,7 @@ Did you know you can see where a register is initialized in its current scope by You can perform a program memory search using a regular expression (regex). If a Windows executable contains Icons or Bitmap Resources, they are displayed in the CodeBrowser. Do a Search->Program Text on Labels for "Rsrc_Icon*" and "Rsrc_Bitmap*" to find them. -The average temperature on Earth is 15 degrees celsius. +The average temperature on Earth is 15 degrees Celsius. If you hover on a reference in the XREF or operand fields, a popup with the reference code or data will appear. If you hover on a data type in the CodeBrowser or Data Type Manager, a popup with the data type definition will appear. @@ -100,8 +100,10 @@ Ghidra allows full customization of all colors, fonts and icons via Edit->Theme- You can quickly change the font size of the Listing, Decompiler or the Bytes windows by pressing Ctrl-+ or Ctrl-- while inside of those windows. -You can quickly control the font size from the Theme Editor dialog via Edit->Theme->Configure. +You can quickly control the font size from the Theme Editor dialog's toolbar via Edit->Theme->Configure. You can create a table whose rows correspond to the address ranges in a selection via Select->Create Table From Ranges. +The tab and title of any Search Results window can be renamed by right-clicking and choosing 'Rename'. + This is the last tip. You can turn them off now. diff --git a/Ghidra/Features/PDB/build.gradle b/Ghidra/Features/PDB/build.gradle index 58c4aef6d9..b5f23c7a4b 100644 --- a/Ghidra/Features/PDB/build.gradle +++ b/Ghidra/Features/PDB/build.gradle @@ -44,4 +44,4 @@ rootProject.assembleDistribution { include "src/pdb/**" into { getZipPath(this.project) } } -} +} \ No newline at end of file diff --git a/Ghidra/Features/PDB/src/main/help/help/TOC_Source.xml b/Ghidra/Features/PDB/src/main/help/help/TOC_Source.xml index 3ddcfbbd9b..3f5a75b04e 100644 --- a/Ghidra/Features/PDB/src/main/help/help/TOC_Source.xml +++ b/Ghidra/Features/PDB/src/main/help/help/TOC_Source.xml @@ -52,7 +52,7 @@ - + diff --git a/Ghidra/Features/PDB/src/main/help/help/topics/Pdb/PDB.htm b/Ghidra/Features/PDB/src/main/help/help/topics/Pdb/PDB.htm index 4e4a0166f4..42ca3e9509 100644 --- a/Ghidra/Features/PDB/src/main/help/help/topics/Pdb/PDB.htm +++ b/Ghidra/Features/PDB/src/main/help/help/topics/Pdb/PDB.htm @@ -102,7 +102,7 @@

NOTE: Execution of pdb.exe has runtime dependencies which must be satisfied. - Please refer to the README_PDB document for details.

+ Please refer to the README_PDB document for details.

Debug Interface Access SDK

@@ -118,7 +118,7 @@

If you are attempting to load a PDB on a Windows machine and see an error message such as "Unable to locate the DIA SDK," you will need to add and register one or more files on your computer. Refer to the - README_PDB document for detailed instructions. + README_PDB document for detailed instructions.

Related Topics:

diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java index 1ef2d6ff31..03462daf6a 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/Application.java @@ -830,6 +830,7 @@ public class Application { /** * Returns a collection of module library directories. Library directories are optional for a module. * @return a collection of module library directories. + * @see ModuleUtilities#getModuleLibDirectories(Collection) */ public static Collection getLibraryDirectories() { checkAppInitialized(); diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java b/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java index 2d57f5f4be..b15242ba77 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpBuilder.java @@ -51,12 +51,14 @@ public class GHelpBuilder { private static final String OUTPUT_DIRECTORY_OPTION = "-o"; private static final String MODULE_NAME_OPTION = "-n"; private static final String HELP_PATHS_OPTION = "-hp"; + private static final String HELP_PATHS_GENERATED_OPTION = "-hpg"; private static final String DEBUG_SWITCH = "-debug"; private static final String IGNORE_INVALID_SWITCH = "-ignoreinvalid"; private String outputDirectoryName; private String moduleName; private Collection dependencyHelpPaths = new LinkedHashSet<>(); + private Collection generatedDependencyHelpPaths = new LinkedHashSet<>(); private Collection helpInputDirectories = new LinkedHashSet<>(); private static boolean debugEnabled = false; private boolean ignoreInvalid = false; // TODO: Do actual validation here @@ -112,7 +114,22 @@ public class GHelpBuilder { for (File file : dependencyHelpPaths) { allHelp.add(file); } - return HelpModuleCollection.fromFiles(allHelp); + + HelpModuleCollection help = HelpModuleCollection.fromFiles(allHelp); + + for (File file : generatedDependencyHelpPaths) { + help.addGeneratedHelpLocation(file); + } + + return help; + } + + private HelpModuleCollection collectInputHelp() { + HelpModuleCollection help = HelpModuleCollection.fromFiles(helpInputDirectories); + for (File file : generatedDependencyHelpPaths) { + help.addGeneratedHelpLocation(file); + } + return help; } private Results validateHelpDirectories(HelpModuleCollection help, LinkDatabase linkDatabase) { @@ -163,11 +180,11 @@ public class GHelpBuilder { JavaHelpFilesBuilder fileBuilder = new JavaHelpFilesBuilder(outputDirectory, moduleName, linkDatabase); - HelpModuleCollection help = HelpModuleCollection.fromFiles(helpInputDirectories); + HelpModuleCollection helpInput = collectInputHelp(); // 1) Generate JavaHelp files for the module (e.g., TOC file, map file) try { - fileBuilder.generateHelpFiles(help); + fileBuilder.generateHelpFiles(helpInput); } catch (Exception e) { exitWithError("Unexpected error building help module files:\n", e); @@ -302,6 +319,20 @@ public class GHelpBuilder { } } } + else if (opt.equals(HELP_PATHS_GENERATED_OPTION)) { + i++; + if (i >= args.length) { + errorMessage(HELP_PATHS_GENERATED_OPTION + " requires an argument"); + printUsage(); + System.exit(1); + } + String hp = args[i]; + if (hp.length() > 0) { + for (String p : hp.split(File.pathSeparator)) { + generatedDependencyHelpPaths.add(new File(p)); + } + } + } else if (opt.equals(DEBUG_SWITCH)) { debugEnabled = true; } diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java b/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java index 456287c685..5f9a5c9380 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpHTMLEditorKit.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,7 +21,8 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.*; import java.net.*; -import java.util.*; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -36,7 +37,6 @@ import javax.swing.text.html.HTML.Tag; import generic.jar.ResourceFile; import generic.theme.GColor; import generic.theme.Gui; -import ghidra.framework.Application; import ghidra.framework.preferences.Preferences; import ghidra.util.Msg; import resources.*; @@ -183,6 +183,10 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { */ private HyperlinkEvent validateURL(HyperlinkEvent event) { URL url = event.getURL(); + if (url == null) { + Msg.trace(this, "No URL for link: " + event); + return maybeCreateNewHyperlinkEventWithUpdatedURL(event); + } try { url.openStream();// assume that this will fail if the file does not exist } @@ -239,7 +243,7 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { // directory). See if it may be a relative link to a build's installation root (like // a file in /docs). // - newUrl = findApplicationfile(HREF); + newUrl = HelpBuildUtils.findApplicationUrl(HREF); return newUrl; } @@ -385,37 +389,15 @@ public class GHelpHTMLEditorKit extends HTMLEditorKit { return url; } - return findModuleFile("help/shared/" + name); - } - - private URL findApplicationfile(String relativePath) { - ResourceFile installDir = Application.getInstallationDirectory(); - ResourceFile file = new ResourceFile(installDir, relativePath); - if (file.exists()) { + ResourceFile file = HelpBuildUtils.findModuleFile("help/shared/" + name); + if (file != null) { try { return file.toURL(); } catch (MalformedURLException e) { Msg.showError(this, null, "Unexpected Error", "Unexpected error parsing file to URL: " + file); - } - } - return null; - } - - private URL findModuleFile(String relativePath) { - Collection moduleDirs = Application.getModuleRootDirectories(); - for (ResourceFile dir : moduleDirs) { - ResourceFile file = new ResourceFile(dir, relativePath); - if (file.exists()) { - try { - return file.toURL(); - } - catch (MalformedURLException e) { - Msg.showError(this, null, "Unexpected Error", - "Unexpected error parsing file to URL: " + file); - return null; - } + return null; } } return null; diff --git a/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java b/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java index b847bc8834..fb59065e0b 100644 --- a/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java +++ b/Ghidra/Framework/Help/src/main/java/help/GHelpSet.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,9 +28,8 @@ import javax.help.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import generic.jar.ResourceFile; -import ghidra.framework.Application; import ghidra.util.SystemUtilities; +import help.validator.JavaHelpValidator; /** * Ghidra help set that creates a GhidraHelpBroker, installs some custom HTML handling code via @@ -201,17 +200,22 @@ public class GHelpSet extends HelpSet { /** * This is meant for help files that are not included in the standard help system. Their * id paths are expected to be relative to the application install directory. - * @param id the help id. + * @param rawId the help id. * @return the URL to the help file. */ - private URL tryToCreateURLFromID(String id) { + private URL tryToCreateURLFromID(String rawId) { - URL fileURL = createFileURL(id); - if (fileURL != null) { - return fileURL; + String idText = rawId; + if (rawId.startsWith(JavaHelpValidator.EXTERNAL_PREFIX)) { + idText = rawId.substring(JavaHelpValidator.EXTERNAL_PREFIX.length()); } - URL rawURL = createRawURL(id); + URL fileUrl = HelpBuildUtils.findApplicationUrl(idText); + if (fileUrl != null) { + return fileUrl; + } + + URL rawURL = createRawURL(idText); return rawURL; } @@ -238,31 +242,6 @@ public class GHelpSet extends HelpSet { return null; } - private URL createFileURL(String id) { - ResourceFile helpFile = fileFromID(id); - if (!helpFile.exists()) { - LOG.trace("ID is not a file; tried: " + helpFile); - return null; - } - - try { - return helpFile.toURL(); - } - catch (MalformedURLException e) { - // this shouldn't happen, as the file exists - LOG.trace("ID is not a URL; tried to make URL from file: " + helpFile); - } - return null; - } - - private ResourceFile fileFromID(String id) { - // this allows us to find files by using relative paths (e.g., 'docs/WhatsNew.html' - // will get resolved relative to the installation directory in a build). - ResourceFile installDir = Application.getInstallationDirectory(); - ResourceFile helpFile = new ResourceFile(installDir, id); - return helpFile; - } - @Override public boolean isID(URL url) { return mapDelegate.isID(url); diff --git a/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java b/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java index 58efa2c0be..18d8d3af76 100644 --- a/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java +++ b/Ghidra/Framework/Help/src/main/java/help/HelpBuildUtils.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -30,7 +30,8 @@ import generic.theme.GIcon; import generic.theme.GThemeDefaults.Colors; import generic.theme.Gui; import ghidra.framework.Application; -import ghidra.util.HelpLocation; +import ghidra.util.*; +import help.validator.JavaHelpValidator; import help.validator.location.*; import resources.IconProvider; import resources.Icons; @@ -166,6 +167,71 @@ public class HelpBuildUtils { return null; } + /** + * Finds the actual module file for the given relative path when in development mode. For + * example, given: + *
+	 * 	help/shared/DefaultStyle.css
+	 * 
+ * This method will find: + *
+	 * 	{repo}/Ghidra/Framework/Help/src/main/resources/help/shared/DefaultStyle.css
+	 * 
+ * @param relativePath the path + * @return the file + */ + public static ResourceFile findModuleFile(String relativePath) { + Collection moduleDirs = Application.getModuleRootDirectories(); + for (ResourceFile dir : moduleDirs) { + ResourceFile file = new ResourceFile(dir, relativePath); + if (file.exists()) { + return file; + } + } + return null; + } + + /** + * Searches the application classpath (for a module file) and directory structure (for a release + * file), depending on whether in release mode or development mode, to find the URL for the + * given relative path. + * @param relativePath the path + * @return the URL or null if not found + */ + public static URL findApplicationUrl(String relativePath) { + + String updatedPath = relativePath; + if (relativePath.startsWith(JavaHelpValidator.EXTERNAL_PREFIX)) { + updatedPath = relativePath.substring(JavaHelpValidator.EXTERNAL_PREFIX.length()); + } + + ResourceFile file = null; + if (SystemUtilities.isInDevelopmentMode()) { + // example: "docs/WhatsNew.html", which lives in a source dir in dev mode + file = findModuleFile("src/global/" + updatedPath); + } + else { + // + // In release mode, some of the help content is relative to the root of the application, + // such as 'docs/WhatsNew.html'. + // + ResourceFile installDir = Application.getInstallationDirectory(); + file = new ResourceFile(installDir, updatedPath); + } + + if (file == null || !file.exists()) { + return null; + } + + try { + return file.toURL(); + } + catch (MalformedURLException e) { + Msg.trace(HelpBuildUtils.class, "Unexpected error parsing file to URL: " + file); + } + return null; + } + //================================================================================================== // Cleanup Methods //================================================================================================== diff --git a/Ghidra/Framework/Help/src/main/java/help/JavaHelpFilesBuilder.java b/Ghidra/Framework/Help/src/main/java/help/JavaHelpFilesBuilder.java index d57f8c007e..425f1115cf 100644 --- a/Ghidra/Framework/Help/src/main/java/help/JavaHelpFilesBuilder.java +++ b/Ghidra/Framework/Help/src/main/java/help/JavaHelpFilesBuilder.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -220,6 +220,7 @@ public class JavaHelpFilesBuilder { Files.delete(file); } catch (IOException e) { + // ignore } } } diff --git a/Ghidra/Framework/Help/src/main/java/help/validator/JavaHelpValidator.java b/Ghidra/Framework/Help/src/main/java/help/validator/JavaHelpValidator.java index ff738de814..bbb29d434d 100644 --- a/Ghidra/Framework/Help/src/main/java/help/validator/JavaHelpValidator.java +++ b/Ghidra/Framework/Help/src/main/java/help/validator/JavaHelpValidator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -29,23 +29,13 @@ import help.validator.location.HelpModuleCollection; import help.validator.model.*; public class JavaHelpValidator { + + // This allows help links to signal that the reference is pointing to a file that lives outside + // of the help system + public static final String EXTERNAL_PREFIX = "external:"; + private static boolean debug; - /** Files that are generated and may not exist at validation time */ - private static Set EXCLUDED_FILE_NAMES = createExcludedFileSet(); - - private static Set createExcludedFileSet() { - Set set = new HashSet<>(); - - // The expected format is the help path, without an extension (this helps catch multiple - // references with anchors) - set.add("help/topics/Misc/Tips"); - set.add("docs/WhatsNew"); - set.add("docs/README_PDB"); - - return set; - } - private String moduleName; private HelpModuleCollection help; @@ -304,7 +294,7 @@ public class JavaHelpValidator { path = path.substring(0, index); } - return EXCLUDED_FILE_NAMES.contains(path); + return path.startsWith(EXTERNAL_PREFIX); } private void validateExternalFileLinks(LinkDatabase linkDatabase) { diff --git a/Ghidra/Framework/Help/src/main/java/help/validator/LinkDatabase.java b/Ghidra/Framework/Help/src/main/java/help/validator/LinkDatabase.java index 1c47a4b4b1..5c8ea30ee9 100644 --- a/Ghidra/Framework/Help/src/main/java/help/validator/LinkDatabase.java +++ b/Ghidra/Framework/Help/src/main/java/help/validator/LinkDatabase.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,6 +15,12 @@ */ package help.validator; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.Map.Entry; + import help.OverlayHelpTree; import help.TOCItemProvider; import help.validator.links.InvalidHREFLink; @@ -22,12 +28,6 @@ import help.validator.links.InvalidLink; import help.validator.location.HelpModuleCollection; import help.validator.model.*; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.Map.Entry; - public class LinkDatabase { /** Sorted for later presentation */ diff --git a/Ghidra/Framework/Help/src/main/java/help/validator/location/GeneratedDirectoryHelpModuleLocation.java b/Ghidra/Framework/Help/src/main/java/help/validator/location/GeneratedDirectoryHelpModuleLocation.java new file mode 100644 index 0000000000..4059aa0523 --- /dev/null +++ b/Ghidra/Framework/Help/src/main/java/help/validator/location/GeneratedDirectoryHelpModuleLocation.java @@ -0,0 +1,43 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package help.validator.location; + +import java.io.File; + +import help.validator.model.GhidraTOCFile; + +/** + * Represents a directory that holds generated content. At the time of writing, the only known + * such input is the 'tips of the day' html file that is created from a text file. + */ +public class GeneratedDirectoryHelpModuleLocation extends DirectoryHelpModuleLocation { + + public GeneratedDirectoryHelpModuleLocation(File file) { + super(file); + } + + @Override + public GhidraTOCFile loadSourceTOCFile() { + // Generated directories are not full help directories with TOC source files. + return null; + } + + @Override + public boolean isHelpInputSource() { + return false; + } + +} diff --git a/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleCollection.java b/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleCollection.java index 8489df7b28..b7b653fb29 100644 --- a/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleCollection.java +++ b/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleCollection.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,21 +16,10 @@ package help.validator.location; import java.io.File; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; +import java.net.*; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import javax.help.HelpSet; @@ -38,19 +27,9 @@ import javax.help.Map.ID; import javax.help.TOCView; import javax.swing.tree.DefaultMutableTreeNode; +import help.*; import help.CustomTOCView.CustomTreeItemDecorator; -import help.HelpBuildUtils; -import help.PathKey; -import help.TOCItemProvider; -import help.validator.model.AnchorDefinition; -import help.validator.model.GhidraTOCFile; -import help.validator.model.HREF; -import help.validator.model.HelpFile; -import help.validator.model.HelpTopic; -import help.validator.model.IMG; -import help.validator.model.TOCItem; -import help.validator.model.TOCItemDefinition; -import help.validator.model.TOCItemExternal; +import help.validator.model.*; /** * A class that is meant to hold a single help input directory and 0 or more @@ -130,12 +109,21 @@ public class HelpModuleCollection implements TOCItemProvider { if (inputHelp == null && externalHelpSets.size() == 0) { throw new IllegalArgumentException( - "Required TOC file does not exist. " + "You must create a TOC_Source.xml file, " + + "Required TOC file does not exist. You must create a TOC_Source.xml file, " + "even if it is an empty template, or provide a pre-built TOC. " + "Help directories: " + locations.toString()); } } + public void addGeneratedHelpLocation(File file) { + HelpModuleLocation location = new GeneratedDirectoryHelpModuleLocation(file); + helpLocations.add(location); + HelpSet helpSet = location.getHelpSet(); + if (helpSet != null) { + externalHelpSets.add(helpSet); + } + } + public GhidraTOCFile getSourceTOCFile() { return inputHelp.getSourceTOCFile(); } @@ -160,17 +148,17 @@ public class HelpModuleCollection implements TOCItemProvider { externalHelpSets = new ArrayList<>(); for (HelpModuleLocation location : helpLocations) { - if (location.isHelpInputSource()) { - continue; // help sets only exist in pre-built help - } + doAddHelpSet(location); + } + } - HelpSet helpSet = location.getHelpSet(); - externalHelpSets.add(helpSet); + private void doAddHelpSet(HelpModuleLocation location) { + if (location.isHelpInputSource()) { + return; // help sets only exist in pre-built help } - if (externalHelpSets.isEmpty()) { - return; - } + HelpSet helpSet = location.getHelpSet(); + externalHelpSets.add(helpSet); } public boolean containsHelpFiles() { @@ -230,7 +218,8 @@ public class HelpModuleCollection implements TOCItemProvider { public Collection getAllAnchorDefinitions() { List result = new ArrayList<>(); for (HelpModuleLocation location : helpLocations) { - result.addAll(location.getAllAnchorDefinitions()); + Collection anchors = location.getAllAnchorDefinitions(); + result.addAll(anchors); } return result; } @@ -250,7 +239,6 @@ public class HelpModuleCollection implements TOCItemProvider { if (helpPath == null) { return null; } - Map map = getPathHelpFileMap(); return map.get(new PathKey(helpPath)); } @@ -373,4 +361,5 @@ public class HelpModuleCollection implements TOCItemProvider { public String toString() { return helpLocations.toString(); } + } diff --git a/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleLocation.java b/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleLocation.java index 3cabd9e679..6a9b88ca19 100644 --- a/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleLocation.java +++ b/Ghidra/Framework/Help/src/main/java/help/validator/location/HelpModuleLocation.java @@ -55,6 +55,7 @@ public abstract class HelpModuleLocation { public abstract boolean isHelpInputSource(); protected void loadHelpTopics() { + Path helpTopicsDir = helpDir.resolve("topics"); if (!Files.exists(helpTopicsDir)) { HelpBuildUtils.debug("No topics found in help dir: " + this); diff --git a/gradle/helpProject.gradle b/gradle/helpProject.gradle index 4e27de875e..6438e0fc0d 100644 --- a/gradle/helpProject.gradle +++ b/gradle/helpProject.gradle @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -272,6 +272,9 @@ tasks.register('indexHelp', JavaExec) { // tell the indexer where send its output args '-db', outputFile.absolutePath + // debug + // args '-verbose' + // for each help file that was found, add it as an argument to the indexer helpFiles.each { File file -> args "${file.absolutePath}" @@ -321,7 +324,7 @@ tasks.register('buildHelpFiles', JavaExec) { // configuration time. return getHelpInputs(sourceSets.main.runtimeClasspath.files) }) - + outputs.dir outputDir mainClass = 'help.GHelpBuilder' @@ -330,8 +333,11 @@ tasks.register('buildHelpFiles', JavaExec) { args '-o', "${outputDir.absolutePath}" // set the output directory arg + // to allow remote debugging of the help build jvm + // jvmArgs '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=13001' - // args '-debug' // print debug info + // print debug info + // args '-debug' doFirst { @@ -368,7 +374,7 @@ tasks.register('buildHelpFiles', JavaExec) { args "${helpJar.absolutePath}" } } - + // The help dir to process. This needs to be the last argument to the process, // thus, this is why it is inside of this block args "${helpRootDir.absolutePath}" @@ -393,7 +399,7 @@ tasks.register('buildHelp', Jar) { dependsOn tasks.named('buildHelpFiles') duplicatesStrategy 'exclude' - from "build/help/main" // include the generated help and index files from + from "build/help/main" // include the generated help and index files from "src/main/help" // include the help source files destinationDirectory = file("build/libs")